diff --git a/.cargo/config.toml b/.cargo/config.toml index 1b8ffe1a1c82..68a0d7b552dc 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,3 +9,7 @@ rustdocflags = [ CC_x86_64_unknown_linux_musl = { value = ".cargo/musl-gcc", force = true, relative = true } CXX_x86_64_unknown_linux_musl = { value = ".cargo/musl-g++", force = true, relative = true } CARGO_WORKSPACE_ROOT_DIR = { value = "", relative = true } + +[net] +retry = 5 +# git-fetch-with-cli = true # commented because there is a risk that a runner can be banned by github diff --git a/.config/lychee.toml b/.config/lychee.toml index b1f08de33340..58f8d068d9d1 100644 --- a/.config/lychee.toml +++ b/.config/lychee.toml @@ -28,7 +28,7 @@ exclude = [ "http://visitme/", "https://visitme/", - # TODO + # TODO meta issue: "https://docs.substrate.io/main-docs/build/custom-rpc/#public-rpcs", "https://docs.substrate.io/rustdocs/latest/sp_api/macro.decl_runtime_apis.html", "https://github.com/ipfs/js-ipfs-bitswap/blob/", @@ -50,8 +50,10 @@ exclude = [ "https://w3f.github.io/parachain-implementers-guide/runtime/session_info.html", # Behind a captcha (code 403): + "https://chainlist.org/chain/*", "https://iohk.io/en/blog/posts/2023/11/03/partner-chains-are-coming-to-cardano/", "https://www.reddit.com/r/rust/comments/3spfh1/does_collect_allocate_more_than_once_while/", + # 403 rate limited: "https://etherscan.io/block/11090290", "https://subscan.io/", diff --git a/.config/nextest.toml b/.config/nextest.toml index 1e18f8b5589c..b4bdec4aea92 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -21,7 +21,6 @@ retries = 5 # The number of threads to run tests with. Supported values are either an integer or # the string "num-cpus". Can be overridden through the `--test-threads` option. # test-threads = "num-cpus" - test-threads = 20 # The number of threads required for each test. This is generally used in overrides to @@ -124,3 +123,10 @@ serial-integration = { max-threads = 1 } [[profile.default.overrides]] filter = 'test(/(^ui$|_ui|ui_)/)' test-group = 'serial-integration' + +# Running eth-rpc tests sequentially +# These tests rely on a shared resource (the RPC and Node) +# and would cause race conditions due to transaction nonces if run in parallel. +[[profile.default.overrides]] +filter = 'package(pallet-revive-eth-rpc) and test(/^tests::/)' +test-group = 'serial-integration' diff --git a/.config/taplo.toml b/.config/taplo.toml index 7cbc1b075125..4b8afc74a52e 100644 --- a/.config/taplo.toml +++ b/.config/taplo.toml @@ -40,3 +40,10 @@ keys = ["workspace.dependencies"] [rule.formatting] reorder_keys = true + +[[rule]] +include = ["**/Cargo.toml"] +keys = ["build-dependencies", "dependencies", "dev-dependencies"] + +[rule.formatting] +reorder_keys = true diff --git a/.github/actions/workflow-stopper/action.yml b/.github/actions/workflow-stopper/action.yml new file mode 100644 index 000000000000..0bd9382fdb30 --- /dev/null +++ b/.github/actions/workflow-stopper/action.yml @@ -0,0 +1,28 @@ +name: "stop all workflows" +description: "Action stops all workflows in a PR to save compute resources." +inputs: + app-id: + description: "App id" + required: true + app-key: + description: "App token" + required: true +runs: + using: "composite" + steps: + - name: Worfklow stopper - Generate token + uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ inputs.app-id }} + private-key: ${{ inputs.app-key }} + owner: "paritytech" + repositories: "workflow-stopper" + - name: Workflow stopper - Stop all workflows + uses: octokit/request-action@v2.x + with: + route: POST /repos/paritytech/workflow-stopper/actions/workflows/stopper.yml/dispatches + ref: main + inputs: '${{ format(''{{ "github_sha": "{0}", "github_repository": "{1}", "github_ref_name": "{2}", "github_workflow_id": "{3}", "github_job_name": "{4}" }}'', github.event.pull_request.head.sha, github.repository, github.ref_name, github.run_id, github.job) }}' + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.github/env b/.github/env index bb61e1f4cd99..730c37f1db80 100644 --- a/.github/env +++ b/.github/env @@ -1 +1 @@ -IMAGE="docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-09-11-v202409111034" +IMAGE="docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-11-19-v202411281558" diff --git a/.github/scripts/check-missing-readme-generation.sh b/.github/scripts/check-missing-readme-generation.sh new file mode 100755 index 000000000000..13f2b6a7cb28 --- /dev/null +++ b/.github/scripts/check-missing-readme-generation.sh @@ -0,0 +1,36 @@ +#!/bin/bash +echo "Running script relative to `pwd`" +# Find all README.docify.md files +DOCIFY_FILES=$(find . -name "README.docify.md") + +# Initialize a variable to track directories needing README regeneration +NEED_REGENERATION="" + +for file in $DOCIFY_FILES; do + echo "Processing $file" + + # Get the directory containing the docify file + DIR=$(dirname "$file") + + # Go to the directory and run cargo build + cd "$DIR" + cargo check --features generate-readme || { echo "Readme generation for $DIR failed. Ensure the crate compiles successfully and has a `generate-readme` feature which guards markdown compilation in the crate as follows: https://docs.rs/docify/latest/docify/macro.compile_markdown.html#conventions." && exit 1; } + + # Check if README.md has any uncommitted changes + git diff --exit-code README.md + + if [ $? -ne 0 ]; then + echo "Error: Found uncommitted changes in $DIR/README.md" + NEED_REGENERATION="$NEED_REGENERATION $DIR" + fi + + # Return to the original directory + cd - > /dev/null +done + +# Check if any directories need README regeneration +if [ -n "$NEED_REGENERATION" ]; then + echo "The following directories need README regeneration:" + echo "$NEED_REGENERATION" + exit 1 +fi \ No newline at end of file diff --git a/.github/scripts/cmd/cmd.py b/.github/scripts/cmd/cmd.py index 9da05cac17b9..2c017b7d0c3e 100755 --- a/.github/scripts/cmd/cmd.py +++ b/.github/scripts/cmd/cmd.py @@ -58,7 +58,7 @@ def setup_logging(): %(prog)s --runtime westend rococo --pallet pallet_balances pallet_multisig --quiet --clean ''' -parser_bench = subparsers.add_parser('bench', help='Runs benchmarks', epilog=bench_example, formatter_class=argparse.RawDescriptionHelpFormatter) +parser_bench = subparsers.add_parser('bench', help='Runs benchmarks (old CLI)', epilog=bench_example, formatter_class=argparse.RawDescriptionHelpFormatter) for arg, config in common_args.items(): parser_bench.add_argument(arg, **config) @@ -67,6 +67,35 @@ def setup_logging(): parser_bench.add_argument('--pallet', help='Pallet(s) space separated', nargs='*', default=[]) parser_bench.add_argument('--fail-fast', help='Fail fast on first failed benchmark', action='store_true') + +""" +BENCH OMNI +""" + +bench_example = '''**Examples**: + Runs all benchmarks + %(prog)s + + Runs benchmarks for pallet_balances and pallet_multisig for all runtimes which have these pallets. **--quiet** makes it to output nothing to PR but reactions + %(prog)s --pallet pallet_balances pallet_xcm_benchmarks::generic --quiet + + Runs bench for all pallets for westend runtime and fails fast on first failed benchmark + %(prog)s --runtime westend --fail-fast + + Does not output anything and cleans up the previous bot's & author command triggering comments in PR + %(prog)s --runtime westend rococo --pallet pallet_balances pallet_multisig --quiet --clean +''' + +parser_bench_old = subparsers.add_parser('bench-omni', help='Runs benchmarks (frame omni bencher)', epilog=bench_example, formatter_class=argparse.RawDescriptionHelpFormatter) + +for arg, config in common_args.items(): + parser_bench_old.add_argument(arg, **config) + +parser_bench_old.add_argument('--runtime', help='Runtime(s) space separated', choices=runtimeNames, nargs='*', default=runtimeNames) +parser_bench_old.add_argument('--pallet', help='Pallet(s) space separated', nargs='*', default=[]) +parser_bench_old.add_argument('--fail-fast', help='Fail fast on first failed benchmark', action='store_true') + + """ FMT """ @@ -98,12 +127,12 @@ def main(): print(f'args: {args}') - if args.command == 'bench': + if args.command == 'bench-omni': runtime_pallets_map = {} failed_benchmarks = {} successful_benchmarks = {} - profile = "release" + profile = "production" print(f'Provided runtimes: {args.runtime}') # convert to mapped dict @@ -113,11 +142,22 @@ 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['bench_features']}") + build_command = f"forklift cargo build -p {runtime['package']} --profile {profile} --features={runtime['bench_features']}" + print(f'-- building "{runtime["name"]}" with `{build_command}`') + os.system(build_command) print(f'-- listing pallets for benchmark for {runtime["name"]}') wasm_file = f"target/{profile}/wbuild/{runtime['package']}/{runtime['package'].replace('-', '_')}.wasm" - output = os.popen( - f"frame-omni-bencher v1 benchmark pallet --no-csv-header --no-storage-info --no-min-squares --no-median-slopes --all --list --runtime={wasm_file} {runtime['bench_flags']}").read() + list_command = f"frame-omni-bencher v1 benchmark pallet " \ + f"--no-csv-header " \ + f"--no-storage-info " \ + f"--no-min-squares " \ + f"--no-median-slopes " \ + f"--all " \ + f"--list " \ + f"--runtime={wasm_file} " \ + f"{runtime['bench_flags']}" + print(f'-- running: {list_command}') + output = os.popen(list_command).read() raw_pallets = output.strip().split('\n') all_pallets = set() @@ -230,6 +270,149 @@ def main(): print_and_log('✅ Successful benchmarks of runtimes/pallets:') for runtime, pallets in successful_benchmarks.items(): print_and_log(f'-- {runtime}: {pallets}') + + if args.command == 'bench': + runtime_pallets_map = {} + failed_benchmarks = {} + successful_benchmarks = {} + + profile = "production" + + print(f'Provided runtimes: {args.runtime}') + # convert to mapped dict + runtimesMatrix = list(filter(lambda x: x['name'] in args.runtime, runtimesMatrix)) + runtimesMatrix = {x['name']: x for x in runtimesMatrix} + print(f'Filtered out runtimes: {runtimesMatrix}') + + # loop over remaining runtimes to collect available pallets + for runtime in runtimesMatrix.values(): + build_command = f"forklift cargo build -p {runtime['old_package']} --profile {profile} --features={runtime['bench_features']} --locked" + print(f'-- building {runtime["name"]} with `{build_command}`') + os.system(build_command) + + chain = runtime['name'] if runtime['name'] == 'dev' else f"{runtime['name']}-dev" + + machine_test = f"target/{profile}/{runtime['old_bin']} benchmark machine --chain={chain}" + print(f"Running machine test for `{machine_test}`") + os.system(machine_test) + + print(f'-- listing pallets for benchmark for {chain}') + list_command = f"target/{profile}/{runtime['old_bin']} " \ + f"benchmark pallet " \ + f"--no-csv-header " \ + f"--no-storage-info " \ + f"--no-min-squares " \ + f"--no-median-slopes " \ + f"--all " \ + f"--list " \ + f"--chain={chain}" + print(f'-- running: {list_command}') + output = os.popen(list_command).read() + raw_pallets = output.strip().split('\n') + + all_pallets = set() + for pallet in raw_pallets: + if pallet: + all_pallets.add(pallet.split(',')[0].strip()) + + pallets = list(all_pallets) + print(f'Pallets in {runtime["name"]}: {pallets}') + runtime_pallets_map[runtime['name']] = pallets + + print(f'\n') + + # filter out only the specified pallets from collected runtimes/pallets + if args.pallet: + print(f'Pallets: {args.pallet}') + new_pallets_map = {} + # keep only specified pallets if they exist in the runtime + for runtime in runtime_pallets_map: + if set(args.pallet).issubset(set(runtime_pallets_map[runtime])): + new_pallets_map[runtime] = args.pallet + + runtime_pallets_map = new_pallets_map + + print(f'Filtered out runtimes & pallets: {runtime_pallets_map}\n') + + if not runtime_pallets_map: + if args.pallet and not args.runtime: + print(f"No pallets {args.pallet} found in any runtime") + elif args.runtime and not args.pallet: + print(f"{args.runtime} runtime does not have any pallets") + elif args.runtime and args.pallet: + print(f"No pallets {args.pallet} found in {args.runtime}") + else: + print('No runtimes found') + sys.exit(1) + + for runtime in runtime_pallets_map: + for pallet in runtime_pallets_map[runtime]: + config = runtimesMatrix[runtime] + header_path = os.path.abspath(config['header']) + template = None + + chain = config['name'] if runtime == 'dev' else f"{config['name']}-dev" + + print(f'-- config: {config}') + if runtime == 'dev': + # to support sub-modules (https://github.com/paritytech/command-bot/issues/275) + search_manifest_path = f"cargo metadata --locked --format-version 1 --no-deps | jq -r '.packages[] | select(.name == \"{pallet.replace('_', '-')}\") | .manifest_path'" + print(f'-- running: {search_manifest_path}') + manifest_path = os.popen(search_manifest_path).read() + if not manifest_path: + print(f'-- pallet {pallet} not found in dev runtime') + if args.fail_fast: + print_and_log(f'Error: {pallet} not found in dev runtime') + sys.exit(1) + package_dir = os.path.dirname(manifest_path) + print(f'-- package_dir: {package_dir}') + print(f'-- manifest_path: {manifest_path}') + output_path = os.path.join(package_dir, "src", "weights.rs") + template = config['template'] + else: + default_path = f"./{config['path']}/src/weights" + xcm_path = f"./{config['path']}/src/weights/xcm" + output_path = default_path + if pallet.startswith("pallet_xcm_benchmarks"): + template = config['template'] + output_path = xcm_path + + print(f'-- benchmarking {pallet} in {runtime} into {output_path}') + cmd = f"target/{profile}/{config['old_bin']} benchmark pallet " \ + f"--extrinsic=* " \ + f"--chain={chain} " \ + f"--pallet={pallet} " \ + f"--header={header_path} " \ + f"--output={output_path} " \ + f"--wasm-execution=compiled " \ + f"--steps=50 " \ + f"--repeat=20 " \ + f"--heap-pages=4096 " \ + f"{f'--template={template} ' if template else ''}" \ + f"--no-storage-info --no-min-squares --no-median-slopes " + print(f'-- Running: {cmd} \n') + status = os.system(cmd) + + if status != 0 and args.fail_fast: + print_and_log(f'❌ Failed to benchmark {pallet} in {runtime}') + sys.exit(1) + + # Otherwise collect failed benchmarks and print them at the end + # push failed pallets to failed_benchmarks + if status != 0: + failed_benchmarks[f'{runtime}'] = failed_benchmarks.get(f'{runtime}', []) + [pallet] + else: + successful_benchmarks[f'{runtime}'] = successful_benchmarks.get(f'{runtime}', []) + [pallet] + + if failed_benchmarks: + print_and_log('❌ Failed benchmarks of runtimes/pallets:') + for runtime, pallets in failed_benchmarks.items(): + print_and_log(f'-- {runtime}: {pallets}') + + if successful_benchmarks: + print_and_log('✅ Successful benchmarks of runtimes/pallets:') + for runtime, pallets in successful_benchmarks.items(): + print_and_log(f'-- {runtime}: {pallets}') elif args.command == 'fmt': command = f"cargo +nightly fmt" diff --git a/.github/scripts/cmd/test_cmd.py b/.github/scripts/cmd/test_cmd.py index 7b29fbfe90d8..68998b989909 100644 --- a/.github/scripts/cmd/test_cmd.py +++ b/.github/scripts/cmd/test_cmd.py @@ -47,7 +47,7 @@ def get_mock_bench_output(runtime, pallets, output_path, header, bench_flags, template = None): return f"frame-omni-bencher v1 benchmark pallet --extrinsic=* " \ - f"--runtime=target/release/wbuild/{runtime}-runtime/{runtime.replace('-', '_')}_runtime.wasm " \ + f"--runtime=target/production/wbuild/{runtime}-runtime/{runtime.replace('-', '_')}_runtime.wasm " \ f"--pallet={pallets} --header={header} " \ f"--output={output_path} " \ f"--wasm-execution=compiled " \ @@ -93,7 +93,7 @@ def tearDown(self): def test_bench_command_normal_execution_all_runtimes(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=list(map(lambda x: x['name'], mock_runtimes_matrix)), pallet=['pallet_balances'], fail_fast=True, @@ -117,10 +117,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 production --features=runtime-benchmarks"), + call("forklift cargo build -p westend-runtime --profile production --features=runtime-benchmarks"), + call("forklift cargo build -p rococo-runtime --profile production --features=runtime-benchmarks"), + call("forklift cargo build -p asset-hub-westend-runtime --profile production --features=runtime-benchmarks"), call(get_mock_bench_output( runtime='kitchensink', @@ -150,7 +150,7 @@ def test_bench_command_normal_execution_all_runtimes(self): def test_bench_command_normal_execution(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=['westend'], pallet=['pallet_balances', 'pallet_staking'], fail_fast=True, @@ -170,7 +170,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 production --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output( @@ -193,7 +193,7 @@ def test_bench_command_normal_execution(self): def test_bench_command_normal_execution_xcm(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=['westend'], pallet=['pallet_xcm_benchmarks::generic'], fail_fast=True, @@ -213,7 +213,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 production --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output( @@ -229,7 +229,7 @@ def test_bench_command_normal_execution_xcm(self): def test_bench_command_two_runtimes_two_pallets(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=['westend', 'rococo'], pallet=['pallet_balances', 'pallet_staking'], fail_fast=True, @@ -250,8 +250,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 production --features=runtime-benchmarks"), + call("forklift cargo build -p rococo-runtime --profile production --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output( runtime='westend', @@ -287,7 +287,7 @@ def test_bench_command_two_runtimes_two_pallets(self): def test_bench_command_one_dev_runtime(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=['dev'], pallet=['pallet_balances'], fail_fast=True, @@ -309,7 +309,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 production --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output( runtime='kitchensink', @@ -324,7 +324,7 @@ def test_bench_command_one_dev_runtime(self): def test_bench_command_one_cumulus_runtime(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=['asset-hub-westend'], pallet=['pallet_assets'], fail_fast=True, @@ -344,7 +344,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 production --features=runtime-benchmarks"), # Asset-hub-westend runtime calls call(get_mock_bench_output( runtime='asset-hub-westend', @@ -359,7 +359,7 @@ def test_bench_command_one_cumulus_runtime(self): def test_bench_command_one_cumulus_runtime_xcm(self): self.mock_parse_args.return_value = (argparse.Namespace( - command='bench', + command='bench-omni', runtime=['asset-hub-westend'], pallet=['pallet_xcm_benchmarks::generic', 'pallet_assets'], fail_fast=True, @@ -379,7 +379,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 production --features=runtime-benchmarks"), # Asset-hub-westend runtime calls call(get_mock_bench_output( runtime='asset-hub-westend', diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index 56d0371d678e..c9be21e45dcb 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -237,24 +237,52 @@ fetch_release_artifacts() { popd > /dev/null } -# Fetch the release artifacts like binary and signatures from S3. Assumes the ENV are set: +# Fetch deb package from S3. Assumes the ENV are set: # - RELEASE_ID # - GITHUB_TOKEN # - REPO in the form paritytech/polkadot -fetch_release_artifacts_from_s3() { +fetch_debian_package_from_s3() { BINARY=$1 echo "Version : $VERSION" echo "Repo : $REPO" echo "Binary : $BINARY" + echo "Tag : $RELEASE_TAG" OUTPUT_DIR=${OUTPUT_DIR:-"./release-artifacts/${BINARY}"} echo "OUTPUT_DIR : $OUTPUT_DIR" URL_BASE=$(get_s3_url_base $BINARY) echo "URL_BASE=$URL_BASE" - URL_BINARY=$URL_BASE/$VERSION/$BINARY - URL_SHA=$URL_BASE/$VERSION/$BINARY.sha256 - URL_ASC=$URL_BASE/$VERSION/$BINARY.asc + URL=$URL_BASE/$RELEASE_TAG/x86_64-unknown-linux-gnu/${BINARY}_${VERSION}_amd64.deb + + mkdir -p "$OUTPUT_DIR" + pushd "$OUTPUT_DIR" > /dev/null + + echo "Fetching deb package..." + + echo "Fetching %s" "$URL" + curl --progress-bar -LO "$URL" || echo "Missing $URL" + + pwd + ls -al --color + popd > /dev/null + +} + +# Fetch the release artifacts like binary and signatures from S3. Assumes the ENV are set: +# inputs: binary (polkadot), target(aarch64-apple-darwin) +fetch_release_artifacts_from_s3() { + BINARY=$1 + TARGET=$2 + OUTPUT_DIR=${OUTPUT_DIR:-"./release-artifacts/${TARGET}/${BINARY}"} + echo "OUTPUT_DIR : $OUTPUT_DIR" + + URL_BASE=$(get_s3_url_base $BINARY) + echo "URL_BASE=$URL_BASE" + + URL_BINARY=$URL_BASE/$VERSION/$TARGET/$BINARY + URL_SHA=$URL_BASE/$VERSION/$TARGET/$BINARY.sha256 + URL_ASC=$URL_BASE/$VERSION/$TARGET/$BINARY.asc # Fetch artifacts mkdir -p "$OUTPUT_DIR" @@ -269,7 +297,6 @@ fetch_release_artifacts_from_s3() { pwd ls -al --color popd > /dev/null - } # Pass the name of the binary as input, it will @@ -277,15 +304,26 @@ fetch_release_artifacts_from_s3() { function get_s3_url_base() { name=$1 case $name in - polkadot | polkadot-execute-worker | polkadot-prepare-worker | staking-miner) + polkadot | polkadot-execute-worker | polkadot-prepare-worker ) printf "https://releases.parity.io/polkadot" ;; - polkadot-parachain) - printf "https://releases.parity.io/cumulus" + polkadot-parachain) + printf "https://releases.parity.io/polkadot-parachain" + ;; + + polkadot-omni-node) + printf "https://releases.parity.io/polkadot-omni-node" ;; - *) + chain-spec-builder) + printf "https://releases.parity.io/chain-spec-builder" + ;; + + frame-omni-bencher) + printf "https://releases.parity.io/frame-omni-bencher" + ;; + *) printf "UNSUPPORTED BINARY $name" exit 1 ;; @@ -306,9 +344,10 @@ function import_gpg_keys() { EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" PARITY_RELEASES="90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE" + PARITY_RELEASES_SIGN_COMMITS="D8018FBB3F534D866A45998293C5FB5F6A367B51" echo "Importing GPG keys from $GPG_KEYSERVER" - for key in $SEC $EGOR $MORGAN $PARITY_RELEASES; do + for key in $SEC $EGOR $MORGAN $PARITY_RELEASES $PARITY_RELEASES_SIGN_COMMITS; do ( echo "Importing GPG key $key" gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key @@ -467,3 +506,16 @@ validate_stable_tag() { exit 1 fi } + +# Prepare docker stable tag form the polkadot stable tag +# input: tag (polkaodot-stableYYMM(-X) or polkadot-stableYYMM(-X)-rcX) +# output: stableYYMM(-X) or stableYYMM(-X)-rcX +prepare_docker_stable_tag() { + tag="$1" + if [[ "$tag" =~ stable[0-9]{4}(-[0-9]+)?(-rc[0-9]+)? ]]; then + echo "${BASH_REMATCH[0]}" + else + echo "Tag is invalid: $tag" + exit 1 + fi +} diff --git a/.github/scripts/release/build-deb.sh b/.github/scripts/release/build-deb.sh index 6cb833f98a4e..8dce621bb4de 100755 --- a/.github/scripts/release/build-deb.sh +++ b/.github/scripts/release/build-deb.sh @@ -9,8 +9,7 @@ cargo install --version 2.7.0 cargo-deb --locked -q echo "Using cargo-deb v$(cargo-deb --version)" echo "Building a Debian package for '$PRODUCT' in '$PROFILE' profile" -# we need to start the custom version with a didgit as requires it cargo-deb -cargo deb --profile $PROFILE --no-strip --no-build -p $PRODUCT --deb-version 1-$VERSION +cargo deb --profile $PROFILE --no-strip --no-build -p $PRODUCT --deb-version $VERSION deb=target/debian/$PRODUCT_*_amd64.deb diff --git a/.github/scripts/release/build-linux-release.sh b/.github/scripts/release/build-linux-release.sh index a6bd658d292a..874c9b44788b 100755 --- a/.github/scripts/release/build-linux-release.sh +++ b/.github/scripts/release/build-linux-release.sh @@ -3,6 +3,8 @@ # This is used to build our binaries: # - polkadot # - polkadot-parachain +# - polkadot-omni-node +# # set -e BIN=$1 @@ -21,7 +23,7 @@ time cargo build --profile $PROFILE --locked --verbose --bin $BIN --package $PAC echo "Artifact target: $ARTIFACTS" cp ./target/$PROFILE/$BIN "$ARTIFACTS" -pushd "$ARTIFACTS" > /dev/nul +pushd "$ARTIFACTS" > /dev/null sha256sum "$BIN" | tee "$BIN.sha256" EXTRATAG="$($ARTIFACTS/$BIN --version | diff --git a/.github/scripts/release/build-macos-release.sh b/.github/scripts/release/build-macos-release.sh new file mode 100755 index 000000000000..ba6dcc65d650 --- /dev/null +++ b/.github/scripts/release/build-macos-release.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# This is used to build our binaries: +# - polkadot +# - polkadot-parachain +# - polkadot-omni-node +# set -e + +BIN=$1 +PACKAGE=${2:-$BIN} + +PROFILE=${PROFILE:-production} +# parity-macos runner needs a path where it can +# write, so make it relative to github workspace. +ARTIFACTS=$GITHUB_WORKSPACE/artifacts/$BIN +VERSION=$(git tag -l --contains HEAD | grep -E "^v.*") + +echo "Artifacts will be copied into $ARTIFACTS" +mkdir -p "$ARTIFACTS" + +git log --pretty=oneline -n 1 +time cargo build --profile $PROFILE --locked --verbose --bin $BIN --package $PACKAGE + +echo "Artifact target: $ARTIFACTS" + +cp ./target/$PROFILE/$BIN "$ARTIFACTS" +pushd "$ARTIFACTS" > /dev/null +sha256sum "$BIN" | tee "$BIN.sha256" + +EXTRATAG="$($ARTIFACTS/$BIN --version | + sed -n -r 's/^'$BIN' ([0-9.]+.*-[0-9a-f]{7,13})-.*$/\1/p')" + +EXTRATAG="${VERSION}-${EXTRATAG}-$(cut -c 1-8 $ARTIFACTS/$BIN.sha256)" + +echo "$BIN version = ${VERSION} (EXTRATAG = ${EXTRATAG})" +echo -n ${VERSION} > "$ARTIFACTS/VERSION" +echo -n ${EXTRATAG} > "$ARTIFACTS/EXTRATAG" diff --git a/.github/scripts/release/distributions b/.github/scripts/release/distributions new file mode 100644 index 000000000000..a430ec76c6ba --- /dev/null +++ b/.github/scripts/release/distributions @@ -0,0 +1,39 @@ +Origin: Parity +Label: Parity +Codename: release +Architectures: amd64 +Components: main +Description: Apt repository for software made by Parity Technologies Ltd. +SignWith: 90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE + +Origin: Parity +Label: Parity Staging +Codename: staging +Architectures: amd64 +Components: main +Description: Staging distribution for Parity Technologies Ltd. packages +SignWith: 90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE + +Origin: Parity +Label: Parity stable2407 +Codename: stable2407 +Architectures: amd64 +Components: main +Description: Apt repository for software made by Parity Technologies Ltd. +SignWith: 90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE + +Origin: Parity +Label: Parity stable2409 +Codename: stable2409 +Architectures: amd64 +Components: main +Description: Apt repository for software made by Parity Technologies Ltd. +SignWith: 90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE + +Origin: Parity +Label: Parity stable2412 +Codename: stable2412 +Architectures: amd64 +Components: main +Description: Apt repository for software made by Parity Technologies Ltd. +SignWith: 90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE diff --git a/.github/scripts/release/release_lib.sh b/.github/scripts/release/release_lib.sh index f5032073b617..984709f2ea03 100644 --- a/.github/scripts/release/release_lib.sh +++ b/.github/scripts/release/release_lib.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Set the new version by replacing the value of the constant given as patetrn +# Set the new version by replacing the value of the constant given as pattern # in the file. # # input: pattern, version, file @@ -119,21 +119,79 @@ set_polkadot_parachain_binary_version() { upload_s3_release() { + alias aws='podman run --rm -it docker.io/paritytech/awscli -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_BUCKET aws' + + product=$1 + version=$2 + target=$3 + + echo "Working on product: $product " + echo "Working on version: $version " + echo "Working on platform: $target " + + URL_BASE=$(get_s3_url_base $product) + + echo "Current content, should be empty on new uploads:" + aws s3 ls "s3://${URL_BASE}/${version}/${target}" --recursive --human-readable --summarize || true + echo "Content to be uploaded:" + artifacts="release-artifacts/$target/$product/" + ls "$artifacts" + aws s3 sync --acl public-read "$artifacts" "s3://${URL_BASE}/${version}/${target}" + echo "Uploaded files:" + aws s3 ls "s3://${URL_BASE}/${version}/${target}" --recursive --human-readable --summarize + echo "✅ The release should be at https://${URL_BASE}/${version}/${target}" +} + +# Upload runtimes artifacts to s3 release bucket +# +# input: version (stable release tage.g. polkadot-stable2412 or polkadot-stable2412-rc1) +# output: none +upload_s3_runtimes_release_artifacts() { alias aws='podman run --rm -it docker.io/paritytech/awscli -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_BUCKET aws' - product=$1 - version=$2 + version=$1 - echo "Working on product: $product " echo "Working on version: $version " echo "Current content, should be empty on new uploads:" - aws s3 ls "s3://releases.parity.io/polkadot/${version}/" --recursive --human-readable --summarize || true + aws s3 ls "s3://releases.parity.io/polkadot/runtimes/${version}/" --recursive --human-readable --summarize || true echo "Content to be uploaded:" - artifacts="artifacts/$product/" + artifacts="artifacts/runtimes/" ls "$artifacts" - aws s3 sync --acl public-read "$artifacts" "s3://releases.parity.io/polkadot/${version}/" + aws s3 sync --acl public-read "$artifacts" "s3://releases.parity.io/polkadot/runtimes/${version}/" echo "Uploaded files:" - aws s3 ls "s3://releases.parity.io/polkadot/${version}/" --recursive --human-readable --summarize - echo "✅ The release should be at https://releases.parity.io/polkadot/${version}" + aws s3 ls "s3://releases.parity.io/polkadot/runtimes/${version}/" --recursive --human-readable --summarize + echo "✅ The release should be at https://releases.parity.io/polkadot/runtimes/${version}" +} + + +# Pass the name of the binary as input, it will +# return the s3 base url +function get_s3_url_base() { + name=$1 + case $name in + polkadot | polkadot-execute-worker | polkadot-prepare-worker ) + printf "releases.parity.io/polkadot" + ;; + + polkadot-parachain) + printf "releases.parity.io/polkadot-parachain" + ;; + + polkadot-omni-node) + printf "releases.parity.io/polkadot-omni-node" + ;; + + chain-spec-builder) + printf "releases.parity.io/chain-spec-builder" + ;; + + frame-omni-bencher) + printf "releases.parity.io/frame-omni-bencher" + ;; + *) + printf "UNSUPPORTED BINARY $name" + exit 1 + ;; + esac } diff --git a/.github/workflows/build-misc.yml b/.github/workflows/build-misc.yml index 2a8e81b97878..335c26282027 100644 --- a/.github/workflows/build-misc.yml +++ b/.github/workflows/build-misc.yml @@ -16,12 +16,11 @@ permissions: contents: read jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml build-runtimes-polkavm: - timeout-minutes: 20 + timeout-minutes: 60 needs: [preflight] runs-on: ${{ needs.preflight.outputs.RUNNER }} container: @@ -38,11 +37,14 @@ jobs: - name: Build env: SUBSTRATE_RUNTIME_TARGET: riscv - run: | - forklift cargo check -p minimal-template-runtime - forklift cargo check -p westend-runtime - forklift cargo check -p rococo-runtime - forklift cargo check -p polkadot-test-runtime + id: required + run: forklift cargo check -p minimal-template-runtime -p westend-runtime -p rococo-runtime -p polkadot-test-runtime + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} build-subkey: timeout-minutes: 20 @@ -62,9 +64,16 @@ jobs: - name: Build env: SKIP_WASM_BUILD: 1 + id: required run: | cd ./substrate/bin/utils/subkey forklift cargo build --locked --release + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} confirm-required-build-misc-jobs-passed: runs-on: ubuntu-latest diff --git a/.github/workflows/build-publish-eth-rpc.yml b/.github/workflows/build-publish-eth-rpc.yml index 9dc575cf1be2..3aa1624096df 100644 --- a/.github/workflows/build-publish-eth-rpc.yml +++ b/.github/workflows/build-publish-eth-rpc.yml @@ -44,7 +44,7 @@ jobs: uses: actions/checkout@v4 - name: Build Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./substrate/frame/revive/rpc/Dockerfile @@ -70,7 +70,7 @@ jobs: password: ${{ secrets.PARITYPR_DOCKERHUB_PASSWORD }} - name: Build Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./substrate/frame/revive/rpc/Dockerfile diff --git a/.github/workflows/check-frame-omni-bencher.yml b/.github/workflows/check-frame-omni-bencher.yml index 924a8b7f712f..bc0ff82b6774 100644 --- a/.github/workflows/check-frame-omni-bencher.yml +++ b/.github/workflows/check-frame-omni-bencher.yml @@ -36,9 +36,16 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script + id: required run: | forklift cargo build --locked --quiet --release -p asset-hub-westend-runtime --features runtime-benchmarks forklift cargo run --locked --release -p frame-omni-bencher --quiet -- v1 benchmark pallet --runtime target/release/wbuild/asset-hub-westend-runtime/asset_hub_westend_runtime.compact.compressed.wasm --all --steps 2 --repeat 1 --quiet + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} runtime-matrix: runs-on: ubuntu-latest @@ -80,6 +87,7 @@ jobs: uses: actions/checkout@v4 - name: script + id: required run: | RUNTIME_BLOB_NAME=$(echo $PACKAGE_NAME | sed 's/-/_/g').compact.compressed.wasm RUNTIME_BLOB_PATH=./target/release/wbuild/$PACKAGE_NAME/$RUNTIME_BLOB_NAME @@ -90,6 +98,13 @@ jobs: cmd="./target/release/frame-omni-bencher v1 benchmark pallet --runtime $RUNTIME_BLOB_PATH --all --steps 2 --repeat 1 $FLAGS" echo "Running command: $cmd" eval "$cmd" + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} + confirm-frame-omni-benchers-passed: runs-on: ubuntu-latest name: All benchmarks passed diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 8bd87118201a..21e2756e8b76 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - - uses: actions/setup-node@v4.0.4 + - uses: actions/setup-node@v4.1.0 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" @@ -56,7 +56,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - - uses: actions/setup-node@v4.0.4 + - uses: actions/setup-node@v4.1.0 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 3bbb9baba46e..cea6b9a8636a 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.0 (22. Sep 2023) - name: Lychee link checker - uses: lycheeverse/lychee-action@2bb232618be239862e31382c5c0eaeba12e5e966 # for v1.9.1 (10. Jan 2024) + uses: lycheeverse/lychee-action@f81112d0d2814ded911bd23e3beaa9dda9093915 # for v1.9.1 (10. Jan 2024) with: args: >- --config .config/lychee.toml diff --git a/.github/workflows/check-runtime-migration.yml b/.github/workflows/check-runtime-migration.yml index 758de0e7b433..9866ae18b98a 100644 --- a/.github/workflows/check-runtime-migration.yml +++ b/.github/workflows/check-runtime-migration.yml @@ -101,20 +101,29 @@ jobs: ./try-runtime create-snapshot --uri ${{ matrix.uri }} snapshot.raw - name: Build Runtime + id: required1 run: | echo "---------- Building ${{ matrix.package }} runtime ----------" - time forklift cargo build --release --locked -p ${{ matrix.package }} --features try-runtime -q + forklift cargo build --release --locked -p ${{ matrix.package }} --features try-runtime -q - name: Run Check + id: required2 run: | echo "Running ${{ matrix.network }} runtime migration check" export RUST_LOG=remote-ext=debug,runtime=debug echo "---------- Executing on-runtime-upgrade for ${{ matrix.network }} ----------" - time ./try-runtime ${{ matrix.command_extra_args }} \ + ./try-runtime ${{ matrix.command_extra_args }} \ --runtime ./target/release/wbuild/${{ matrix.package }}/${{ matrix.wasm }} \ on-runtime-upgrade --disable-spec-version-check --checks=all ${{ matrix.subcommand_extra_args }} snap -p snapshot.raw sleep 5 + - name: Stop all workflows if failed + if: ${{ failure() && (steps.required1.conclusion == 'failure' || steps.required2.conclusion == 'failure') }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} + # name of this job must be unique across all workflows # otherwise GitHub will mark all these jobs as required confirm-required-checks-passed: diff --git a/.github/workflows/check-semver.yml b/.github/workflows/check-semver.yml index 6b8ac4489abc..0da3e54ef60b 100644 --- a/.github/workflows/check-semver.yml +++ b/.github/workflows/check-semver.yml @@ -4,13 +4,14 @@ on: pull_request: types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] workflow_dispatch: + merge_group: concurrency: group: check-semver-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true env: - TOOLCHAIN: nightly-2024-06-01 + TOOLCHAIN: nightly-2024-11-19 jobs: preflight: @@ -80,11 +81,16 @@ jobs: - name: install parity-publish if: ${{ !contains(github.event.pull_request.labels.*.name, 'R0-silent') }} # Set the target dir to cache the build. - run: CARGO_TARGET_DIR=./target/ cargo install parity-publish@0.8.0 --locked -q + run: CARGO_TARGET_DIR=./target/ cargo install parity-publish@0.10.3 --locked -q - name: check semver if: ${{ !contains(github.event.pull_request.labels.*.name, 'R0-silent') }} run: | + if [ -z "$PR" ]; then + echo "Skipping master/merge queue" + exit 0 + fi + export CARGO_TARGET_DIR=target export RUSTFLAGS='-A warnings -A missing_docs' export SKIP_WASM_BUILD=1 diff --git a/.github/workflows/checks-quick.yml b/.github/workflows/checks-quick.yml index eefe36d9791d..4c26b85a6303 100644 --- a/.github/workflows/checks-quick.yml +++ b/.github/workflows/checks-quick.yml @@ -15,7 +15,6 @@ concurrency: permissions: {} jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml @@ -28,7 +27,14 @@ jobs: steps: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Cargo fmt + id: required run: cargo +nightly fmt --all -- --check + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} check-dependency-rules: runs-on: ubuntu-latest timeout-minutes: 20 @@ -91,7 +97,6 @@ jobs: --exclude "substrate/frame/contracts/fixtures/build" "substrate/frame/contracts/fixtures/contracts/common" - "substrate/frame/revive/fixtures/build" "substrate/frame/revive/fixtures/contracts/common" - name: deny git deps run: python3 .github/scripts/deny-git-deps.py . @@ -102,7 +107,7 @@ jobs: - name: Checkout sources uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Setup Node.js - uses: actions/setup-node@v4.0.4 + uses: actions/setup-node@v4.1.0 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" @@ -172,6 +177,32 @@ jobs: env: ASSERT_REGEX: "FAIL-CI" GIT_DEPTH: 1 + check-readme: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Install prerequisites + run: | + sudo apt-get update + sudo apt-get install -y protobuf-compiler + + - name: Set rust version from env file + run: | + RUST_VERSION=$(cat .github/env | sed -E 's/.*ci-unified:([^-]+)-([^-]+).*/\2/') + echo $RUST_VERSION + echo "RUST_VERSION=${RUST_VERSION}" >> $GITHUB_ENV + + - name: Install Rust + uses: actions-rust-lang/setup-rust-toolchain@11df97af8e8102fd60b60a77dfbf58d40cd843b8 # v1.10.1 + with: + cache: false + toolchain: ${{ env.RUST_VERSION }} + components: cargo, clippy, rust-docs, rust-src, rustfmt, rustc, rust-std + + - name: Find README.docify.md files and check generated READMEs + run: .github/scripts/check-missing-readme-generation.sh confirm-required-checks-quick-jobs-passed: runs-on: ubuntu-latest @@ -187,6 +218,7 @@ jobs: - check-markdown - check-umbrella - check-fail-ci + - check-readme if: always() && !cancelled() steps: - run: | diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 8ec3660307d4..02428711811f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -31,9 +31,17 @@ jobs: steps: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: script + id: required run: | cargo clippy --all-targets --locked --workspace --quiet cargo clippy --all-targets --all-features --locked --workspace --quiet + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} + check-try-runtime: runs-on: ${{ needs.preflight.outputs.RUNNER }} needs: [preflight] @@ -44,6 +52,7 @@ jobs: steps: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: script + id: required run: | forklift cargo check --locked --all --features try-runtime --quiet # this is taken from cumulus @@ -52,6 +61,13 @@ jobs: # 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 --quiet + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} + # check-core-crypto-features works fast without forklift check-core-crypto-features: runs-on: ${{ needs.preflight.outputs.RUNNER }} @@ -63,6 +79,7 @@ jobs: steps: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: script + id: required run: | cd substrate/primitives/core ./check-features-variants.sh @@ -73,6 +90,12 @@ jobs: cd substrate/primitives/keyring ./check-features-variants.sh cd - + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} # name of this job must be unique across all workflows # otherwise GitHub will mark all these jobs as required confirm-required-checks-passed: diff --git a/.github/workflows/cmd.yml b/.github/workflows/cmd.yml index 525ab0c0fc23..42b2eab3b9e4 100644 --- a/.github/workflows/cmd.yml +++ b/.github/workflows/cmd.yml @@ -19,10 +19,10 @@ jobs: steps: - name: Generate token id: generate_token - uses: tibdex/github-app-token@v2.1.0 + uses: actions/create-github-app-token@v1 with: - app_id: ${{ secrets.CMD_BOT_APP_ID }} - private_key: ${{ secrets.CMD_BOT_APP_KEY }} + app-id: ${{ secrets.CMD_BOT_APP_ID }} + private-key: ${{ secrets.CMD_BOT_APP_KEY }} - name: Check if user is a member of the organization id: is-member @@ -227,7 +227,8 @@ jobs: cat .github/env >> $GITHUB_OUTPUT if [ -n "$IMAGE_OVERRIDE" ]; then - echo "IMAGE=$IMAGE_OVERRIDE" >> $GITHUB_OUTPUT + IMAGE=$IMAGE_OVERRIDE + echo "IMAGE=$IMAGE" >> $GITHUB_OUTPUT fi if [[ $BODY == "/cmd bench"* ]]; then @@ -237,6 +238,10 @@ jobs: else echo "RUNNER=ubuntu-latest" >> $GITHUB_OUTPUT fi + - name: Print outputs + run: | + echo "RUNNER=${{ steps.set-image.outputs.RUNNER }}" + echo "IMAGE=${{ steps.set-image.outputs.IMAGE }}" # Get PR branch name, because the issue_comment event does not contain the PR branch name get-pr-branch: @@ -283,10 +288,24 @@ jobs: env: JOB_NAME: "cmd" runs-on: ${{ needs.set-image.outputs.RUNNER }} - timeout-minutes: 4320 # 72 hours -> 3 days; as it could take a long time to run all the runtimes/pallets container: image: ${{ needs.set-image.outputs.IMAGE }} + timeout-minutes: 1440 # 24 hours per runtime steps: + - name: Generate token + uses: actions/create-github-app-token@v1 + id: generate_token + with: + app-id: ${{ secrets.CMD_BOT_APP_ID }} + private-key: ${{ secrets.CMD_BOT_APP_KEY }} + + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ steps.generate_token.outputs.token }} + repository: ${{ needs.get-pr-branch.outputs.repo }} + ref: ${{ needs.get-pr-branch.outputs.pr-branch }} + - name: Get command uses: actions-ecosystem/action-regex-match@v2 id: get-pr-comment @@ -340,13 +359,7 @@ jobs: repo: context.repo.repo, body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has started 🚀 [See logs here](${job_url})` }) - - - name: Checkout - uses: actions/checkout@v4 - with: - repository: ${{ needs.get-pr-branch.outputs.repo }} - ref: ${{ needs.get-pr-branch.outputs.pr-branch }} - + - name: Install dependencies for bench if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') run: | @@ -364,6 +377,7 @@ jobs: # Fixes "detected dubious ownership" error in the ci git config --global --add safe.directory '*' git remote -v + cat /proc/cpuinfo python3 -m pip install -r .github/scripts/generate-prdoc.requirements.txt python3 .github/scripts/cmd/cmd.py $CMD $PR_ARG git status @@ -386,19 +400,41 @@ jobs: name: command-output path: /tmp/cmd/command_output.log + # Generate token for commit, as the earlier token expires after 1 hour, while cmd can take longer + - name: Generate token for commit + uses: actions/create-github-app-token@v1 + id: generate_token_commit + with: + app-id: ${{ secrets.CMD_BOT_APP_ID }} + private-key: ${{ secrets.CMD_BOT_APP_KEY }} + - name: Commit changes run: | if [ -n "$(git status --porcelain)" ]; then - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" + git config --global user.name command-bot + git config --global user.email "<>" + git config --global pull.rebase false + + # Push the results to the target branch + git remote add \ + github \ + "https://x-access-token:${{ steps.generate_token_commit.outputs.token }}@github.com/${{ needs.get-pr-branch.outputs.repo }}.git" || : + + push_changes() { + git push github "HEAD:${{ needs.get-pr-branch.outputs.pr-branch }}" + } git add . git restore --staged Cargo.lock # ignore changes in Cargo.lock git commit -m "Update from ${{ github.actor }} running command '${{ steps.get-pr-comment.outputs.group2 }}'" || true - git pull --rebase origin ${{ needs.get-pr-branch.outputs.pr-branch }} - - git push origin ${{ needs.get-pr-branch.outputs.pr-branch }} + # Attempt to push changes + if ! push_changes; then + echo "Push failed, trying to rebase..." + git pull --rebase github "${{ needs.get-pr-branch.outputs.pr-branch }}" + # After successful rebase, try pushing again + push_changes + fi else echo "Nothing to commit"; fi diff --git a/.github/workflows/command-backport.yml b/.github/workflows/command-backport.yml index 8f23bcd75f01..8a017a434525 100644 --- a/.github/workflows/command-backport.yml +++ b/.github/workflows/command-backport.yml @@ -40,7 +40,7 @@ jobs: uses: korthout/backport-action@v3 id: backport with: - target_branches: stable2407 stable2409 + target_branches: stable2407 stable2409 stable2412 merge_commits: skip github_token: ${{ steps.generate_token.outputs.token }} pull_description: | @@ -86,7 +86,7 @@ jobs: const reviewer = '${{ github.event.pull_request.user.login }}'; for (const pullNumber of pullNumbers) { - await github.pulls.createReviewRequest({ + await github.pulls.requestReviewers({ owner: context.repo.owner, repo: context.repo.repo, pull_number: parseInt(pullNumber), diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a257c8229598..b7c70c9e6d66 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,8 +25,15 @@ jobs: steps: - uses: actions/checkout@v4 - run: forklift cargo test --doc --workspace + id: required env: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} build-rustdoc: runs-on: ${{ needs.preflight.outputs.RUNNER }} @@ -38,6 +45,7 @@ jobs: steps: - uses: actions/checkout@v4 - run: forklift cargo doc --all-features --workspace --no-deps + id: required env: SKIP_WASM_BUILD: 1 RUSTDOCFLAGS: "-Dwarnings --default-theme=ayu --html-in-header ./docs/sdk/assets/header.html --extend-css ./docs/sdk/assets/theme.css --html-after-content ./docs/sdk/assets/after-content.html" @@ -60,6 +68,12 @@ jobs: path: ./crate-docs/ retention-days: 1 if-no-files-found: error + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} build-implementers-guide: runs-on: ubuntu-latest diff --git a/.github/workflows/publish-check-compile.yml b/.github/workflows/publish-check-compile.yml new file mode 100644 index 000000000000..ce1b2cb231d0 --- /dev/null +++ b/.github/workflows/publish-check-compile.yml @@ -0,0 +1,48 @@ +name: Check publish build + +on: + push: + branches: + - master + pull_request: + 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 + + check-publish-compile: + timeout-minutes: 90 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + + - name: Rust Cache + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 + with: + cache-on-failure: true + + - name: install parity-publish + run: cargo install parity-publish@0.10.3 --locked -q + + - name: parity-publish update plan + run: parity-publish --color always plan --skip-check --prdoc prdoc/ + + - name: parity-publish apply plan + run: parity-publish --color always apply --registry + + - name: parity-publish check compile + run: | + packages="$(parity-publish apply --print)" + + if [ -n "$packages" ]; then + cargo --color always check $(printf -- '-p %s ' $packages) + fi diff --git a/.github/workflows/publish-check-crates.yml b/.github/workflows/publish-check-crates.yml index 3fad3b641474..3150cb9dd405 100644 --- a/.github/workflows/publish-check-crates.yml +++ b/.github/workflows/publish-check-crates.yml @@ -24,7 +24,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.8.0 --locked -q + run: cargo install parity-publish@0.10.3 --locked -q - name: parity-publish check run: parity-publish --color always check --allow-unpublished diff --git a/.github/workflows/publish-claim-crates.yml b/.github/workflows/publish-claim-crates.yml index 37bf06bb82d8..a6efc8a5599e 100644 --- a/.github/workflows/publish-claim-crates.yml +++ b/.github/workflows/publish-claim-crates.yml @@ -18,7 +18,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.8.0 --locked -q + run: cargo install parity-publish@0.10.3 --locked -q - name: parity-publish claim env: diff --git a/.github/workflows/release-branchoff-stable.yml b/.github/workflows/release-10_branchoff-stable.yml similarity index 83% rename from .github/workflows/release-branchoff-stable.yml rename to .github/workflows/release-10_branchoff-stable.yml index 3086c0d21f42..adce1b261b71 100644 --- a/.github/workflows/release-branchoff-stable.yml +++ b/.github/workflows/release-10_branchoff-stable.yml @@ -13,13 +13,7 @@ on: required: true jobs: - check-workflow-can-run: - uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main - - prepare-tooling: - needs: [check-workflow-can-run] - if: needs.check-workflow-can-run.outputs.checks_passed == 'true' runs-on: ubuntu-latest outputs: node_version: ${{ steps.validate_inputs.outputs.node_version }} @@ -45,7 +39,7 @@ jobs: runs-on: ubuntu-latest environment: release env: - PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_KEY: ${{ secrets.PGP_KMS_SIGN_COMMITS_KEY }} PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -58,10 +52,19 @@ jobs: # Install pgpkms that is used to sign commits pip install git+https://github.com/paritytech-release/pgpkms.git@5a8f82fbb607ea102d8c178e761659de54c7af69 + - name: Generate content write token for the release automation + id: generate_write_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.RELEASE_AUTOMATION_APP_ID }} + private-key: ${{ secrets.RELEASE_AUTOMATION_APP_PRIVATE_KEY }} + owner: paritytech + - name: Checkout sources uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 with: ref: master + token: ${{ steps.generate_write_token.outputs.token }} - name: Import gpg keys run: | @@ -69,14 +72,13 @@ jobs: import_gpg_keys - - name: Config git run: | git config --global commit.gpgsign true git config --global gpg.program /home/runner/.local/bin/pgpkms-git git config --global user.name "ParityReleases" git config --global user.email "release-team@parity.io" - git config --global user.signingKey "90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE" + git config --global user.signingKey "D8018FBB3F534D866A45998293C5FB5F6A367B51" - name: Create stable branch run: | @@ -84,6 +86,8 @@ jobs: git show-ref "$STABLE_BRANCH_NAME" - name: Bump versions, reorder prdocs and push stable branch + env: + GH_TOKEN: ${{ steps.generate_write_token.outputs.token }} run: | . ./.github/scripts/release/release_lib.sh @@ -101,4 +105,6 @@ jobs: reorder_prdocs $STABLE_BRANCH_NAME + gh auth setup-git + git push origin "$STABLE_BRANCH_NAME" diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-11_rc-automation.yml similarity index 59% rename from .github/workflows/release-10_rc-automation.yml rename to .github/workflows/release-11_rc-automation.yml index 41783f6cc721..0be671185c70 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-11_rc-automation.yml @@ -23,12 +23,46 @@ jobs: - name: "RelEng: Polkadot Release Coordination" room: '!cqAmzdIcbOFwrdrubV:parity.io' environment: release + env: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_SIGN_COMMITS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} steps: + - name: Install pgpkkms + run: | + # Install pgpkms that is used to sign commits + pip install git+https://github.com/paritytech-release/pgpkms.git@5a8f82fbb607ea102d8c178e761659de54c7af69 + + - name: Generate content write token for the release automation + id: generate_write_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.RELEASE_AUTOMATION_APP_ID }} + private-key: ${{ secrets.RELEASE_AUTOMATION_APP_PRIVATE_KEY }} + owner: paritytech + - name: Checkout sources uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 with: fetch-depth: 0 + token: ${{ steps.generate_write_token.outputs.token }} + + - name: Import gpg keys + run: | + . ./.github/scripts/common/lib.sh + + import_gpg_keys + + - name: Config git + run: | + git config --global commit.gpgsign true + git config --global gpg.program /home/runner/.local/bin/pgpkms-git + git config --global user.name "ParityReleases" + git config --global user.email "release-team@parity.io" + git config --global user.signingKey "D8018FBB3F534D866A45998293C5FB5F6A367B51" - name: Compute next rc tag # if: ${{ steps.get_rel_product.outputs.product == 'polkadot' }} @@ -58,13 +92,12 @@ jobs: fi - name: Apply new tag - uses: tvdias/github-tagger@ed7350546e3e503b5e942dffd65bc8751a95e49d # v0.0.2 - with: - # We can't use the normal GITHUB_TOKEN for the following reason: - # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token - # RELEASE_BRANCH_TOKEN requires public_repo OAuth scope - repo-token: "${{ secrets.RELEASE_BRANCH_TOKEN }}" - tag: ${{ steps.compute_tag.outputs.new_tag }} + env: + GH_TOKEN: ${{ steps.generate_write_token.outputs.token }} + RC_TAG: ${{ steps.compute_tag.outputs.new_tag }} + run: | + git tag -s $RC_TAG -m "new rc tag $RC_TAG" + git push origin $RC_TAG - name: Send Matrix message to ${{ matrix.channel.name }} uses: s3krit/matrix-message-action@70ad3fb812ee0e45ff8999d6af11cafad11a6ecf # v0.0.3 diff --git a/.github/workflows/release-20_build-rc.yml b/.github/workflows/release-20_build-rc.yml new file mode 100644 index 000000000000..d4c7055c37c5 --- /dev/null +++ b/.github/workflows/release-20_build-rc.yml @@ -0,0 +1,263 @@ +name: Release - Build node release candidate + +on: + workflow_dispatch: + inputs: + binary: + description: Binary to be build for the release + default: all + type: choice + options: + - polkadot + - polkadot-parachain + - polkadot-omni-node + - frame-omni-bencher + - chain-spec-builder + - all + + release_tag: + description: Tag matching the actual release candidate with the format polkadot-stableYYMM(-X)-rcX or polkadot-stableYYMM(-X) + type: string + +jobs: + check-synchronization: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + + validate-inputs: + needs: [check-synchronization] + if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.validate_inputs.outputs.release_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + RELEASE_TAG=$(validate_stable_tag ${{ inputs.release_tag }}) + echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT + + build-polkadot-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot", "polkadot-prepare-worker", "polkadot-execute-worker"]' + package: polkadot + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: x86_64-unknown-linux-gnu + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-polkadot-parachain-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot-parachain"]' + package: "polkadot-parachain-bin" + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: x86_64-unknown-linux-gnu + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-polkadot-omni-node-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot-omni-node' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot-omni-node"]' + package: "polkadot-omni-node" + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: x86_64-unknown-linux-gnu + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-frame-omni-bencher-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'frame-omni-bencher' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["frame-omni-bencher"]' + package: "frame-omni-bencher" + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: x86_64-unknown-linux-gnu + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-chain-spec-builder-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'chain-spec-builder' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["chain-spec-builder"]' + package: staging-chain-spec-builder + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: x86_64-unknown-linux-gnu + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-polkadot-macos-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot", "polkadot-prepare-worker", "polkadot-execute-worker"]' + package: polkadot + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: aarch64-apple-darwin + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-polkadot-parachain-macos-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot-parachain"]' + package: polkadot-parachain-bin + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: aarch64-apple-darwin + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-polkadot-omni-node-macos-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot-omni-node' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot-omni-node"]' + package: polkadot-omni-node + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: aarch64-apple-darwin + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-frame-omni-bencher-macos-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'frame-omni-bencher' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["frame-omni-bencher"]' + package: frame-omni-bencher + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: aarch64-apple-darwin + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read + + build-chain-spec-builder-macos-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'chain-spec-builder' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["chain-spec-builder"]' + package: staging-chain-spec-builder + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: aarch64-apple-darwin + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + permissions: + id-token: write + attestations: write + contents: read diff --git a/.github/workflows/release-30_publish_release_draft.yml b/.github/workflows/release-30_publish_release_draft.yml index 73d1aeaa4009..78ceea91f100 100644 --- a/.github/workflows/release-30_publish_release_draft.yml +++ b/.github/workflows/release-30_publish_release_draft.yml @@ -1,19 +1,46 @@ name: Release - Publish draft -on: - push: - tags: - # Catches v1.2.3 and v1.2.3-rc1 - - v[0-9]+.[0-9]+.[0-9]+* - # - polkadot-stable[0-9]+* Activate when the release process from release org is setteled +# This workflow runs in paritytech-release and creates full release draft with: +# - release notes +# - info about the runtimes +# - attached artifacts: +# - runtimes +# - binaries +# - signatures +on: workflow_dispatch: inputs: - version: - description: Current release/rc version + release_tag: + description: Tag matching the actual release candidate with the format polkadot-stableYYMM(-X)-rcX or polkadot-stableYYMM(-X) + required: true + type: string jobs: + check-synchronization: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + + validate-inputs: + needs: [ check-synchronization ] + if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.validate_inputs.outputs.release_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + RELEASE_TAG=$(validate_stable_tag ${{ inputs.release_tag }}) + echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT + get-rust-versions: + needs: [ validate-inputs ] runs-on: ubuntu-latest outputs: rustc-stable: ${{ steps.get-rust-versions.outputs.stable }} @@ -24,54 +51,35 @@ jobs: echo "stable=$RUST_STABLE_VERSION" >> $GITHUB_OUTPUT build-runtimes: + needs: [ validate-inputs ] uses: "./.github/workflows/release-srtool.yml" with: excluded_runtimes: "asset-hub-rococo bridge-hub-rococo contracts-rococo coretime-rococo people-rococo rococo rococo-parachain substrate-test bp cumulus-test kitchensink minimal-template parachain-template penpal polkadot-test seedling shell frame-try sp solochain-template polkadot-sdk-docs-first" build_opts: "--features on-chain-release-build" - - build-binaries: - runs-on: ubuntu-latest - strategy: - matrix: - # Tuples of [package, binary-name] - binary: [ [frame-omni-bencher, frame-omni-bencher], [staging-chain-spec-builder, chain-spec-builder], [polkadot-omni-node, polkadot-omni-node] ] - steps: - - name: Checkout sources - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.0.0 - - - name: Install protobuf-compiler - run: | - sudo apt update - sudo apt install -y protobuf-compiler - - - name: Build ${{ matrix.binary[1] }} binary - run: | - cargo build --locked --profile=production -p ${{ matrix.binary[0] }} --bin ${{ matrix.binary[1] }} - target/production/${{ matrix.binary[1] }} --version - - - name: Upload ${{ matrix.binary[1] }} binary - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ matrix.binary[1] }} - path: target/production/${{ matrix.binary[1] }} - + profile: production + permissions: + id-token: write + attestations: write + contents: read publish-release-draft: runs-on: ubuntu-latest - needs: [ get-rust-versions, build-runtimes ] + environment: release + needs: [ validate-inputs, get-rust-versions, build-runtimes ] outputs: release_url: ${{ steps.create-release.outputs.html_url }} asset_upload_url: ${{ steps.create-release.outputs.upload_url }} + steps: - name: Checkout - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.0.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Download artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - name: Prepare tooling run: | - URL=https://github.com/chevdor/tera-cli/releases/download/v0.2.4/tera-cli_linux_amd64.deb + URL=https://github.com/chevdor/tera-cli/releases/download/v0.4.0/tera-cli_linux_amd64.deb wget $URL -O tera.deb sudo dpkg -i tera.deb @@ -87,20 +95,21 @@ jobs: GLUTTON_WESTEND_DIGEST: ${{ github.workspace}}/glutton-westend-runtime/glutton-westend-srtool-digest.json PEOPLE_WESTEND_DIGEST: ${{ github.workspace}}/people-westend-runtime/people-westend-srtool-digest.json WESTEND_DIGEST: ${{ github.workspace}}/westend-runtime/westend-srtool-digest.json + RELEASE_TAG: ${{ needs.validate-inputs.outputs.release_tag }} shell: bash run: | . ./.github/scripts/common/lib.sh export REF1=$(get_latest_release_tag) - if [[ -z "${{ inputs.version }}" ]]; then + if [[ -z "$RELEASE_TAG" ]]; then export REF2="${{ github.ref_name }}" echo "REF2: ${REF2}" else - export REF2="${{ inputs.version }}" + export REF2="$RELEASE_TAG" echo "REF2: ${REF2}" fi echo "REL_TAG=$REF2" >> $GITHUB_ENV - export VERSION=$(echo "$REF2" | sed -E 's/.*(stable[0-9]+).*$/\1/') + export VERSION=$(echo "$REF2" | sed -E 's/.*(stable[0-9]{4}(-[0-9]+)?).*$/\1/') ./scripts/release/build-changelogs.sh @@ -112,19 +121,29 @@ jobs: scripts/release/context.json **/*-srtool-digest.json + - name: Generate content write token for the release automation + id: generate_write_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.POLKADOT_SDK_RELEASE_RW_APP_ID }} + private-key: ${{ secrets.POLKADOT_SDK_RELEASE_RW_APP_KEY }} + owner: paritytech + repositories: polkadot-sdk + - name: Create draft release id: create-release - uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ env.REL_TAG }} - release_name: Polkadot ${{ env.REL_TAG }} - body_path: ${{ github.workspace}}/scripts/release/RELEASE_DRAFT.md - draft: true + GITHUB_TOKEN: ${{ steps.generate_write_token.outputs.token }} + run: | + gh release create ${{ env.REL_TAG }} \ + --repo paritytech/polkadot-sdk \ + --draft \ + --title "Polkadot ${{ env.REL_TAG }}" \ + --notes-file ${{ github.workspace}}/scripts/release/RELEASE_DRAFT.md publish-runtimes: - needs: [ build-runtimes, publish-release-draft ] + needs: [ validate-inputs, build-runtimes, publish-release-draft ] + environment: release continue-on-error: true runs-on: ubuntu-latest strategy: @@ -132,7 +151,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.0.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Download artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 @@ -144,44 +163,83 @@ jobs: >>$GITHUB_ENV echo ASSET=$(find ${{ matrix.chain }}-runtime -name '*.compact.compressed.wasm') >>$GITHUB_ENV echo SPEC=$(<${JSON} jq -r .runtimes.compact.subwasm.core_version.specVersion) + - name: Generate content write token for the release automation + id: generate_write_token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.POLKADOT_SDK_RELEASE_RW_APP_ID }} + private-key: ${{ secrets.POLKADOT_SDK_RELEASE_RW_APP_KEY }} + owner: paritytech + repositories: polkadot-sdk + - name: Upload compressed ${{ matrix.chain }} v${{ env.SPEC }} wasm - if: ${{ matrix.chain != 'rococo-parachain' }} - uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.publish-release-draft.outputs.asset_upload_url }} - asset_path: ${{ env.ASSET }} - asset_name: ${{ matrix.chain }}_runtime-v${{ env.SPEC }}.compact.compressed.wasm - asset_content_type: application/wasm + GITHUB_TOKEN: ${{ steps.generate_write_token.outputs.token }} + run: | + gh release upload ${{ needs.validate-inputs.outputs.release_tag }} \ + --repo paritytech/polkadot-sdk \ + '${{ env.ASSET }}#${{ matrix.chain }}_runtime-v${{ env.SPEC }}.compact.compressed.wasm' - publish-binaries: - needs: [ publish-release-draft, build-binaries ] + publish-release-artifacts: + needs: [ validate-inputs, publish-release-draft ] + environment: release continue-on-error: true runs-on: ubuntu-latest strategy: matrix: - binary: [frame-omni-bencher, chain-spec-builder, polkadot-omni-node] + binary: [ polkadot, polkadot-execute-worker, polkadot-prepare-worker, polkadot-parachain, polkadot-omni-node, frame-omni-bencher, chain-spec-builder ] + target: [ x86_64-unknown-linux-gnu, aarch64-apple-darwin ] steps: - - name: Download artifacts - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + - name: Checkout sources + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Fetch binaries from s3 based on version + run: | + . ./.github/scripts/common/lib.sh + + VERSION="${{ needs.validate-inputs.outputs.release_tag }}" + fetch_release_artifacts_from_s3 ${{ matrix.binary }} ${{ matrix.target }} + + - name: Rename aarch64-apple-darwin binaries + if: ${{ matrix.target == 'aarch64-apple-darwin' }} + working-directory: ${{ github.workspace}}/release-artifacts/${{ matrix.target }}/${{ matrix.binary }} + run: | + mv ${{ matrix.binary }} ${{ matrix.binary }}-aarch64-apple-darwin + mv ${{ matrix.binary }}.asc ${{ matrix.binary }}-aarch64-apple-darwin.asc + mv ${{ matrix.binary }}.sha256 ${{ matrix.binary }}-aarch64-apple-darwin.sha256 + + - name: Generate content write token for the release automation + id: generate_write_token + uses: actions/create-github-app-token@v1 with: - name: ${{ matrix.binary }} + app-id: ${{ vars.POLKADOT_SDK_RELEASE_RW_APP_ID }} + private-key: ${{ secrets.POLKADOT_SDK_RELEASE_RW_APP_KEY }} + owner: paritytech + repositories: polkadot-sdk - - name: Upload ${{ matrix.binary }} binary - uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 #v1.0.2 + - name: Upload ${{ matrix.binary }} binary to release draft env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.publish-release-draft.outputs.asset_upload_url }} - asset_path: ${{ github.workspace}}/${{ matrix.binary }} - asset_name: ${{ matrix.binary }} - asset_content_type: application/octet-stream + GITHUB_TOKEN: ${{ steps.generate_write_token.outputs.token }} + working-directory: ${{ github.workspace}}/release-artifacts/${{ matrix.target }}/${{ matrix.binary }} + run: | + if [[ ${{ matrix.target }} == "aarch64-apple-darwin" ]]; then + gh release upload ${{ needs.validate-inputs.outputs.release_tag }} \ + --repo paritytech/polkadot-sdk \ + ${{ matrix.binary }}-aarch64-apple-darwin \ + ${{ matrix.binary }}-aarch64-apple-darwin.asc \ + ${{ matrix.binary }}-aarch64-apple-darwin.sha256 + else + gh release upload ${{ needs.validate-inputs.outputs.release_tag }} \ + --repo paritytech/polkadot-sdk \ + ${{ matrix.binary }} \ + ${{ matrix.binary }}.asc \ + ${{ matrix.binary }}.sha256 + fi post_to_matrix: runs-on: ubuntu-latest - needs: publish-release-draft + needs: [ validate-inputs, publish-release-draft ] environment: release strategy: matrix: @@ -197,5 +255,5 @@ jobs: access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} server: m.parity.io message: | - **New version of polkadot tagged**: ${{ github.ref_name }}
- Draft release created: ${{ needs.publish-release-draft.outputs.release_url }} + **New version of polkadot tagged**: ${{ needs.validate-inputs.outputs.release_tag }}
+ And release draft is release created in [polkadot-sdk repo](https://github.com/paritytech/polkadot-sdk/releases) diff --git a/.github/workflows/release-31_promote-rc-to-final.yml b/.github/workflows/release-31_promote-rc-to-final.yml new file mode 100644 index 000000000000..6aa9d4bddd1d --- /dev/null +++ b/.github/workflows/release-31_promote-rc-to-final.yml @@ -0,0 +1,125 @@ +name: Release - Promote RC to final candidate on S3 + +on: + workflow_dispatch: + inputs: + binary: + description: Binary to be build for the release + default: all + type: choice + options: + - polkadot + - polkadot-parachain + - polkadot-omni-node + - frame-omni-bencher + - chain-spec-builder + - all + release_tag: + description: Tag matching the actual release candidate with the format polkadot-stableYYMM(-X)-rcX + type: string + + +jobs: + + check-synchronization: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + + validate-inputs: + needs: [ check-synchronization ] + if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.validate_inputs.outputs.release_tag }} + final_tag: ${{ steps.validate_inputs.outputs.final_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + RELEASE_TAG=$(validate_stable_tag ${{ inputs.release_tag }}) + echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT + + promote-polkadot-rc-to-final: + if: ${{ inputs.binary == 'polkadot' || inputs.binary == 'all' }} + needs: [ validate-inputs ] + uses: ./.github/workflows/release-reusable-promote-to-final.yml + strategy: + matrix: + target: [ x86_64-unknown-linux-gnu, aarch64-apple-darwin ] + with: + package: polkadot + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: ${{ matrix.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + promote-polkadot-parachain-rc-to-final: + if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'all' }} + needs: [ validate-inputs ] + uses: ./.github/workflows/release-reusable-promote-to-final.yml + strategy: + matrix: + target: [ x86_64-unknown-linux-gnu, aarch64-apple-darwin ] + with: + package: polkadot-parachain + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: ${{ matrix.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + promote-polkadot-omni-node-rc-to-final: + if: ${{ inputs.binary == 'polkadot-omni-node' || inputs.binary == 'all' }} + needs: [ validate-inputs ] + uses: ./.github/workflows/release-reusable-promote-to-final.yml + strategy: + matrix: + target: [ x86_64-unknown-linux-gnu, aarch64-apple-darwin ] + with: + package: polkadot-omni-node + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: ${{ matrix.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + promote-frame-omni-bencher-rc-to-final: + if: ${{ inputs.binary == 'frame-omni-bencher' || inputs.binary == 'all' }} + needs: [ validate-inputs ] + uses: ./.github/workflows/release-reusable-promote-to-final.yml + strategy: + matrix: + target: [ x86_64-unknown-linux-gnu, aarch64-apple-darwin ] + with: + package: frame-omni-bencher + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: ${{ matrix.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + promote-chain-spec-builder-rc-to-final: + if: ${{ inputs.binary == 'chain-spec-builder' || inputs.binary == 'all' }} + needs: [ validate-inputs ] + uses: ./.github/workflows/release-reusable-promote-to-final.yml + strategy: + matrix: + target: [ x86_64-unknown-linux-gnu, aarch64-apple-darwin ] + with: + package: chain-spec-builder + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + target: ${{ matrix.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/release-40_publish-deb-package.yml b/.github/workflows/release-40_publish-deb-package.yml new file mode 100644 index 000000000000..3c5411ab16f0 --- /dev/null +++ b/.github/workflows/release-40_publish-deb-package.yml @@ -0,0 +1,152 @@ +name: Release - Publish polakdot deb package + +on: + workflow_dispatch: + inputs: + tag: + description: Current final release tag in the format polakdot-stableYYMM or polkadot-stable-YYMM-X + default: polkadot-stable2412 + required: true + type: string + + distribution: + description: Distribution where to publish deb package (release, staging, stable2407, etc) + default: staging + required: true + type: string + +jobs: + check-synchronization: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + + validate-inputs: + needs: [check-synchronization] + if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.validate_inputs.outputs.release_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + RELEASE_TAG=$(validate_stable_tag ${{ inputs.tag }}) + echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT + + + fetch-artifacts-from-s3: + runs-on: ubuntu-latest + needs: [validate-inputs] + env: + REPO: ${{ github.repository }} + RELEASE_TAG: ${{ needs.validate-inputs.outputs.release_tag }} + outputs: + VERSION: ${{ steps.fetch_artifacts_from_s3.outputs.VERSION }} + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Fetch rc artifacts or release artifacts from s3 based on version + id: fetch_artifacts_from_s3 + run: | + . ./.github/scripts/common/lib.sh + + VERSION="$(get_polkadot_node_version_from_code)" + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + + fetch_debian_package_from_s3 polkadot + + - name: Upload artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: release-artifacts + path: release-artifacts/polkadot/*.deb + + publish-deb-package: + runs-on: ubuntu-latest + needs: [fetch-artifacts-from-s3] + environment: release + env: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_DEB_PATH: "s3://releases-package-repos/deb" + LOCAL_DEB_REPO_PATH: ${{ github.workspace }}/deb + VERSION: ${{ needs.fetch-artifacts-from-s3.outputs.VERSION }} + + steps: + - name: Install pgpkkms + run: | + # Install pgpkms that is used to sign built artifacts + python3 -m pip install "pgpkms @ git+https://github.com/paritytech-release/pgpkms.git@1f8555426662ac93a3849480a35449f683b1c89f" + echo "PGPKMS_REPREPRO_PATH=$(which pgpkms-reprepro)" >> $GITHUB_ENV + + - name: Install awscli + run: | + python3 -m pip install awscli + which aws + + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Import gpg keys + shell: bash + run: | + . ./.github/scripts/common/lib.sh + + import_gpg_keys + + - name: Download artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: release-artifacts + path: release-artifacts + + - name: Setup local deb repo + run: | + sudo apt-get install -y reprepro + which reprepro + + sed -i "s|^SignWith:.*|SignWith: ! ${PGPKMS_REPREPRO_PATH}|" ${{ github.workspace }}/.github/scripts/release/distributions + + mkdir -p ${{ github.workspace }}/deb/conf + cp ${{ github.workspace }}/.github/scripts/release/distributions ${{ github.workspace }}/deb/conf/distributions + cat ${{ github.workspace }}/deb/conf/distributions + + - name: Sync local deb repo + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + run: | + # Download the current state of the deb repo + aws s3 sync "$AWS_DEB_PATH/db" "$LOCAL_DEB_REPO_PATH/db" + aws s3 sync "$AWS_DEB_PATH/pool" "$LOCAL_DEB_REPO_PATH/pool" + aws s3 sync "$AWS_DEB_PATH/dists" "$LOCAL_DEB_REPO_PATH/dists" + + - name: Add deb package to local repo + env: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + # Add the new deb to the repo + reprepro -b "$LOCAL_DEB_REPO_PATH" includedeb "${{ inputs.distribution }}" "release-artifacts/polkadot_${VERSION}_amd64.deb" + + - name: Upload updated deb repo + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + run: | + # Upload the updated repo - dists and pool should be publicly readable + aws s3 sync "$LOCAL_DEB_REPO_PATH/pool" "$AWS_DEB_PATH/pool" --acl public-read + aws s3 sync "$LOCAL_DEB_REPO_PATH/dists" "$AWS_DEB_PATH/dists" --acl public-read + aws s3 sync "$LOCAL_DEB_REPO_PATH/db" "$AWS_DEB_PATH/db" + aws s3 sync "$LOCAL_DEB_REPO_PATH/conf" "$AWS_DEB_PATH/conf" + + # Invalidate caches to make sure latest files are served + aws cloudfront create-invalidation --distribution-id E36FKEYWDXAZYJ --paths '/deb/*' diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 211fa000f8f5..a3c49598d6b1 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -4,10 +4,6 @@ name: Release - Publish Docker Image # It builds and published releases and rc candidates. on: - #TODO: activate automated run later - # release: - # types: - # - published workflow_dispatch: inputs: image_type: @@ -30,16 +26,6 @@ on: - polkadot-parachain - chain-spec-builder - release_id: - description: | - Release ID. - You can find it using the command: - curl -s \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/$OWNER/$REPO/releases | \ - jq '.[] | { name: .name, id: .id }' - required: true - type: number - registry: description: Container registry required: true @@ -55,12 +41,12 @@ on: default: parity version: - description: version to build/release + description: Version of the polkadot node release in format v1.16.0 or v1.16.0-rc1 default: v0.9.18 required: true stable_tag: - description: Tag matching the actual stable release version in the format stableYYMM or stableYYMM-X for patch releases + description: Tag matching the actual stable release version in the format polkadpt-stableYYMM(-rcX) or plkadot-stableYYMM-X(-rcX) for patch releases required: true permissions: @@ -78,11 +64,15 @@ env: IMAGE_TYPE: ${{ inputs.image_type }} jobs: + check-synchronization: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + validate-inputs: + needs: [check-synchronization] + if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' runs-on: ubuntu-latest outputs: version: ${{ steps.validate_inputs.outputs.VERSION }} - release_id: ${{ steps.validate_inputs.outputs.RELEASE_ID }} stable_tag: ${{ steps.validate_inputs.outputs.stable_tag }} steps: @@ -97,11 +87,6 @@ jobs: VERSION=$(filter_version_from_input "${{ inputs.version }}") echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT - RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") - echo "RELEASE_ID=${RELEASE_ID}" >> $GITHUB_OUTPUT - - echo "Release ID: $RELEASE_ID" - STABLE_TAG=$(validate_stable_tag ${{ inputs.stable_tag }}) echo "stable_tag=${STABLE_TAG}" >> $GITHUB_OUTPUT @@ -114,50 +99,26 @@ jobs: - name: Checkout sources uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - #TODO: this step will be needed when automated triggering will work - #this step runs only if the workflow is triggered automatically when new release is published - # if: ${{ env.EVENT_NAME == 'release' && env.EVENT_ACTION != '' && env.EVENT_ACTION == 'published' }} - # run: | - # mkdir -p release-artifacts && cd release-artifacts - - # for f in $BINARY $BINARY.asc $BINARY.sha256; do - # URL="https://github.com/${{ github.event.repository.full_name }}/releases/download/${{ github.event.release.tag_name }}/$f" - # echo " - Fetching $f from $URL" - # wget "$URL" -O "$f" - # done - # chmod a+x $BINARY - # ls -al - - name: Fetch rc artifacts or release artifacts from s3 based on version - #this step runs only if the workflow is triggered manually - if: ${{ env.EVENT_NAME == 'workflow_dispatch' && inputs.binary != 'polkadot-omni-node' && inputs.binary != 'chain-spec-builder'}} + # if: ${{ env.EVENT_NAME == 'workflow_dispatch' && inputs.binary != 'polkadot-omni-node' && inputs.binary != 'chain-spec-builder'}} run: | . ./.github/scripts/common/lib.sh - VERSION="${{ needs.validate-inputs.outputs.VERSION }}" + VERSION="${{ needs.validate-inputs.outputs.stable_tag }}" if [[ ${{ inputs.binary }} == 'polkadot' ]]; then bins=(polkadot polkadot-prepare-worker polkadot-execute-worker) for bin in "${bins[@]}"; do - fetch_release_artifacts_from_s3 $bin + fetch_release_artifacts_from_s3 $bin x86_64-unknown-linux-gnu done else - fetch_release_artifacts_from_s3 $BINARY + fetch_release_artifacts_from_s3 $BINARY x86_64-unknown-linux-gnu fi - - name: Fetch polkadot-omni-node/chain-spec-builder rc artifacts or release artifacts based on release id - #this step runs only if the workflow is triggered manually and only for chain-spec-builder - if: ${{ env.EVENT_NAME == 'workflow_dispatch' && (inputs.binary == 'polkadot-omni-node' || inputs.binary == 'chain-spec-builder') }} - run: | - . ./.github/scripts/common/lib.sh - - RELEASE_ID="${{ needs.validate-inputs.outputs.RELEASE_ID }}" - fetch_release_artifacts - - name: Upload artifacts uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: release-artifacts - path: release-artifacts/${{ env.BINARY }}/**/* + path: release-artifacts/x86_64-unknown-linux-gnu/${{ env.BINARY }}/**/* build-container: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build if: ${{ inputs.binary == 'polkadot-omni-node' || inputs.binary == 'polkadot-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} @@ -173,7 +134,7 @@ jobs: uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - name: Check sha256 ${{ env.BINARY }} - if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'polkadot' }} + # if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'polkadot' }} working-directory: release-artifacts run: | . ../.github/scripts/common/lib.sh @@ -182,7 +143,7 @@ jobs: check_sha256 $BINARY && echo "OK" || echo "ERR" - name: Check GPG ${{ env.BINARY }} - if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'polkadot' }} + # if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'polkadot' }} working-directory: release-artifacts run: | . ../.github/scripts/common/lib.sh @@ -190,35 +151,29 @@ jobs: check_gpg $BINARY - name: Fetch rc commit and tag + working-directory: release-artifacts if: ${{ env.IMAGE_TYPE == 'rc' }} id: fetch_rc_refs + shell: bash run: | - . ./.github/scripts/common/lib.sh - - echo "release=${{ needs.validate-inputs.outputs.stable_tag }}" >> $GITHUB_OUTPUT + . ../.github/scripts/common/lib.sh commit=$(git rev-parse --short HEAD) && \ echo "commit=${commit}" >> $GITHUB_OUTPUT - - echo "tag=${{ needs.validate-inputs.outputs.version }}" >> $GITHUB_OUTPUT + echo "release=$(echo ${{ needs.validate-inputs.outputs.version }})" >> $GITHUB_OUTPUT + echo "tag=$(prepare_docker_stable_tag ${{ needs.validate-inputs.outputs.stable_tag }})" >> $GITHUB_OUTPUT - name: Fetch release tags working-directory: release-artifacts if: ${{ env.IMAGE_TYPE == 'release'}} id: fetch_release_refs + shell: bash run: | - chmod a+rx $BINARY - - if [[ $BINARY != 'chain-spec-builder' ]]; then - VERSION=$(./$BINARY --version | awk '{ print $2 }' ) - release=$( echo $VERSION | cut -f1 -d- ) - else - release=$(echo ${{ needs.validate-inputs.outputs.VERSION }} | sed 's/^v//') - fi + . ../.github/scripts/common/lib.sh echo "tag=latest" >> $GITHUB_OUTPUT - echo "release=${release}" >> $GITHUB_OUTPUT - echo "stable=${{ needs.validate-inputs.outputs.stable_tag }}" >> $GITHUB_OUTPUT + echo "release=$(echo ${{ needs.validate-inputs.outputs.version }})" >> $GITHUB_OUTPUT + echo "stable=$(prepare_docker_stable_tag ${{ needs.validate-inputs.outputs.stable_tag }})" >> $GITHUB_OUTPUT - name: Build Injected Container image for polkadot rc if: ${{ env.BINARY == 'polkadot' }} @@ -342,19 +297,21 @@ jobs: - name: Fetch values id: fetch-data run: | + . ./.github/scripts/common/lib.sh date=$(date -u '+%Y-%m-%dT%H:%M:%SZ') echo "date=$date" >> $GITHUB_OUTPUT + echo "stable=$(prepare_docker_stable_tag ${{ needs.validate-inputs.outputs.stable_tag }})" >> $GITHUB_OUTPUT - name: Build and push id: docker_build - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@5e99dacf67635c4f273e532b9266ddb609b3025a # v6.9.0 with: push: true file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile # TODO: The owner should be used below but buildx does not resolve the VARs # TODO: It would be good to get rid of this GHA that we don't really need. tags: | - parity/polkadot:${{ needs.validate-inputs.outputs.stable_tag }} + parity/polkadot:${{ steps.fetch-data.outputs.stable }} parity/polkadot:latest parity/polkadot:${{ needs.fetch-latest-debian-package-version.outputs.polkadot_container_tag }} build-args: | diff --git a/.github/workflows/release-build-rc.yml b/.github/workflows/release-build-rc.yml deleted file mode 100644 index 5c25e3c749b8..000000000000 --- a/.github/workflows/release-build-rc.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Release - Build node release candidate - -on: - workflow_dispatch: - inputs: - binary: - description: Binary to be build for the release - default: all - type: choice - options: - - polkadot - - polkadot-parachain - - all - - release_tag: - description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM - type: string - -jobs: - check-synchronization: - uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main - - validate-inputs: - needs: [check-synchronization] - if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' - runs-on: ubuntu-latest - outputs: - release_tag: ${{ steps.validate_inputs.outputs.release_tag }} - - steps: - - name: Checkout sources - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - - - name: Validate inputs - id: validate_inputs - run: | - . ./.github/scripts/common/lib.sh - - RELEASE_TAG=$(validate_stable_tag ${{ inputs.release_tag }}) - echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT - - build-polkadot-binary: - needs: [validate-inputs] - if: ${{ inputs.binary == 'polkadot' || inputs.binary == 'all' }} - uses: "./.github/workflows/release-reusable-rc-buid.yml" - with: - binary: '["polkadot", "polkadot-prepare-worker", "polkadot-execute-worker"]' - package: polkadot - release_tag: ${{ needs.validate-inputs.outputs.release_tag }} - secrets: - PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} - PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} - - build-polkadot-parachain-binary: - needs: [validate-inputs] - if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'all' }} - uses: "./.github/workflows/release-reusable-rc-buid.yml" - with: - binary: '["polkadot-parachain"]' - package: "polkadot-parachain-bin" - release_tag: ${{ needs.validate-inputs.outputs.release_tag }} - secrets: - PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} - PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} - AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/release-reusable-promote-to-final.yml b/.github/workflows/release-reusable-promote-to-final.yml new file mode 100644 index 000000000000..ed4a80a01e82 --- /dev/null +++ b/.github/workflows/release-reusable-promote-to-final.yml @@ -0,0 +1,83 @@ +name: Promote rc to final + +on: + workflow_call: + inputs: + package: + description: Package to be promoted + required: true + type: string + + release_tag: + description: Tag matching the actual release candidate with the format polkadot-stableYYMM(-X)-rcX taht will be changed to final in form of polkadot-stableYYMM(-X) + required: true + type: string + + target: + description: Target triple for which the artifacts are being uploaded (e.g aarch64-apple-darwin) + required: true + type: string + + secrets: + AWS_DEFAULT_REGION: + required: true + AWS_RELEASE_ACCESS_KEY_ID: + required: true + AWS_RELEASE_SECRET_ACCESS_KEY: + required: true + +jobs: + + promote-release-artifacts: + environment: release + runs-on: ubuntu-latest + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + + steps: + - name: Checkout sources + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Prepare final tag + id: prepare_final_tag + shell: bash + run: | + tag="$(echo ${{ inputs.release_tag }} | sed 's/-rc[0-9]*$//')" + echo $tag + echo "FINAL_TAG=${tag}" >> $GITHUB_OUTPUT + + - name: Fetch binaries from s3 based on version + run: | + . ./.github/scripts/common/lib.sh + + VERSION="${{ inputs.release_tag }}" + if [[ ${{ inputs.package }} == 'polkadot' ]]; then + packages=(polkadot polkadot-prepare-worker polkadot-execute-worker) + for package in "${packages[@]}"; do + fetch_release_artifacts_from_s3 $package ${{ inputs.target }} + done + else + fetch_release_artifacts_from_s3 ${{ inputs.package }} ${{ inputs.target }} + fi + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Upload ${{ inputs.package }} ${{ inputs.target }} artifacts to s3 + run: | + . ./.github/scripts/release/release_lib.sh + + if [[ ${{ inputs.package }} == 'polkadot' ]]; then + packages=(polkadot polkadot-prepare-worker polkadot-execute-worker) + for package in "${packages[@]}"; do + upload_s3_release $package ${{ steps.prepare_final_tag.outputs.final_tag }} ${{ inputs.target }} + done + else + upload_s3_release ${{ inputs.package }} ${{ steps.prepare_final_tag.outputs.final_tag }} ${{ inputs.target }} + fi diff --git a/.github/workflows/release-reusable-rc-buid.yml b/.github/workflows/release-reusable-rc-buid.yml index ae6c430b6d37..0222b2aa91e2 100644 --- a/.github/workflows/release-reusable-rc-buid.yml +++ b/.github/workflows/release-reusable-rc-buid.yml @@ -10,7 +10,7 @@ on: type: string package: - description: Package to be built, for now is either polkadot or polkadot-parachain-bin + description: Package to be built, for now can be polkadot, polkadot-parachain-bin, or polkadot-omni-node required: true type: string @@ -19,6 +19,11 @@ on: required: true type: string + target: + description: Target triple for which the artifacts are being built (e.g. x86_64-unknown-linux-gnu) + required: true + type: string + secrets: PGP_KMS_KEY: required: true @@ -57,8 +62,9 @@ jobs: run: cat .github/env >> $GITHUB_OUTPUT build-rc: + if: ${{ inputs.target == 'x86_64-unknown-linux-gnu' }} needs: [set-image] - runs-on: ubuntu-latest + runs-on: ubuntu-latest-m environment: release container: image: ${{ needs.set-image.outputs.IMAGE }} @@ -98,7 +104,7 @@ jobs: ./.github/scripts/release/build-linux-release.sh ${{ matrix.binaries }} ${{ inputs.package }} - name: Generate artifact attestation - uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 with: subject-path: /artifacts/${{ matrix.binaries }}/${{ matrix.binaries }} @@ -127,11 +133,127 @@ jobs: - name: Upload ${{ matrix.binaries }} artifacts uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: - name: ${{ matrix.binaries }} + name: ${{ matrix.binaries }}_${{ inputs.target }} path: /artifacts/${{ matrix.binaries }} + build-macos-rc: + if: ${{ inputs.target == 'aarch64-apple-darwin' }} + runs-on: parity-macos + environment: release + strategy: + matrix: + binaries: ${{ fromJSON(inputs.binary) }} + env: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + SKIP_WASM_BUILD: 1 + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: ${{ inputs.release_tag }} + fetch-depth: 0 + + - name: Set rust version from env file + run: | + RUST_VERSION=$(cat .github/env | sed -E 's/.*ci-unified:([^-]+)-([^-]+).*/\2/') + echo $RUST_VERSION + echo "RUST_VERSION=${RUST_VERSION}" >> $GITHUB_ENV + - name: Set workspace environment variable + # relevant for artifacts upload, which can not interpolate Github Action variable syntax when + # used within valid paths. We can not use root-based paths either, since it is set as read-only + # on the `parity-macos` runner. + run: echo "ARTIFACTS_PATH=${GITHUB_WORKSPACE}/artifacts/${{ matrix.binaries }}" >> $GITHUB_ENV + + - name: Set up Homebrew + uses: Homebrew/actions/setup-homebrew@1ccc07ccd54b6048295516a3eb89b192c35057dc # master from 12.09.2024 + - name: Set homebrew binaries location on path + run: echo "/opt/homebrew/bin" >> $GITHUB_PATH + + - name: Install rust ${{ env.RUST_VERSION }} + uses: actions-rust-lang/setup-rust-toolchain@11df97af8e8102fd60b60a77dfbf58d40cd843b8 # v1.10.1 + with: + cache: false + toolchain: ${{ env.RUST_VERSION }} + target: wasm32-unknown-unknown + components: cargo, clippy, rust-docs, rust-src, rustfmt, rustc, rust-std + + - name: cargo info + run: | + echo "######## rustup show ########" + rustup show + echo "######## cargo --version ########" + cargo --version + + - name: Install protobuf + run: brew install protobuf + - name: Install gpg + run: | + brew install gnupg + # Setup for being able to resolve: keyserver.ubuntu.com. + # See: https://github.com/actions/runner-images/issues/9777 + mkdir -p ~/.gnupg/ + touch ~/.gnupg/dirmngr.conf + echo "standard-resolver" > ~/.gnupg/dirmngr.conf + - name: Install sha256sum + run: | + brew install coreutils + + - name: Install pgpkkms + run: | + # Install pgpkms that is used to sign built artifacts + python3 -m pip install "pgpkms @ git+https://github.com/paritytech-release/pgpkms.git@5a8f82fbb607ea102d8c178e761659de54c7af69" --break-system-packages + + - name: Import gpg keys + shell: bash + run: | + . ./.github/scripts/common/lib.sh + + import_gpg_keys + + - name: Build binary + run: | + git config --global --add safe.directory "${GITHUB_WORKSPACE}" #avoid "detected dubious ownership" error + ./.github/scripts/release/build-macos-release.sh ${{ matrix.binaries }} ${{ inputs.package }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 + with: + subject-path: ${{ env.ARTIFACTS_PATH }}/${{ matrix.binaries }} + + - name: Sign artifacts + working-directory: ${{ env.ARTIFACTS_PATH }} + run: | + python3 -m pgpkms sign --input ${{matrix.binaries }} -o ${{ matrix.binaries }}.asc + + - name: Check sha256 ${{ matrix.binaries }} + working-directory: ${{ env.ARTIFACTS_PATH }} + shell: bash + run: | + . "${GITHUB_WORKSPACE}"/.github/scripts/common/lib.sh + + echo "Checking binary ${{ matrix.binaries }}" + check_sha256 ${{ matrix.binaries }} + + - name: Check GPG ${{ matrix.binaries }} + working-directory: ${{ env.ARTIFACTS_PATH }} + shell: bash + run: | + . "${GITHUB_WORKSPACE}"/.github/scripts/common/lib.sh + + check_gpg ${{ matrix.binaries }} + + - name: Upload ${{ matrix.binaries }} artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: ${{ matrix.binaries }}_${{ inputs.target }} + path: ${{ env.ARTIFACTS_PATH }} + build-polkadot-deb-package: - if: ${{ inputs.package == 'polkadot' }} + if: ${{ inputs.package == 'polkadot' && inputs.target == 'x86_64-unknown-linux-gnu' }} needs: [build-rc] runs-on: ubuntu-latest @@ -151,40 +273,175 @@ jobs: - name: Build polkadot deb package shell: bash run: | - . "${GITHUB_WORKSPACE}"/.github/scripts/release/build-deb.sh ${{ inputs.package }} ${{ inputs.release_tag }} + . "${GITHUB_WORKSPACE}"/.github/scripts/common/lib.sh + VERSION=$(get_polkadot_node_version_from_code) + . "${GITHUB_WORKSPACE}"/.github/scripts/release/build-deb.sh ${{ inputs.package }} ${VERSION} - name: Generate artifact attestation - uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 with: subject-path: target/production/*.deb - name: Upload ${{inputs.package }} artifacts uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: - name: ${{ inputs.package }} + name: ${{ inputs.package }}_${{ inputs.target }} path: target/production overwrite: true upload-polkadot-artifacts-to-s3: - if: ${{ inputs.package == 'polkadot' }} + if: ${{ inputs.package == 'polkadot' && inputs.target == 'x86_64-unknown-linux-gnu' }} needs: [build-polkadot-deb-package] uses: ./.github/workflows/release-reusable-s3-upload.yml with: package: ${{ inputs.package }} release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} secrets: AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} - upload-polkadot-parachain-artifacts-to-s3: - if: ${{ inputs.package == 'polkadot-parachain-bin' }} + if: ${{ inputs.package == 'polkadot-parachain-bin' && inputs.target == 'x86_64-unknown-linux-gnu' }} + needs: [build-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: polkadot-parachain + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-polkadot-omni-node-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot-omni-node' && inputs.target == 'x86_64-unknown-linux-gnu' }} needs: [build-rc] uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-frame-omni-bencher-artifacts-to-s3: + if: ${{ inputs.package == 'frame-omni-bencher' && inputs.target == 'x86_64-unknown-linux-gnu' }} + needs: [build-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-chain-spec-builder-artifacts-to-s3: + if: ${{ inputs.package == 'staging-chain-spec-builder' && inputs.target == 'x86_64-unknown-linux-gnu' }} + needs: [build-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: chain-spec-builder + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-polkadot-macos-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot' && inputs.target == 'aarch64-apple-darwin' }} + # TODO: add and use a `build-polkadot-homebrew-package` which packs all `polkadot` binaries: + # `polkadot`, `polkadot-prepare-worker` and `polkadot-execute-worker`. + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-polkadot-prepare-worker-macos-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: polkadot-prepare-worker + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-polkadot-execute-worker-macos-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: polkadot-execute-worker + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-polkadot-omni-node-macos-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot-omni-node' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-polkadot-parachain-macos-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot-parachain-bin' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml with: package: polkadot-parachain release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-frame-omni-bencher-macos-artifacts-to-s3: + if: ${{ inputs.package == 'frame-omni-bencher' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + upload-chain-spec-builder-macos-artifacts-to-s3: + if: ${{ inputs.package == 'staging-chain-spec-builder' && inputs.target == 'aarch64-apple-darwin' }} + needs: [build-macos-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: chain-spec-builder + release_tag: ${{ inputs.release_tag }} + target: ${{ inputs.target }} secrets: AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} diff --git a/.github/workflows/release-reusable-s3-upload.yml b/.github/workflows/release-reusable-s3-upload.yml index 6776b78da8e6..48c7e53c6c8f 100644 --- a/.github/workflows/release-reusable-s3-upload.yml +++ b/.github/workflows/release-reusable-s3-upload.yml @@ -9,7 +9,12 @@ on: type: string release_tag: - description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM-rcX + description: Tag matching the actual release candidate with the format polkadot-stableYYMM(-X)-rcX or polkadot-stableYYMM-rcX + required: true + type: string + + target: + description: Target triple for which the artifacts are being uploaded (e.g aarch64-apple-darwin) required: true type: string @@ -34,11 +39,11 @@ jobs: - name: Checkout uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - - name: Download artifacts + - name: Download amd64 artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - name: ${{ inputs.package }} - path: artifacts/${{ inputs.package }} + name: ${{ inputs.package }}_${{ inputs.target }} + path: release-artifacts/${{ inputs.target }}/${{ inputs.package }} - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 @@ -50,4 +55,4 @@ jobs: - name: Upload ${{ inputs.package }} artifacts to s3 run: | . ./.github/scripts/release/release_lib.sh - upload_s3_release ${{ inputs.package }} ${{ inputs.release_tag }} + upload_s3_release ${{ inputs.package }} ${{ inputs.release_tag }} ${{ inputs.target }} diff --git a/.github/workflows/release-srtool.yml b/.github/workflows/release-srtool.yml index 9a29b46d2fc3..fc10496d481b 100644 --- a/.github/workflows/release-srtool.yml +++ b/.github/workflows/release-srtool.yml @@ -1,7 +1,7 @@ name: Srtool build env: - SUBWASM_VERSION: 0.20.0 + SUBWASM_VERSION: 0.21.0 TOML_CLI_VERSION: 0.2.4 on: @@ -11,14 +11,16 @@ on: type: string build_opts: type: string + profile: + type: string outputs: published_runtimes: value: ${{ jobs.find-runtimes.outputs.runtime }} - schedule: - - cron: "00 02 * * 1" # 2AM weekly on monday - - workflow_dispatch: +permissions: + id-token: write + attestations: write + contents: read jobs: find-runtimes: @@ -75,6 +77,7 @@ jobs: with: chain: ${{ matrix.chain }} runtime_dir: ${{ matrix.runtime_dir }} + profile: ${{ inputs.profile }} - name: Summary run: | @@ -83,6 +86,11 @@ jobs: echo "Compact Runtime: ${{ steps.srtool_build.outputs.wasm }}" echo "Compressed Runtime: ${{ steps.srtool_build.outputs.wasm_compressed }}" + - name: Generate artifact attestation + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + with: + subject-path: ${{ steps.srtool_build.outputs.wasm }} + # We now get extra information thanks to subwasm - name: Install subwasm run: | diff --git a/.github/workflows/runtimes-matrix.json b/.github/workflows/runtimes-matrix.json index f991db55b86d..104e73521331 100644 --- a/.github/workflows/runtimes-matrix.json +++ b/.github/workflows/runtimes-matrix.json @@ -8,6 +8,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic,pallet_nomination_pools,pallet_remark,pallet_transaction_storage", "uri": null, + "old_package": "staging-node-cli", + "old_bin": "substrate-node", "is_relay": false }, { @@ -19,6 +21,8 @@ "bench_flags": "", "bench_features": "runtime-benchmarks", "uri": "wss://try-runtime-westend.polkadot.io:443", + "old_package": "polkadot", + "old_bin": "polkadot", "is_relay": true }, { @@ -27,9 +31,11 @@ "path": "polkadot/runtime/rococo", "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", "bench_flags": "", + "uri": "wss://try-runtime-rococo.polkadot.io:443", + "old_package": "polkadot", + "old_bin": "polkadot", "is_relay": true }, { @@ -41,6 +47,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "", "uri": "wss://westend-asset-hub-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -52,6 +60,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "", "uri": "wss://rococo-asset-hub-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -63,6 +73,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "", "uri": "wss://rococo-bridge-hub-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -74,6 +86,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "", "uri": "wss://westend-bridge-hub-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -84,7 +98,10 @@ "template": "cumulus/templates/xcm-bench-template.hbs", "bench_features": "runtime-benchmarks", "bench_flags": "", - "uri": "wss://westend-collectives-rpc.polkadot.io:443" + "uri": "wss://westend-collectives-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", + "is_relay": false }, { "name": "contracts-rococo", @@ -95,6 +112,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm", "uri": "wss://rococo-contracts-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -106,6 +125,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", "uri": "wss://rococo-coretime-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -117,6 +138,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", "uri": "wss://westend-coretime-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -128,6 +151,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none", "uri": null, + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -139,6 +164,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", "uri": "wss://rococo-people-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false }, { @@ -150,6 +177,8 @@ "bench_features": "runtime-benchmarks", "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", "uri": "wss://westend-people-rpc.polkadot.io:443", + "old_package": "polkadot-parachain-bin", + "old_bin": "polkadot-parachain", "is_relay": false } ] diff --git a/.github/workflows/tests-linux-stable-coverage.yml b/.github/workflows/tests-linux-stable-coverage.yml index c5af6bcae77f..61e01cda4428 100644 --- a/.github/workflows/tests-linux-stable-coverage.yml +++ b/.github/workflows/tests-linux-stable-coverage.yml @@ -102,7 +102,7 @@ jobs: merge-multiple: true - run: ls -al reports/ - name: Upload to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} verbose: true diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml index 24b96219738a..3f8dc4fe1240 100644 --- a/.github/workflows/tests-linux-stable.yml +++ b/.github/workflows/tests-linux-stable.yml @@ -34,7 +34,14 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script + id: required run: WASM_BUILD_NO_COLOR=1 forklift cargo test -p staging-node-cli --release --locked -- --ignored + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} # https://github.com/paritytech/ci_cd/issues/864 test-linux-stable-runtime-benchmarks: @@ -53,7 +60,14 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script + id: required run: forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet --cargo-quiet + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} test-linux-stable: needs: [preflight] @@ -82,6 +96,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script + id: required run: | # Fixes "detected dubious ownership" error in the ci git config --global --add safe.directory '*' @@ -97,6 +112,12 @@ jobs: - name: runtime-api tests if: ${{ matrix.partition == '1/3' }} run: forklift cargo nextest run -p sp-api-test --features enable-staging-api --cargo-quiet + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} # some tests do not run with `try-runtime` feature enabled # https://github.com/paritytech/polkadot-sdk/pull/4251#discussion_r1624282143 @@ -123,6 +144,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script + id: required run: | forklift cargo nextest run --workspace \ --locked \ @@ -132,6 +154,12 @@ jobs: --features experimental,ci-only-tests \ --filter-expr " !test(/all_security_features_work/) - test(/nonexistent_cache_dir/)" \ --partition count:${{ matrix.partition }} \ + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' && !github.event.pull_request.head.repo.fork }} + uses: ./.github/actions/workflow-stopper + with: + app-id: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_ID }} + app-key: ${{ secrets.WORKFLOW_STOPPER_RUNNER_APP_KEY }} confirm-required-jobs-passed: runs-on: ubuntu-latest diff --git a/.github/workflows/tests-misc.yml b/.github/workflows/tests-misc.yml index cca32650b106..decd88f2e84c 100644 --- a/.github/workflows/tests-misc.yml +++ b/.github/workflows/tests-misc.yml @@ -165,12 +165,14 @@ jobs: - name: Download artifact (master run) uses: actions/download-artifact@v4.1.8 + continue-on-error: true with: name: cargo-check-benches-master-${{ github.sha }} path: ./artifacts/master - name: Download artifact (current run) uses: actions/download-artifact@v4.1.8 + continue-on-error: true with: name: cargo-check-benches-current-${{ github.sha }} path: ./artifacts/current @@ -183,6 +185,12 @@ jobs: exit 0 fi + # fail if no artifacts + if [ ! -d ./artifacts/master ] || [ ! -d ./artifacts/current ]; then + echo "No artifacts found" + exit 1 + fi + docker run --rm \ -v $PWD/artifacts/master:/artifacts/master \ -v $PWD/artifacts/current:/artifacts/current \ diff --git a/.gitignore b/.gitignore index afa9ed33f4a0..d48287657085 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,6 @@ artifacts bin/node-template/Cargo.lock nohup.out polkadot_argument_parsing -polkadot.* !docs/sdk/src/polkadot_sdk/polkadot.rs pwasm-alloc/Cargo.lock pwasm-libc/Cargo.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f508404f1efa..42a7e87bda43 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ workflow: variables: # CI_IMAGE: !reference [ .ci-unified, variables, CI_IMAGE ] - CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-09-11-v202409111034" + CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-11-19-v202411281558" # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" diff --git a/.gitlab/pipeline/zombienet/parachain-template.yml b/.gitlab/pipeline/zombienet/parachain-template.yml index 896ba7913be7..d5c1b6558b39 100644 --- a/.gitlab/pipeline/zombienet/parachain-template.yml +++ b/.gitlab/pipeline/zombienet/parachain-template.yml @@ -43,4 +43,4 @@ zombienet-parachain-template-smoke: - ls -ltr $(pwd)/artifacts - cargo test -p template-zombienet-tests --features zombienet --tests minimal_template_block_production_test - cargo test -p template-zombienet-tests --features zombienet --tests parachain_template_block_production_test - # - cargo test -p template-zombienet-tests --features zombienet --tests solochain_template_block_production_test + - cargo test -p template-zombienet-tests --features zombienet --tests solochain_template_block_production_test diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 9a907d8d9946..14a235bcda86 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -63,6 +63,8 @@ LOCAL_SDK_TEST: "/builds/parity/mirrors/polkadot-sdk/polkadot/zombienet-sdk-tests" FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 RUN_IN_CONTAINER: "1" + # don't retry sdk tests + NEXTEST_RETRIES: 0 artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: always @@ -179,7 +181,7 @@ zombienet-polkadot-elastic-scaling-0001-basic-3cores-6s-blocks: --local-dir="${LOCAL_DIR}/elastic_scaling" --test="0001-basic-3cores-6s-blocks.zndsl" -zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains: +.zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains: extends: - .zombienet-polkadot-common before_script: @@ -190,6 +192,7 @@ zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains: --local-dir="${LOCAL_DIR}/elastic_scaling" --test="0002-elastic-scaling-doesnt-break-parachains.zndsl" + .zombienet-polkadot-functional-0012-spam-statement-distribution-requests: extends: - .zombienet-polkadot-common @@ -225,7 +228,7 @@ 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: +.zombienet-polkadot-functional-0016-approval-voting-parallel: extends: - .zombienet-polkadot-common script: @@ -233,7 +236,7 @@ zombienet-polkadot-functional-0016-approval-voting-parallel: --local-dir="${LOCAL_DIR}/functional" --test="0016-approval-voting-parallel.zndsl" -zombienet-polkadot-functional-0017-sync-backing: +.zombienet-polkadot-functional-0017-sync-backing: extends: - .zombienet-polkadot-common script: @@ -252,6 +255,17 @@ zombienet-polkadot-functional-0018-shared-core-idle-parachain: --local-dir="${LOCAL_DIR}/functional" --test="0018-shared-core-idle-parachain.zndsl" +zombienet-polkadot-functional-0019-coretime-collation-fetching-fairness: + extends: + - .zombienet-polkadot-common + before_script: + - !reference [ .zombienet-polkadot-common, before_script ] + - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/functional + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0019-coretime-collation-fetching-fairness.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common @@ -386,3 +400,19 @@ zombienet-polkadot-malus-0001-dispute-valid: - unset NEXTEST_FAILURE_OUTPUT - unset NEXTEST_SUCCESS_OUTPUT - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- smoke::coretime_revenue::coretime_revenue_test + +zombienet-polkadot-elastic-scaling-slot-based-3cores: + extends: + - .zombienet-polkadot-common + needs: + - job: build-polkadot-zombienet-tests + artifacts: true + before_script: + - !reference [ ".zombienet-polkadot-common", "before_script" ] + - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}" + - export CUMULUS_IMAGE="docker.io/paritypr/test-parachain:${PIPELINE_IMAGE_TAG}" + script: + # we want to use `--no-capture` in zombienet tests. + - unset NEXTEST_FAILURE_OUTPUT + - unset NEXTEST_SUCCESS_OUTPUT + - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- elastic_scaling::slot_based_3cores::slot_based_3cores_test diff --git a/Cargo.lock b/Cargo.lock index 14ce58be7faa..6151ed33c5b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,48 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "alloy-core" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618bd382f0bc2ac26a7e4bfae01c9b015ca8f21b37ca40059ae35a7e62b3dc6" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives 0.8.15", + "alloy-rlp", + "alloy-sol-types 0.8.15", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41056bde53ae10ffbbf11618efbe1e0290859e5eab0fe9ef82ebdb62f12a866f" +dependencies = [ + "alloy-json-abi", + "alloy-primitives 0.8.15", + "alloy-sol-type-parser", + "alloy-sol-types 0.8.15", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.6.18", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c357da577dfb56998d01f574d81ad7a1958d248740a7981b205d69d65a7da404" +dependencies = [ + "alloy-primitives 0.8.15", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + [[package]] name = "alloy-primitives" version = "0.4.2" @@ -135,13 +177,41 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more", + "derive_more 0.99.17", + "hex-literal", + "itoa", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6259a506ab13e1d658796c31e6e39d2e2ee89243bcc505ddc613b35732e0a430" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 1.0.0", + "foldhash", + "hashbrown 0.15.2", "hex-literal", + "indexmap 2.7.0", "itoa", + "k256", + "keccak-asm", + "paste", "proptest", "rand", "ruint", + "rustc-hash 2.0.0", "serde", + "sha3 0.10.8", "tiny-keccak", ] @@ -168,19 +238,89 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", - "syn-solidity", + "syn 2.0.87", + "syn-solidity 0.4.2", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d64f851d95619233f74b310f12bcf16e0cbc27ee3762b6115c14a84809280a" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf7ed1574b699f48bf17caab4e6e54c6d12bc3c006ab33d58b1e227c1c3559f" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck 0.5.0", + "indexmap 2.7.0", + "proc-macro-error2", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", + "syn-solidity 0.8.15", "tiny-keccak", ] +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c02997ccef5f34f9c099277d4145f183b422938ed5322dc57a089fe9b9ad9ee" +dependencies = [ + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", + "syn-solidity 0.8.15", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce13ff37285b0870d0a0746992a4ae48efaf34b766ae4c2640fa15e5305f8e73" +dependencies = [ + "serde", + "winnow 0.6.18", +] + [[package]] name = "alloy-sol-types" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98d7107bed88e8f09f0ddcc3335622d87bfb6821f3e0c7473329fb1cfad5e015" dependencies = [ - "alloy-primitives", - "alloy-sol-macro", + "alloy-primitives 0.4.2", + "alloy-sol-macro 0.4.2", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-sol-types" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1174cafd6c6d810711b4e00383037bdb458efc4fe3dbafafa16567e0320c54d8" +dependencies = [ + "alloy-json-abi", + "alloy-primitives 0.8.15", + "alloy-sol-macro 0.8.15", "const-hex", "serde", ] @@ -295,7 +435,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -701,30 +841,14 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "asn1-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" -dependencies = [ - "asn1-rs-derive 0.4.0", - "asn1-rs-impl 0.1.0", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", -] - [[package]] name = "asn1-rs" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" dependencies = [ - "asn1-rs-derive 0.5.0", - "asn1-rs-impl 0.2.0", + "asn1-rs-derive", + "asn1-rs-impl", "displaydoc", "nom", "num-traits", @@ -733,18 +857,6 @@ dependencies = [ "time", ] -[[package]] -name = "asn1-rs-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", - "synstructure 0.12.6", -] - [[package]] name = "asn1-rs-derive" version = "0.5.0" @@ -753,21 +865,10 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", "synstructure 0.13.1", ] -[[package]] -name = "asn1-rs-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", -] - [[package]] name = "asn1-rs-impl" version = "0.2.0" @@ -776,7 +877,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -806,15 +907,15 @@ version = "0.0.0" dependencies = [ "asset-hub-rococo-runtime", "bp-bridge-hub-rococo", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "rococo-emulated-chain", "sp-core 28.0.0", - "sp-keyring", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] @@ -822,112 +923,113 @@ name = "asset-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ "assert_matches", - "asset-test-utils", - "cumulus-pallet-parachain-system", + "asset-test-utils 7.0.0", + "cumulus-pallet-parachain-system 0.7.0", "emulated-integration-tests-common", - "frame-support", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-treasury", - "pallet-utility", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "rococo-runtime-constants", + "frame-support 28.0.0", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-treasury 27.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-runtime-common 7.0.0", + "rococo-runtime-constants 7.0.0", "rococo-system-emulated-network", "sp-core 28.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", - "xcm-runtime-apis", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "asset-hub-rococo-runtime" version = "0.11.0" dependencies = [ - "asset-test-utils", - "assets-common", + "asset-test-utils 7.0.0", + "assets-common 0.7.0", "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-asset-conversion", - "pallet-asset-conversion-ops", - "pallet-asset-conversion-tx-payment", - "pallet-assets", - "pallet-assets-freezer", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-nft-fractionalization", - "pallet-nfts", - "pallet-nfts-runtime-api", - "pallet-proxy", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-uniques", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub-router", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "pallet-asset-conversion 10.0.0", + "pallet-asset-conversion-ops 0.1.0", + "pallet-asset-conversion-tx-payment 10.0.0", + "pallet-assets 29.1.0", + "pallet-assets-freezer 0.1.0", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-nft-fractionalization 10.0.0", + "pallet-nfts 22.0.0", + "pallet-nfts-runtime-api 14.0.0", + "pallet-proxy 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-uniques 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "pallet-xcm-bridge-hub-router 0.5.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "primitive-types 0.13.1", - "rococo-runtime-constants", + "rococo-runtime-constants 7.0.0", "scale-info", "serde_json", - "snowbridge-router-primitives", + "snowbridge-router-primitives 0.9.0", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-keyring", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", "sp-weights 27.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -936,14 +1038,14 @@ version = "0.0.0" dependencies = [ "asset-hub-westend-runtime", "bp-bridge-hub-westend", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "sp-core 28.0.0", - "sp-keyring", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", "westend-emulated-chain", ] @@ -952,168 +1054,227 @@ name = "asset-hub-westend-integration-tests" version = "1.0.0" dependencies = [ "assert_matches", - "asset-test-utils", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", + "asset-test-utils 7.0.0", + "assets-common 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", "emulated-integration-tests-common", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "pallet-asset-conversion", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-transaction-payment", - "pallet-treasury", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-asset-conversion 10.0.0", + "pallet-asset-tx-payment 28.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-treasury 27.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-runtime-common 7.0.0", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", "westend-system-emulated-network", - "xcm-runtime-apis", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "asset-hub-westend-runtime" version = "0.15.0" dependencies = [ - "asset-test-utils", - "assets-common", + "asset-test-utils 7.0.0", + "assets-common 0.7.0", "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-asset-conversion", - "pallet-asset-conversion-ops", - "pallet-asset-conversion-tx-payment", - "pallet-assets", - "pallet-assets-freezer", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-nft-fractionalization", - "pallet-nfts", - "pallet-nfts-runtime-api", - "pallet-proxy", - "pallet-revive", - "pallet-session", - "pallet-state-trie-migration", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-uniques", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub-router", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "pallet-asset-conversion 10.0.0", + "pallet-asset-conversion-ops 0.1.0", + "pallet-asset-conversion-tx-payment 10.0.0", + "pallet-assets 29.1.0", + "pallet-assets-freezer 0.1.0", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-nft-fractionalization 10.0.0", + "pallet-nfts 22.0.0", + "pallet-nfts-runtime-api 14.0.0", + "pallet-proxy 28.0.0", + "pallet-revive 0.1.0", + "pallet-session 28.0.0", + "pallet-state-trie-migration 29.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-uniques 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "pallet-xcm-bridge-hub-router 0.5.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "primitive-types 0.13.1", "scale-info", "serde_json", - "snowbridge-router-primitives", + "snowbridge-router-primitives 0.9.0", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-keyring", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-std 14.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "westend-runtime-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "asset-test-utils" version = "7.0.0" dependencies = [ - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "frame-support", - "frame-system", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex-literal", - "pallet-assets", - "pallet-balances", - "pallet-collator-selection", - "pallet-session", - "pallet-timestamp", - "pallet-xcm", - "pallet-xcm-bridge-hub-router", - "parachains-common", - "parachains-runtimes-test-utils", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-bridge-hub-router 0.5.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", "parity-scale-codec", "sp-io 30.0.0", "sp-runtime 31.0.1", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "xcm-runtime-apis 0.1.0", +] + +[[package]] +name = "asset-test-utils" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0324df9ce91a9840632e865dd3272bd20162023856f1b189b7ae58afa5c6b61" +dependencies = [ + "cumulus-pallet-parachain-system 0.17.1", + "cumulus-pallet-xcmp-queue 0.17.0", + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-assets 40.0.0", + "pallet-balances 39.0.0", + "pallet-collator-selection 19.0.0", + "pallet-session 38.0.0", + "pallet-timestamp 37.0.0", + "pallet-xcm 17.0.0", + "pallet-xcm-bridge-hub-router 0.15.1", + "parachains-common 18.0.0", + "parachains-runtimes-test-utils 17.0.0", + "parity-scale-codec", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-parachain-info 0.17.0", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", + "substrate-wasm-builder 24.0.1", ] [[package]] name = "assets-common" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", - "frame-support", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", "impl-trait-for-tuples", "log", - "pallet-asset-conversion", - "pallet-assets", - "pallet-xcm", - "parachains-common", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", "parity-scale-codec", "scale-info", "sp-api 26.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", +] + +[[package]] +name = "assets-common" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4556e56f9206b129c3f96249cd907b76e8d7ad5265fe368c228c708789a451a3" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-asset-conversion 20.0.0", + "pallet-assets 40.0.0", + "pallet-xcm 17.0.0", + "parachains-common 18.0.0", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", + "substrate-wasm-builder 24.0.1", ] [[package]] @@ -1144,7 +1305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" dependencies = [ "concurrent-queue", - "event-listener 5.2.0", + "event-listener 5.3.1", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -1235,7 +1396,7 @@ dependencies = [ "futures-lite 2.3.0", "parking", "polling 3.4.0", - "rustix 0.38.25", + "rustix 0.38.21", "slab", "tracing", "windows-sys 0.52.0", @@ -1256,7 +1417,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.2.0", + "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] @@ -1315,9 +1476,9 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.2.0", + "event-listener 5.3.1", "futures-lite 2.3.0", - "rustix 0.38.25", + "rustix 0.38.21", "tracing", ] @@ -1333,7 +1494,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.25", + "rustix 0.38.21", "signal-hook-registry", "slab", "windows-sys 0.52.0", @@ -1385,7 +1546,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -1396,13 +1557,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -1418,6 +1579,19 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "atomic-take" version = "1.1.0" @@ -1568,15 +1742,6 @@ dependencies = [ "serde", ] -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] - [[package]] name = "binary-merkle-tree" version = "13.0.0" @@ -1590,6 +1755,16 @@ dependencies = [ "sp-tracing 16.0.0", ] +[[package]] +name = "binary-merkle-tree" +version = "15.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336bf780dd7526a9a4bc1521720b25c1994dc132cccd59553431923fa4d1a693" +dependencies = [ + "hash-db", + "log", +] + [[package]] name = "bincode" version = "1.3.3" @@ -1617,7 +1792,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -1638,11 +1813,11 @@ dependencies = [ [[package]] name = "bip39" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ - "bitcoin_hashes 0.11.0", + "bitcoin_hashes 0.13.0", "serde", "unicode-normalization", ] @@ -1669,10 +1844,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" [[package]] -name = "bitcoin_hashes" -version = "0.11.0" +name = "bitcoin-io" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin_hashes" @@ -1681,7 +1856,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ "bitcoin-internals", - "hex-conservative", + "hex-conservative 0.1.1", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative 0.2.1", ] [[package]] @@ -1839,9 +2024,9 @@ dependencies = [ [[package]] name = "bounded-collections" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32385ecb91a31bddaf908e8dcf4a15aef1bcd3913cc03ebfad02ff6d568abc1" +checksum = "3d077619e9c237a5d1875166f5e8033e8f6bff0c96f8caf81e1c2d7738c431bf" dependencies = [ "log", "parity-scale-codec", @@ -1863,35 +2048,39 @@ dependencies = [ name = "bp-asset-hub-rococo" version = "0.4.0" dependencies = [ - "bp-xcm-bridge-hub-router", - "frame-support", + "bp-xcm-bridge-hub-router 0.6.0", + "frame-support 28.0.0", "parity-scale-codec", "scale-info", + "sp-core 28.0.0", + "staging-xcm 7.0.0", ] [[package]] name = "bp-asset-hub-westend" version = "0.3.0" dependencies = [ - "bp-xcm-bridge-hub-router", - "frame-support", + "bp-xcm-bridge-hub-router 0.6.0", + "frame-support 28.0.0", "parity-scale-codec", "scale-info", + "sp-core 28.0.0", + "staging-xcm 7.0.0", ] [[package]] name = "bp-beefy" version = "0.1.0" dependencies = [ - "binary-merkle-tree", - "bp-runtime", - "frame-support", - "pallet-beefy-mmr", - "pallet-mmr", + "binary-merkle-tree 13.0.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", + "pallet-beefy-mmr 28.0.0", + "pallet-mmr 27.0.0", "parity-scale-codec", "scale-info", "serde", - "sp-consensus-beefy", + "sp-consensus-beefy 13.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1900,12 +2089,12 @@ dependencies = [ name = "bp-bridge-hub-cumulus" version = "0.7.0" dependencies = [ - "bp-messages", - "bp-polkadot-core", - "bp-runtime", - "frame-support", - "frame-system", - "polkadot-primitives", + "bp-messages 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "polkadot-primitives 7.0.0", "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -1915,9 +2104,9 @@ name = "bp-bridge-hub-kusama" version = "0.6.0" dependencies = [ "bp-bridge-hub-cumulus", - "bp-messages", - "bp-runtime", - "frame-support", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "sp-api 26.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", @@ -1928,9 +2117,9 @@ name = "bp-bridge-hub-polkadot" version = "0.6.0" dependencies = [ "bp-bridge-hub-cumulus", - "bp-messages", - "bp-runtime", - "frame-support", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "sp-api 26.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", @@ -1941,10 +2130,10 @@ name = "bp-bridge-hub-rococo" version = "0.7.0" dependencies = [ "bp-bridge-hub-cumulus", - "bp-messages", - "bp-runtime", - "bp-xcm-bridge-hub", - "frame-support", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "frame-support 28.0.0", "parity-scale-codec", "sp-api 26.0.0", "sp-runtime 31.0.1", @@ -1956,10 +2145,10 @@ name = "bp-bridge-hub-westend" version = "0.3.0" dependencies = [ "bp-bridge-hub-cumulus", - "bp-messages", - "bp-runtime", - "bp-xcm-bridge-hub", - "frame-support", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "frame-support 28.0.0", "parity-scale-codec", "sp-api 26.0.0", "sp-runtime 31.0.1", @@ -1970,29 +2159,47 @@ dependencies = [ name = "bp-header-chain" version = "0.7.0" dependencies = [ - "bp-runtime", - "bp-test-utils", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", "finality-grandpa", - "frame-support", + "frame-support 28.0.0", "hex", "hex-literal", "parity-scale-codec", "scale-info", "serde", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", ] +[[package]] +name = "bp-header-chain" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "890df97cea17ee61ff982466bb9e90cb6b1462adb45380999019388d05e4b92d" +dependencies = [ + "bp-runtime 0.18.0", + "finality-grandpa", + "frame-support 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-grandpa 21.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bp-kusama" version = "0.5.0" dependencies = [ - "bp-header-chain", - "bp-polkadot-core", - "bp-runtime", - "frame-support", + "bp-header-chain 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -2001,9 +2208,9 @@ dependencies = [ name = "bp-messages" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-runtime", - "frame-support", + "bp-header-chain 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "hex", "hex-literal", "parity-scale-codec", @@ -2014,14 +2221,31 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "bp-messages" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7efabf94339950b914ba87249497f1a0e35a73849934d164fecae4b275928cf6" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-runtime 0.18.0", + "frame-support 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bp-parachains" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-polkadot-core", - "bp-runtime", - "frame-support", + "bp-header-chain 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", @@ -2030,28 +2254,60 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "bp-parachains" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9011e5c12c15caf3c4129a98f4f4916ea9165db8daf6ed85867c3106075f40df" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-polkadot-core 0.18.0", + "bp-runtime 0.18.0", + "frame-support 38.0.0", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bp-polkadot" version = "0.5.0" dependencies = [ - "bp-header-chain", - "bp-polkadot-core", - "bp-runtime", - "frame-support", + "bp-header-chain 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "sp-api 26.0.0", "sp-std 14.0.0", ] +[[package]] +name = "bp-polkadot" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa6277dd4333917ecfbcc35e9332a9f11682e0a506e76b617c336224660fce33" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-polkadot-core 0.18.0", + "bp-runtime 0.18.0", + "frame-support 38.0.0", + "sp-api 34.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bp-polkadot-bulletin" version = "0.4.0" dependencies = [ - "bp-header-chain", - "bp-messages", - "bp-polkadot-core", - "bp-runtime", - "frame-support", - "frame-system", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-api 26.0.0", @@ -2063,10 +2319,10 @@ dependencies = [ name = "bp-polkadot-core" version = "0.7.0" dependencies = [ - "bp-messages", - "bp-runtime", - "frame-support", - "frame-system", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex", "parity-scale-codec", "scale-info", @@ -2076,33 +2332,71 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "bp-polkadot-core" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345cf472bac11ef79d403e4846a666b7d22a13cd16d9c85b62cd6b5e16c4a042" +dependencies = [ + "bp-messages 0.18.0", + "bp-runtime 0.18.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "parity-util-mem", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bp-relayers" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-runtime", - "frame-support", - "frame-system", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex", "hex-literal", - "pallet-utility", + "pallet-utility 28.0.0", "parity-scale-codec", "scale-info", "sp-runtime 31.0.1", "sp-std 14.0.0", ] +[[package]] +name = "bp-relayers" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9465ad727e466d67d64244a1aa7bb19933a297913fdde34b8e9bda0a341bdeb" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-messages 0.18.0", + "bp-parachains 0.18.0", + "bp-runtime 0.18.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-utility 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bp-rococo" version = "0.6.0" dependencies = [ - "bp-header-chain", - "bp-polkadot-core", - "bp-runtime", - "frame-support", + "bp-header-chain 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -2111,8 +2405,8 @@ dependencies = [ name = "bp-runtime" version = "0.7.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "hash-db", "hex-literal", "impl-trait-for-tuples", @@ -2127,36 +2421,81 @@ dependencies = [ "sp-state-machine 0.35.0", "sp-std 14.0.0", "sp-trie 29.0.0", - "trie-db 0.29.1", + "trie-db", ] [[package]] -name = "bp-test-utils" -version = "0.7.0" +name = "bp-runtime" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "746d9464f912b278f8a5e2400f10541f95da7fc6c7d688a2788b9a46296146ee" dependencies = [ - "bp-header-chain", - "bp-parachains", - "bp-polkadot-core", - "bp-runtime", - "ed25519-dalek", - "finality-grandpa", - "parity-scale-codec", - "sp-application-crypto 30.0.0", - "sp-consensus-grandpa", + "frame-support 38.0.0", + "frame-system 38.0.0", + "hash-db", + "impl-trait-for-tuples", + "log", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-state-machine 0.43.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 37.0.0", + "trie-db", +] + +[[package]] +name = "bp-test-utils" +version = "0.7.0" +dependencies = [ + "bp-header-chain 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "ed25519-dalek", + "finality-grandpa", + "parity-scale-codec", + "sp-application-crypto 30.0.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-trie 29.0.0", ] +[[package]] +name = "bp-test-utils" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e659078b54c0b6bd79896738212a305842ad37168976363233516754337826" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-parachains 0.18.0", + "bp-polkadot-core 0.18.0", + "bp-runtime 0.18.0", + "ed25519-dalek", + "finality-grandpa", + "parity-scale-codec", + "sp-application-crypto 38.0.0", + "sp-consensus-grandpa 21.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 37.0.0", +] + [[package]] name = "bp-westend" version = "0.3.0" dependencies = [ - "bp-header-chain", - "bp-polkadot-core", - "bp-runtime", - "frame-support", + "bp-header-chain 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -2165,16 +2504,34 @@ dependencies = [ name = "bp-xcm-bridge-hub" version = "0.2.0" dependencies = [ - "bp-messages", - "bp-runtime", - "frame-support", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "frame-support 28.0.0", "parity-scale-codec", "scale-info", "serde", "sp-core 28.0.0", "sp-io 30.0.0", "sp-std 14.0.0", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "bp-xcm-bridge-hub" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6909117ca87cb93703742939d5f0c4c93e9646d9cda22262e9709d68c929999b" +dependencies = [ + "bp-messages 0.18.0", + "bp-runtime 0.18.0", + "frame-support 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", ] [[package]] @@ -2185,72 +2542,103 @@ dependencies = [ "scale-info", "sp-core 28.0.0", "sp-runtime 31.0.1", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "bp-xcm-bridge-hub-router" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9284820ca704f5c065563cad77d2e3d069a23cc9cb3a29db9c0de8dd3b173a87" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", ] [[package]] name = "bridge-hub-common" version = "0.1.0" dependencies = [ - "cumulus-primitives-core", - "frame-support", - "pallet-message-queue", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "pallet-message-queue 31.0.0", "parity-scale-codec", "scale-info", - "snowbridge-core", + "snowbridge-core 0.2.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "bridge-hub-common" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b53c53d627e2da38f8910807944bf3121e154b5c0ac9e122995af9dfb13ed" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "pallet-message-queue 41.0.1", + "parity-scale-codec", + "scale-info", + "snowbridge-core 0.10.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", ] [[package]] name = "bridge-hub-rococo-emulated-chain" version = "0.0.0" dependencies = [ - "bp-messages", - "bridge-hub-common", + "bp-messages 0.7.0", + "bridge-hub-common 0.1.0", "bridge-hub-rococo-runtime", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "sp-core 28.0.0", - "sp-keyring", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] name = "bridge-hub-rococo-integration-tests" version = "1.0.0" dependencies = [ - "cumulus-pallet-xcmp-queue", + "cumulus-pallet-xcmp-queue 0.7.0", "emulated-integration-tests-common", - "frame-support", + "frame-support 28.0.0", "hex-literal", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-message-queue", - "pallet-xcm", - "pallet-xcm-bridge-hub", - "parachains-common", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-bridge-messages 0.7.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "parachains-common 7.0.0", "parity-scale-codec", "rococo-system-emulated-network", "rococo-westend-system-emulated-network", "scale-info", - "snowbridge-core", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", + "snowbridge-core 0.2.0", + "snowbridge-pallet-inbound-queue-fixtures 0.10.0", + "snowbridge-pallet-outbound-queue 0.2.0", + "snowbridge-pallet-system 0.2.0", + "snowbridge-router-primitives 0.9.0", "sp-core 28.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -2262,154 +2650,200 @@ dependencies = [ "bp-bridge-hub-polkadot", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", - "bp-header-chain", - "bp-messages", - "bp-parachains", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", "bp-polkadot-bulletin", - "bp-polkadot-core", - "bp-relayers", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", "bp-rococo", - "bp-runtime", + "bp-runtime 0.7.0", "bp-westend", - "bridge-hub-common", - "bridge-hub-test-utils", - "bridge-runtime-common", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "bp-xcm-bridge-hub-router 0.6.0", + "bridge-hub-common 0.1.0", + "bridge-hub-test-utils 0.7.0", + "bridge-runtime-common 0.7.0", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-bridge-relayers", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "rococo-runtime-constants", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-bridge-relayers 0.7.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", + "rococo-runtime-constants 7.0.0", "scale-info", "serde", "serde_json", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-outbound-queue-runtime-api", - "snowbridge-pallet-ethereum-client", - "snowbridge-pallet-inbound-queue", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", - "snowbridge-runtime-common", - "snowbridge-runtime-test-common", - "snowbridge-system-runtime-api", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", + "snowbridge-outbound-queue-runtime-api 0.2.0", + "snowbridge-pallet-ethereum-client 0.2.0", + "snowbridge-pallet-inbound-queue 0.2.0", + "snowbridge-pallet-outbound-queue 0.2.0", + "snowbridge-pallet-system 0.2.0", + "snowbridge-router-primitives 0.9.0", + "snowbridge-runtime-common 0.2.0", + "snowbridge-runtime-test-common 0.2.0", + "snowbridge-system-runtime-api 0.2.0", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-std 14.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "bridge-hub-test-utils" version = "0.7.0" dependencies = [ - "asset-test-utils", - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", - "bp-test-utils", - "bp-xcm-bridge-hub", - "bridge-runtime-common", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "frame-support", - "frame-system", + "asset-test-utils 7.0.0", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "bridge-runtime-common 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-balances", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-bridge-relayers", - "pallet-timestamp", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-bridge-hub", - "parachains-common", - "parachains-runtimes-test-utils", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-bridge-relayers 0.7.0", + "pallet-timestamp 27.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", "parity-scale-codec", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "bridge-hub-test-utils" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0b3aa5fd8481a06ca16e47fd3d2d9c6abe76b27d922ec8980a853f242173b3" +dependencies = [ + "asset-test-utils 18.0.0", + "bp-header-chain 0.18.1", + "bp-messages 0.18.0", + "bp-parachains 0.18.0", + "bp-polkadot-core 0.18.0", + "bp-relayers 0.18.0", + "bp-runtime 0.18.0", + "bp-test-utils 0.18.0", + "bp-xcm-bridge-hub 0.4.0", + "bridge-runtime-common 0.18.0", + "cumulus-pallet-parachain-system 0.17.1", + "cumulus-pallet-xcmp-queue 0.17.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-balances 39.0.0", + "pallet-bridge-grandpa 0.18.0", + "pallet-bridge-messages 0.18.0", + "pallet-bridge-parachains 0.18.0", + "pallet-bridge-relayers 0.18.0", + "pallet-timestamp 37.0.0", + "pallet-utility 38.0.0", + "pallet-xcm 17.0.0", + "pallet-xcm-bridge-hub 0.13.0", + "parachains-common 18.0.0", + "parachains-runtimes-test-utils 17.0.0", + "parity-scale-codec", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-keyring 39.0.0", + "sp-runtime 39.0.2", + "sp-tracing 17.0.1", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", ] [[package]] name = "bridge-hub-westend-emulated-chain" version = "0.0.0" dependencies = [ - "bp-messages", - "bridge-hub-common", + "bp-messages 0.7.0", + "bridge-hub-common 0.1.0", "bridge-hub-westend-runtime", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "sp-core 28.0.0", - "sp-keyring", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] @@ -2418,34 +2852,34 @@ version = "1.0.0" dependencies = [ "asset-hub-westend-runtime", "bridge-hub-westend-runtime", - "cumulus-pallet-xcmp-queue", + "cumulus-pallet-xcmp-queue 0.7.0", "emulated-integration-tests-common", - "frame-support", + "frame-support 28.0.0", "hex-literal", "log", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-message-queue", - "pallet-xcm", - "pallet-xcm-bridge-hub", - "parachains-common", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-bridge-messages 0.7.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "parachains-common 7.0.0", "parity-scale-codec", "rococo-westend-system-emulated-network", "scale-info", - "snowbridge-core", - "snowbridge-pallet-inbound-queue", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", + "snowbridge-core 0.2.0", + "snowbridge-pallet-inbound-queue 0.2.0", + "snowbridge-pallet-inbound-queue-fixtures 0.10.0", + "snowbridge-pallet-outbound-queue 0.2.0", + "snowbridge-pallet-system 0.2.0", + "snowbridge-router-primitives 0.9.0", "sp-core 28.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -2456,119 +2890,121 @@ dependencies = [ "bp-asset-hub-westend", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot-core", - "bp-relayers", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", "bp-rococo", - "bp-runtime", + "bp-runtime 0.7.0", "bp-westend", - "bridge-hub-common", - "bridge-hub-test-utils", - "bridge-runtime-common", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "bp-xcm-bridge-hub-router 0.6.0", + "bridge-hub-common 0.1.0", + "bridge-hub-test-utils 0.7.0", + "bridge-runtime-common 0.7.0", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-bridge-relayers", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-bridge-relayers 0.7.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "scale-info", "serde", "serde_json", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-outbound-queue-runtime-api", - "snowbridge-pallet-ethereum-client", - "snowbridge-pallet-inbound-queue", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", - "snowbridge-runtime-common", - "snowbridge-runtime-test-common", - "snowbridge-system-runtime-api", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", + "snowbridge-outbound-queue-runtime-api 0.2.0", + "snowbridge-pallet-ethereum-client 0.2.0", + "snowbridge-pallet-inbound-queue 0.2.0", + "snowbridge-pallet-outbound-queue 0.2.0", + "snowbridge-pallet-system 0.2.0", + "snowbridge-router-primitives 0.9.0", + "snowbridge-runtime-common 0.2.0", + "snowbridge-runtime-test-common 0.2.0", + "snowbridge-system-runtime-api 0.2.0", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-std 14.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "westend-runtime-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "bridge-runtime-common" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", - "bp-test-utils", - "bp-xcm-bridge-hub", - "frame-support", - "frame-system", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-bridge-relayers", - "pallet-transaction-payment", - "pallet-utility", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-bridge-relayers 0.7.0", + "pallet-transaction-payment 28.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -2577,11 +3013,43 @@ dependencies = [ "sp-std 14.0.0", "sp-trie 29.0.0", "sp-weights 27.0.0", - "staging-xcm", + "staging-xcm 7.0.0", "static_assertions", "tuplex", ] +[[package]] +name = "bridge-runtime-common" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c639aa22de6e904156a3e8b0e6b9e6af790cb27a1299688cc07997e1ffe5b648" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-messages 0.18.0", + "bp-parachains 0.18.0", + "bp-polkadot-core 0.18.0", + "bp-relayers 0.18.0", + "bp-runtime 0.18.0", + "bp-xcm-bridge-hub 0.4.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-bridge-grandpa 0.18.0", + "pallet-bridge-messages 0.18.0", + "pallet-bridge-parachains 0.18.0", + "pallet-bridge-relayers 0.18.0", + "pallet-transaction-payment 38.0.0", + "pallet-utility 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 37.0.0", + "staging-xcm 14.2.0", + "tuplex", +] + [[package]] name = "bs58" version = "0.5.1" @@ -2647,6 +3115,9 @@ name = "bytes" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +dependencies = [ + "serde", +] [[package]] name = "bzip2-sys" @@ -2823,26 +3294,27 @@ dependencies = [ name = "chain-spec-guide-runtime" version = "0.0.0" dependencies = [ + "cmd_lib", "docify", - "frame-support", - "pallet-balances", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "parity-scale-codec", - "polkadot-sdk-frame", + "frame-support 28.0.0", + "pallet-balances 28.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "parity-scale-codec", + "polkadot-sdk-frame 0.1.0", "sc-chain-spec", "scale-info", "serde", "serde_json", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-keyring", + "sp-genesis-builder 0.8.0", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "staging-chain-spec-builder", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -3059,7 +3531,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -3100,7 +3572,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -3130,12 +3602,12 @@ name = "collectives-westend-emulated-chain" version = "0.0.0" dependencies = [ "collectives-westend-runtime", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "sp-core 28.0.0", - "testnet-parachains-constants", + "testnet-parachains-constants 1.0.0", ] [[package]] @@ -3143,26 +3615,26 @@ name = "collectives-westend-integration-tests" version = "1.0.0" dependencies = [ "assert_matches", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", "emulated-integration-tests-common", - "frame-support", - "pallet-asset-rate", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-treasury", - "pallet-utility", - "pallet-whitelist", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", - "testnet-parachains-constants", - "westend-runtime-constants", + "frame-support 28.0.0", + "pallet-asset-rate 7.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-treasury 27.0.0", + "pallet-utility 28.0.0", + "pallet-whitelist 27.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-runtime-common 7.0.0", + "sp-runtime 31.0.1", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "testnet-parachains-constants 1.0.0", + "westend-runtime-constants 7.0.0", "westend-system-emulated-network", ] @@ -3170,79 +3642,80 @@ dependencies = [ name = "collectives-westend-runtime" version = "3.0.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-alliance", - "pallet-asset-rate", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-collective", - "pallet-collective-content", - "pallet-core-fellowship", - "pallet-message-queue", - "pallet-multisig", - "pallet-preimage", - "pallet-proxy", - "pallet-ranked-collective", - "pallet-referenda", - "pallet-salary", - "pallet-scheduler", - "pallet-session", - "pallet-state-trie-migration", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-treasury", - "pallet-utility", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "pallet-alliance 27.0.0", + "pallet-asset-rate 7.0.0", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-collective 28.0.0", + "pallet-collective-content 0.6.0", + "pallet-core-fellowship 12.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-preimage 28.0.0", + "pallet-proxy 28.0.0", + "pallet-ranked-collective 28.0.0", + "pallet-referenda 28.0.0", + "pallet-salary 13.0.0", + "pallet-scheduler 29.0.0", + "pallet-session 28.0.0", + "pallet-state-trie-migration 29.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-treasury 27.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "scale-info", "serde_json", "sp-api 26.0.0", "sp-arithmetic 23.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-std 14.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "westend-runtime-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -3377,9 +3850,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -3409,9 +3882,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.10.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -3476,64 +3949,64 @@ checksum = "f272d0c4cf831b4fa80ee529c7707f76585986e910e1fbce1d7921970bc1a241" name = "contracts-rococo-runtime" version = "0.8.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-contracts", - "pallet-insecure-randomness-collective-flip", - "pallet-message-queue", - "pallet-multisig", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "rococo-runtime-constants", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-contracts 27.0.0", + "pallet-insecure-randomness-collective-flip 16.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-session 28.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", + "rococo-runtime-constants 7.0.0", "scale-info", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -3587,99 +4060,100 @@ name = "coretime-rococo-emulated-chain" version = "0.1.0" dependencies = [ "coretime-rococo-runtime", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "sp-core 28.0.0", - "testnet-parachains-constants", + "testnet-parachains-constants 1.0.0", ] [[package]] name = "coretime-rococo-integration-tests" version = "0.0.0" dependencies = [ - "cumulus-pallet-parachain-system", + "cumulus-pallet-parachain-system 0.7.0", "emulated-integration-tests-common", - "frame-support", - "pallet-balances", - "pallet-broker", - "pallet-identity", - "pallet-message-queue", - "polkadot-runtime-common", - "polkadot-runtime-parachains", - "rococo-runtime-constants", + "frame-support 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-identity 29.0.0", + "pallet-message-queue 31.0.0", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", + "rococo-runtime-constants 7.0.0", "rococo-system-emulated-network", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", ] [[package]] name = "coretime-rococo-runtime" version = "0.1.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-broker", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-proxy", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "rococo-runtime-constants", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-proxy 28.0.0", + "pallet-session 28.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", + "rococo-runtime-constants 7.0.0", "scale-info", "serde", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -3687,31 +4161,31 @@ name = "coretime-westend-emulated-chain" version = "0.1.0" dependencies = [ "coretime-westend-runtime", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "sp-core 28.0.0", - "testnet-parachains-constants", + "testnet-parachains-constants 1.0.0", ] [[package]] name = "coretime-westend-integration-tests" version = "0.0.0" dependencies = [ - "cumulus-pallet-parachain-system", + "cumulus-pallet-parachain-system 0.7.0", "emulated-integration-tests-common", - "frame-support", - "pallet-balances", - "pallet-broker", - "pallet-identity", - "pallet-message-queue", - "polkadot-runtime-common", - "polkadot-runtime-parachains", - "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", - "westend-runtime-constants", + "frame-support 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-identity 29.0.0", + "pallet-message-queue 31.0.0", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", + "sp-runtime 31.0.1", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "westend-runtime-constants 7.0.0", "westend-system-emulated-network", ] @@ -3719,66 +4193,67 @@ dependencies = [ name = "coretime-westend-runtime" version = "0.1.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-broker", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-multisig", - "pallet-proxy", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-multisig 28.0.0", + "pallet-proxy 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "scale-info", "serde", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "westend-runtime-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -3989,22 +4464,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -4055,6 +4526,21 @@ dependencies = [ "subtle 2.5.0", ] +[[package]] +name = "crypto_secretbox" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" +dependencies = [ + "aead", + "cipher 0.4.4", + "generic-array 0.14.7", + "poly1305", + "salsa20", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "ctr" version = "0.9.2" @@ -4087,9 +4573,9 @@ dependencies = [ "async-trait", "cumulus-client-consensus-common", "cumulus-client-network", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-test-client", - "cumulus-test-relay-sproof-builder", + "cumulus-test-relay-sproof-builder 0.7.0", "cumulus-test-runtime", "futures", "parity-scale-codec", @@ -4098,7 +4584,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-client-api", "sp-api 26.0.0", "sp-consensus", @@ -4119,8 +4605,8 @@ dependencies = [ "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-parachain-inherent", - "cumulus-primitives-aura", - "cumulus-primitives-core", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", "futures", "parity-scale-codec", @@ -4129,7 +4615,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-client-api", "sc-consensus", "sc-consensus-aura", @@ -4140,16 +4626,17 @@ dependencies = [ "schnellru", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "sp-timestamp", + "sp-timestamp 26.0.0", + "sp-trie 29.0.0", "substrate-prometheus-endpoint", "tokio", "tracing", @@ -4161,26 +4648,26 @@ version = "0.7.0" dependencies = [ "async-trait", "cumulus-client-pov-recovery", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", "cumulus-test-client", - "cumulus-test-relay-sproof-builder", + "cumulus-test-relay-sproof-builder 0.7.0", "dyn-clone", "futures", "futures-timer", "log", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-client-api", "sc-consensus", "sc-consensus-babe", "schnellru", "sp-blockchain", "sp-consensus", - "sp-consensus-slots", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", @@ -4194,9 +4681,9 @@ version = "0.7.0" dependencies = [ "anyhow", "async-trait", - "cumulus-primitives-parachain-inherent", + "cumulus-primitives-parachain-inherent 0.7.0", "sp-consensus", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "thiserror", @@ -4208,17 +4695,17 @@ version = "0.7.0" dependencies = [ "async-trait", "cumulus-client-consensus-common", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", "futures", "parking_lot 0.12.3", "sc-consensus", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "tracing", @@ -4229,7 +4716,7 @@ name = "cumulus-client-network" version = "0.7.0" dependencies = [ "async-trait", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-test-service", @@ -4239,8 +4726,8 @@ dependencies = [ "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-test-client", "portpicker", "rstest", @@ -4250,7 +4737,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", @@ -4266,15 +4753,15 @@ name = "cumulus-client-parachain-inherent" version = "0.1.0" dependencies = [ "async-trait", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-parachain-inherent 0.7.0", "cumulus-relay-chain-interface", - "cumulus-test-relay-sproof-builder", + "cumulus-test-relay-sproof-builder 0.7.0", "parity-scale-codec", "sc-client-api", "sp-api 26.0.0", "sp-crypto-hashing 0.1.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-storage 19.0.0", @@ -4288,7 +4775,7 @@ version = "0.7.0" dependencies = [ "assert_matches", "async-trait", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", "cumulus-test-client", "cumulus-test-service", @@ -4298,7 +4785,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "portpicker", "rand", "rstest", @@ -4327,13 +4814,14 @@ dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", "cumulus-client-pov-recovery", - "cumulus-primitives-core", - "cumulus-primitives-proof-size-hostfunction", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-proof-size-hostfunction 0.2.0", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "futures", - "polkadot-primitives", + "futures-timer", + "polkadot-primitives 7.0.0", "sc-client-api", "sc-consensus", "sc-network", @@ -4351,33 +4839,51 @@ dependencies = [ "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", ] [[package]] name = "cumulus-pallet-aura-ext" version = "0.7.0" dependencies = [ - "cumulus-pallet-parachain-system", - "frame-support", - "frame-system", - "pallet-aura", - "pallet-timestamp", + "cumulus-pallet-parachain-system 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-aura 27.0.0", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 30.0.0", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-runtime 31.0.1", ] +[[package]] +name = "cumulus-pallet-aura-ext" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cbe2735fc7cf2b6521eab00cb1a1ab025abc1575cc36887b36dc8c5cb1c9434" +dependencies = [ + "cumulus-pallet-parachain-system 0.17.1", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-aura 37.0.0", + "pallet-timestamp 37.0.0", + "parity-scale-codec", + "scale-info", + "sp-application-crypto 38.0.0", + "sp-consensus-aura 0.40.0", + "sp-runtime 39.0.2", +] + [[package]] name = "cumulus-pallet-dmp-queue" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", - "frame-benchmarking", - "frame-support", - "frame-system", + "cumulus-primitives-core 0.7.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -4385,7 +4891,25 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "cumulus-pallet-dmp-queue" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97263a8e758d201ebe81db7cea7b278b4fb869c11442f77acef70138ac1a252f" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", ] [[package]] @@ -4394,96 +4918,190 @@ version = "0.7.0" dependencies = [ "assert_matches", "bytes", - "cumulus-pallet-parachain-system-proc-macro", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-primitives-proof-size-hostfunction", + "cumulus-pallet-parachain-system-proc-macro 0.6.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-parachain-inherent 0.7.0", + "cumulus-primitives-proof-size-hostfunction 0.2.0", "cumulus-test-client", - "cumulus-test-relay-sproof-builder", + "cumulus-test-relay-sproof-builder 0.7.0", "cumulus-test-runtime", "environmental", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "futures", "hex-literal", "impl-trait-for-tuples", "log", - "pallet-message-queue", + "pallet-message-queue 31.0.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "polkadot-runtime-parachains", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-parachains 7.0.0", "rand", "sc-client-api", "scale-info", - "sp-consensus-slots", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", - "staging-xcm", - "staging-xcm-builder", - "trie-db 0.29.1", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "trie-db", "trie-standardmap", ] +[[package]] +name = "cumulus-pallet-parachain-system" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546403ee1185f4051a74cc9c9d76e82c63cac3fb68e1bf29f61efb5604c96488" +dependencies = [ + "bytes", + "cumulus-pallet-parachain-system-proc-macro 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cumulus-primitives-core 0.16.0", + "cumulus-primitives-parachain-inherent 0.16.0", + "cumulus-primitives-proof-size-hostfunction 0.10.0", + "environmental", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-message-queue 41.0.1", + "parity-scale-codec", + "polkadot-parachain-primitives 14.0.0", + "polkadot-runtime-common 17.0.0", + "polkadot-runtime-parachains 17.0.1", + "scale-info", + "sp-core 34.0.0", + "sp-externalities 0.29.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-state-machine 0.43.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 37.0.0", + "sp-version 37.0.0", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "trie-db", +] + +[[package]] +name = "cumulus-pallet-parachain-system-proc-macro" +version = "0.6.0" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "befbaf3a1ce23ac8476481484fef5f4d500cbd15b4dad6380ce1d28134b0c1f7" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] name = "cumulus-pallet-session-benchmarking" version = "9.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-session", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-session 28.0.0", "parity-scale-codec", "sp-runtime 31.0.1", ] +[[package]] +name = "cumulus-pallet-session-benchmarking" +version = "19.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18168570689417abfb514ac8812fca7e6429764d01942750e395d7d8ce0716ef" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "sp-runtime 39.0.2", +] + [[package]] name = "cumulus-pallet-solo-to-para" version = "0.7.0" dependencies = [ - "cumulus-pallet-parachain-system", - "frame-support", - "frame-system", - "pallet-sudo", + "cumulus-pallet-parachain-system 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-sudo 28.0.0", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "scale-info", "sp-runtime 31.0.1", ] +[[package]] +name = "cumulus-pallet-solo-to-para" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42c74548c8cab75da6f2479a953f044b582cfce98479862344a24df7bbd215" +dependencies = [ + "cumulus-pallet-parachain-system 0.17.1", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-sudo 38.0.0", + "parity-scale-codec", + "polkadot-primitives 16.0.0", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "cumulus-pallet-xcm" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", - "frame-support", - "frame-system", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-io 30.0.0", "sp-runtime 31.0.1", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "cumulus-pallet-xcm" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e49231f6cd8274438b078305dc8ce44c54c0d3f4a28e902589bcbaa53d954608" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", ] [[package]] @@ -4491,39 +5109,81 @@ name = "cumulus-pallet-xcmp-queue" version = "0.7.0" dependencies = [ "bounded-collections", - "bp-xcm-bridge-hub-router", - "cumulus-pallet-parachain-system", - "cumulus-primitives-core", - "frame-benchmarking", - "frame-support", - "frame-system", + "bp-xcm-bridge-hub-router 0.6.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-primitives-core 0.7.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-message-queue", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", "parity-scale-codec", - "polkadot-runtime-common", - "polkadot-runtime-parachains", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "cumulus-pallet-xcmp-queue" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f788bdac9474795ea13ba791b55798fb664b2e3da8c3a7385b480c9af4e6539" +dependencies = [ + "bounded-collections", + "bp-xcm-bridge-hub-router 0.14.1", + "cumulus-primitives-core 0.16.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-message-queue 41.0.1", + "parity-scale-codec", + "polkadot-runtime-common 17.0.0", + "polkadot-runtime-parachains 17.0.1", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", ] [[package]] name = "cumulus-ping" version = "0.7.0" dependencies = [ - "cumulus-pallet-xcm", - "cumulus-primitives-core", - "frame-support", - "frame-system", + "cumulus-pallet-xcm 0.7.0", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-runtime 31.0.1", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "cumulus-ping" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47128f797359951723e2d106a80e592d007bb7446c299958cdbafb1489ddbf0" +dependencies = [ + "cumulus-pallet-xcm 0.17.0", + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", ] [[package]] @@ -4534,8 +5194,8 @@ dependencies = [ "clap 4.5.13", "parity-scale-codec", "polkadot-node-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "sc-executor 0.32.0", "sp-core 28.0.0", "sp-io 30.0.0", @@ -4549,7 +5209,21 @@ name = "cumulus-primitives-aura" version = "0.7.0" dependencies = [ "sp-api 26.0.0", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", +] + +[[package]] +name = "cumulus-primitives-aura" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11e7825bcf3cc6c962a5b9b9f47e02dc381109e521d0bc00cad785c65da18471" +dependencies = [ + "parity-scale-codec", + "polkadot-core-primitives 15.0.0", + "polkadot-primitives 15.0.0", + "sp-api 34.0.0", + "sp-consensus-aura 0.40.0", + "sp-runtime 39.0.2", ] [[package]] @@ -4557,14 +5231,31 @@ name = "cumulus-primitives-core" version = "0.7.0" dependencies = [ "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-core-primitives 7.0.0", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "scale-info", "sp-api 26.0.0", "sp-runtime 31.0.1", "sp-trie 29.0.0", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "cumulus-primitives-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6b5221a4a3097f2ebef66c84c1e6d7a0b8ec7e63f2bd5ae04c1e6d3fc7514e" +dependencies = [ + "parity-scale-codec", + "polkadot-core-primitives 15.0.0", + "polkadot-parachain-primitives 14.0.0", + "polkadot-primitives 16.0.0", + "scale-info", + "sp-api 34.0.0", + "sp-runtime 39.0.2", + "sp-trie 37.0.0", + "staging-xcm 14.2.0", ] [[package]] @@ -4572,14 +5263,29 @@ name = "cumulus-primitives-parachain-inherent" version = "0.7.0" dependencies = [ "async-trait", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-trie 29.0.0", ] +[[package]] +name = "cumulus-primitives-parachain-inherent" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "842a694901e04a62d88995418dec35c22f7dba2b34d32d2b8de37d6b92f973ff" +dependencies = [ + "async-trait", + "cumulus-primitives-core 0.16.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-trie 37.0.0", +] + [[package]] name = "cumulus-primitives-proof-size-hostfunction" version = "0.2.0" @@ -4592,17 +5298,28 @@ dependencies = [ "sp-trie 29.0.0", ] +[[package]] +name = "cumulus-primitives-proof-size-hostfunction" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421f03af054aac7c89e87a49e47964886e53a8d7395990eab27b6f201d42524f" +dependencies = [ + "sp-externalities 0.29.0", + "sp-runtime-interface 28.0.0", + "sp-trie 37.0.0", +] + [[package]] name = "cumulus-primitives-storage-weight-reclaim" version = "1.0.0" dependencies = [ - "cumulus-primitives-core", - "cumulus-primitives-proof-size-hostfunction", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-proof-size-hostfunction 0.2.0", "cumulus-test-runtime", "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -4611,43 +5328,89 @@ dependencies = [ "sp-trie 29.0.0", ] +[[package]] +name = "cumulus-primitives-storage-weight-reclaim" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fc49dfec0ba3438afad73787736cc0dba88d15b5855881f12a4d8b812a72927" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "cumulus-primitives-proof-size-hostfunction 0.10.0", + "docify", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "cumulus-primitives-timestamp" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", - "sp-inherents", - "sp-timestamp", + "cumulus-primitives-core 0.7.0", + "sp-inherents 26.0.0", + "sp-timestamp 26.0.0", +] + +[[package]] +name = "cumulus-primitives-timestamp" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cffb8f010f39ac36b31d38994b8f9d9256d9b5e495d96b4ec59d3e30852d53" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "sp-inherents 34.0.0", + "sp-timestamp 34.0.0", ] [[package]] name = "cumulus-primitives-utility" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", - "frame-support", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", "log", - "pallet-asset-conversion", + "pallet-asset-conversion 10.0.0", "parity-scale-codec", - "polkadot-runtime-common", + "polkadot-runtime-common 7.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", ] [[package]] -name = "cumulus-relay-chain-inprocess-interface" -version = "0.7.0" +name = "cumulus-primitives-utility" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bdcf4d46dd93f1e6d5dd6d379133566a44042ba6476d04bdcbdb4981c622ae4" dependencies = [ - "async-trait", - "cumulus-primitives-core", - "cumulus-relay-chain-interface", - "cumulus-test-service", + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "log", + "pallet-asset-conversion 20.0.0", + "parity-scale-codec", + "polkadot-runtime-common 17.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", +] + +[[package]] +name = "cumulus-relay-chain-inprocess-interface" +version = "0.7.0" +dependencies = [ + "async-trait", + "cumulus-primitives-core 0.7.0", + "cumulus-relay-chain-interface", + "cumulus-test-service", "futures", "futures-timer", "polkadot-cli", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-service", "polkadot-test-client", "prioritized-metered-channel", @@ -4659,7 +5422,7 @@ dependencies = [ "sp-api 26.0.0", "sp-consensus", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", ] @@ -4669,9 +5432,9 @@ name = "cumulus-relay-chain-interface" version = "0.7.0" dependencies = [ "async-trait", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "futures", - "jsonrpsee-core 0.24.3", + "jsonrpsee-core", "parity-scale-codec", "polkadot-overseer", "sc-client-api", @@ -4688,16 +5451,16 @@ version = "0.7.0" dependencies = [ "array-bytes", "async-trait", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", - "polkadot-core-primitives", + "polkadot-core-primitives 7.0.0", "polkadot-network-bridge", "polkadot-node-network-protocol", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-service", "sc-authority-discovery", "sc-client-api", @@ -4709,7 +5472,7 @@ dependencies = [ "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "tokio", @@ -4721,12 +5484,12 @@ name = "cumulus-relay-chain-rpc-interface" version = "0.7.0" dependencies = [ "async-trait", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", "either", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "parity-scale-codec", "pin-project", "polkadot-overseer", @@ -4742,8 +5505,8 @@ dependencies = [ "smoldot 0.11.0", "smoldot-light 0.9.0", "sp-api 26.0.0", - "sp-authority-discovery", - "sp-consensus-babe", + "sp-authority-discovery 26.0.0", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", @@ -4761,19 +5524,19 @@ dependencies = [ name = "cumulus-test-client" version = "0.1.0" dependencies = [ - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-primitives-proof-size-hostfunction", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-test-relay-sproof-builder", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-parachain-inherent 0.7.0", + "cumulus-primitives-proof-size-hostfunction 0.2.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-test-relay-sproof-builder 0.7.0", "cumulus-test-runtime", "cumulus-test-service", - "frame-system", - "pallet-balances", - "pallet-transaction-payment", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "sc-block-builder", "sc-consensus", "sc-consensus-aura", @@ -4783,14 +5546,14 @@ dependencies = [ "sp-api 26.0.0", "sp-application-crypto 30.0.0", "sp-blockchain", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "substrate-test-client", ] @@ -4798,55 +5561,69 @@ dependencies = [ name = "cumulus-test-relay-sproof-builder" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-trie 29.0.0", ] +[[package]] +name = "cumulus-test-relay-sproof-builder" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e570e41c3f05a8143ebff967bbb0c7dcaaa6f0bebd8639b9418b8005b13eda03" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "parity-scale-codec", + "polkadot-primitives 16.0.0", + "sp-runtime 39.0.2", + "sp-state-machine 0.43.0", + "sp-trie 37.0.0", +] + [[package]] name = "cumulus-test-runtime" version = "0.1.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-glutton", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-glutton 14.0.0", + "pallet-message-queue 31.0.0", + "pallet-session 28.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", "scale-info", "serde_json", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-transaction-pool", + "sp-session 27.0.0", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "substrate-wasm-builder", + "staging-parachain-info 0.7.0", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -4865,27 +5642,27 @@ dependencies = [ "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", - "cumulus-pallet-parachain-system", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-test-client", - "cumulus-test-relay-sproof-builder", + "cumulus-test-relay-sproof-builder 0.7.0", "cumulus-test-runtime", - "frame-system", - "frame-system-rpc-runtime-api", + "frame-system 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", "futures", - "jsonrpsee 0.24.3", - "pallet-timestamp", - "pallet-transaction-payment", - "parachains-common", + "jsonrpsee", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "parachains-common 7.0.0", "parity-scale-codec", "polkadot-cli", "polkadot-node-subsystem", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-service", "polkadot-test-service", "portpicker", @@ -4911,17 +5688,17 @@ dependencies = [ "serde_json", "sp-api 26.0.0", "sp-arithmetic 23.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", + "sp-genesis-builder 0.8.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "substrate-test-client", "substrate-test-utils", @@ -4999,7 +5776,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5039,7 +5816,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scratch", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5056,17 +5833,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", -] - -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core 0.14.4", - "darling_macro 0.14.4", + "syn 2.0.87", ] [[package]] @@ -5075,22 +5842,8 @@ version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2 1.0.86", - "quote 1.0.37", - "strsim 0.10.0", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] @@ -5104,18 +5857,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.82", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core 0.14.4", - "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -5124,9 +5866,9 @@ version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.10", + "darling_core", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5144,9 +5886,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "data-encoding-macro" @@ -5187,27 +5929,13 @@ dependencies = [ "zeroize", ] -[[package]] -name = "der-parser" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" -dependencies = [ - "asn1-rs 0.5.2", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - [[package]] name = "der-parser" version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs", "displaydoc", "nom", "num-bigint", @@ -5243,7 +5971,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5254,7 +5982,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5265,7 +5993,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5281,6 +6009,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", + "unicode-xid 0.2.4", +] + [[package]] name = "diff" version = "0.1.13" @@ -5342,6 +6091,15 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-sys" version = "0.4.1" @@ -5373,7 +6131,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5434,7 +6192,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "regex", - "syn 2.0.82", + "syn 2.0.87", "termcolor", "toml 0.8.12", "walkdir", @@ -5599,34 +6357,34 @@ dependencies = [ name = "emulated-integration-tests-common" version = "3.0.0" dependencies = [ - "asset-test-utils", - "bp-messages", - "bp-xcm-bridge-hub", - "bridge-runtime-common", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "frame-support", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-message-queue", - "pallet-xcm", - "pallet-xcm-bridge-hub", - "parachains-common", + "asset-test-utils 7.0.0", + "bp-messages 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "bridge-runtime-common 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-bridge-messages 0.7.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "parachains-common 7.0.0", "parity-scale-codec", "paste", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", "sc-consensus-grandpa", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", + "sp-authority-discovery 26.0.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", - "staging-xcm", + "staging-xcm 7.0.0", "xcm-emulator", ] @@ -5645,18 +6403,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" -dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", -] - [[package]] name = "enum-as-inner" version = "0.6.0" @@ -5666,7 +6412,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5686,7 +6432,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5697,7 +6443,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5764,9 +6510,9 @@ version = "0.1.0" dependencies = [ "async-std", "async-trait", - "bp-header-chain", + "bp-header-chain 0.7.0", "finality-relay", - "frame-support", + "frame-support 28.0.0", "futures", "log", "num-traits", @@ -5789,7 +6535,7 @@ dependencies = [ "honggfuzz", "polkadot-erasure-coding", "polkadot-node-primitives", - "polkadot-primitives", + "polkadot-primitives 7.0.0", ] [[package]] @@ -5813,13 +6559,55 @@ dependencies = [ "libc", ] +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types 0.14.1", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint 0.9.5", +] + [[package]] name = "ethabi-decode" -version = "1.1.0" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d398648d65820a727d6a81e58b962f874473396a047e4c30bafe3240953417" +dependencies = [ + "ethereum-types 0.14.1", + "tiny-keccak", +] + +[[package]] +name = "ethabi-decode" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52029c4087f9f01108f851d0d02df9c21feb5660a19713466724b7f95bd2d773" +dependencies = [ + "ethereum-types 0.15.1", + "tiny-keccak", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9af52ec57c5147716872863c2567c886e7d62f539465b94352dbc0108fe5293" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ - "ethereum-types", + "crunchy", + "fixed-hash", + "impl-codec 0.6.0", + "impl-rlp 0.3.0", + "impl-serde 0.4.0", + "scale-info", "tiny-keccak", ] @@ -5832,22 +6620,38 @@ dependencies = [ "crunchy", "fixed-hash", "impl-codec 0.7.0", - "impl-rlp", + "impl-rlp 0.4.0", "impl-serde 0.5.0", "scale-info", "tiny-keccak", ] +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom 0.13.0", + "fixed-hash", + "impl-codec 0.6.0", + "impl-rlp 0.3.0", + "impl-serde 0.4.0", + "primitive-types 0.12.2", + "scale-info", + "uint 0.9.5", +] + [[package]] name = "ethereum-types" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab15ed80916029f878e0267c3a9f92b67df55e79af370bf66199059ae2b4ee3" dependencies = [ - "ethbloom", + "ethbloom 0.14.1", "fixed-hash", "impl-codec 0.7.0", - "impl-rlp", + "impl-rlp 0.4.0", "impl-serde 0.5.0", "primitive-types 0.13.1", "scale-info", @@ -5862,19 +6666,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.2.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -5887,7 +6681,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.2.0", + "event-listener 5.3.1", "pin-project-lite", ] @@ -5912,7 +6706,7 @@ dependencies = [ "prettyplease", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -5991,11 +6785,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ "expander", - "indexmap 2.2.3", + "indexmap 2.7.0", "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -6109,7 +6903,7 @@ dependencies = [ "async-std", "async-trait", "backoff", - "bp-header-chain", + "bp-header-chain 0.7.0", "futures", "log", "num-traits", @@ -6182,6 +6976,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -6244,27 +7044,55 @@ name = "frame-benchmarking" version = "28.0.0" dependencies = [ "array-bytes", - "frame-support", - "frame-support-procedural", - "frame-system", + "frame-support 28.0.0", + "frame-support-procedural 23.0.0", + "frame-system 28.0.0", "linregress", "log", "parity-scale-codec", "paste", "rusty-fork", + "sc-client-db", "scale-info", "serde", "sp-api 26.0.0", "sp-application-crypto 30.0.0", "sp-core 28.0.0", + "sp-externalities 0.25.0", "sp-io 30.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", + "sp-state-machine 0.35.0", "sp-storage 19.0.0", "static_assertions", ] +[[package]] +name = "frame-benchmarking" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01bdd47c2d541b38bd892da647d1e972c9d85b4ecd7094ad64f7600175da54d" +dependencies = [ + "frame-support 38.0.0", + "frame-support-procedural 30.0.4", + "frame-system 38.0.0", + "linregress", + "log", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-runtime-interface 28.0.0", + "sp-storage 21.0.0", + "static_assertions", +] + [[package]] name = "frame-benchmarking-cli" version = "32.0.0" @@ -6275,11 +7103,11 @@ dependencies = [ "clap 4.5.13", "comfy-table", "cumulus-client-parachain-inherent", - "cumulus-primitives-proof-size-hostfunction", + "cumulus-primitives-proof-size-hostfunction 0.2.0", "cumulus-test-runtime", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "gethostname", "handlebars", "hex", @@ -6287,8 +7115,8 @@ dependencies = [ "linked-hash-map", "log", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "rand", "rand_pcg", "sc-block-builder", @@ -6298,26 +7126,27 @@ dependencies = [ "sc-client-db", "sc-executor 0.32.0", "sc-executor-common 0.29.0", + "sc-runtime-utilities", "sc-service", "sc-sysinfo", "serde", "serde_json", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", "sp-database", "sp-externalities 0.25.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-storage 19.0.0", - "sp-timestamp", - "sp-transaction-pool", + "sp-timestamp 26.0.0", + "sp-transaction-pool 26.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", "sp-wasm-interface 20.0.0", @@ -6333,62 +7162,120 @@ dependencies = [ name = "frame-benchmarking-pallet-pov" version = "18.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-io 30.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "frame-benchmarking-pallet-pov" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ffde6f573a63eeb1ccb7d2667c5741a11ce93bc30f33712e5326b9d8a811c29" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + +[[package]] +name = "frame-decode" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d3379df61ff3dd871e2dde7d1bcdc0263e613c21c7579b149fd4f0ad9b1dc2" +dependencies = [ + "frame-metadata 17.0.0", + "parity-scale-codec", + "scale-decode 0.14.0", + "scale-info", + "scale-type-resolver", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "frame-election-provider-solution-type" version = "13.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", "parity-scale-codec", "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", "scale-info", "sp-arithmetic 23.0.0", - "syn 2.0.82", + "syn 2.0.87", "trybuild", ] +[[package]] +name = "frame-election-provider-solution-type" +version = "14.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8156f209055d352994ecd49e19658c6b469d7c6de923bd79868957d0dcfb6f71" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "frame-election-provider-support" version = "28.0.0" dependencies = [ - "frame-election-provider-solution-type", - "frame-support", - "frame-system", + "frame-election-provider-solution-type 13.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "rand", "scale-info", "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "frame-election-provider-support" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36f5116192c63d39f1b4556fa30ac7db5a6a52575fa241b045f7dfa82ecc2be" +dependencies = [ + "frame-election-provider-solution-type 14.0.1", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-npos-elections 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ "clap 4.5.13", - "frame-election-provider-solution-type", - "frame-election-provider-support", - "frame-support", + "frame-election-provider-solution-type 13.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", "honggfuzz", "parity-scale-codec", "rand", "scale-info", "sp-arithmetic 23.0.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", ] @@ -6398,16 +7285,16 @@ version = "28.0.0" dependencies = [ "aquamarine", "array-bytes", - "frame-support", - "frame-system", - "frame-try-runtime", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-try-runtime 0.34.0", "log", - "pallet-balances", - "pallet-transaction-payment", + "pallet-balances 28.0.0", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", @@ -6415,14 +7302,22 @@ dependencies = [ ] [[package]] -name = "frame-metadata" -version = "15.1.0" +name = "frame-executive" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +checksum = "c365bf3879de25bbee28e9584096955a02fbe8d7e7624e10675800317f1cee5b" dependencies = [ - "cfg-if", + "aquamarine", + "frame-support 38.0.0", + "frame-system 38.0.0", + "frame-try-runtime 0.44.0", + "log", "parity-scale-codec", "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-tracing 17.0.1", ] [[package]] @@ -6437,6 +7332,30 @@ dependencies = [ "serde", ] +[[package]] +name = "frame-metadata" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "701bac17e9b55e0f95067c428ebcb46496587f08e8cf4ccc0fe5903bea10dbb8" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "frame-metadata" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daaf440c68eb2c3d88e5760fe8c7af3f9fee9181fab6c2f2c4e7cc48dcc40bb8" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + [[package]] name = "frame-metadata-hash-extension" version = "0.1.0" @@ -6444,9 +7363,9 @@ dependencies = [ "array-bytes", "const-hex", "docify", - "frame-metadata 16.0.0", - "frame-support", - "frame-system", + "frame-metadata 18.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "merkleized-metadata", "parity-scale-codec", @@ -6454,9 +7373,25 @@ dependencies = [ "sp-api 26.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "substrate-test-runtime-client", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", +] + +[[package]] +name = "frame-metadata-hash-extension" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ac71dbd97039c49fdd69f416a4dd5d8da3652fdcafc3738b45772ad79eb4ec" +dependencies = [ + "array-bytes", + "docify", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", ] [[package]] @@ -6465,15 +7400,15 @@ version = "0.1.0" dependencies = [ "assert_cmd", "clap 4.5.13", - "cumulus-primitives-proof-size-hostfunction", + "cumulus-primitives-proof-size-hostfunction 0.2.0", "cumulus-test-runtime", "frame-benchmarking-cli", "log", "sc-chain-spec", "sc-cli", - "sp-genesis-builder", + "sp-genesis-builder 0.8.0", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", "sp-tracing 16.0.0", "tempfile", "tracing-subscriber 0.3.18", @@ -6485,7 +7420,7 @@ version = "0.35.0" dependencies = [ "futures", "indicatif", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "serde", @@ -6509,13 +7444,13 @@ dependencies = [ "aquamarine", "array-bytes", "assert_matches", - "binary-merkle-tree", + "binary-merkle-tree 13.0.0", "bitflags 1.3.2", "docify", "environmental", - "frame-metadata 16.0.0", - "frame-support-procedural", - "frame-system", + "frame-metadata 18.0.0", + "frame-support-procedural 23.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "k256", "log", @@ -6533,15 +7468,15 @@ dependencies = [ "sp-crypto-hashing 0.1.0", "sp-crypto-hashing-proc-macro 0.1.0", "sp-debug-derive 14.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-state-machine 0.35.0", "sp-std 14.0.0", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "sp-trie 29.0.0", "sp-weights 27.0.0", @@ -6550,22 +7485,64 @@ dependencies = [ ] [[package]] -name = "frame-support-procedural" -version = "23.0.0" +name = "frame-support" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e44af69fa61bc5005ffe0339e198957e77f0f255704a9bee720da18a733e3dc" dependencies = [ - "Inflector", - "cfg-expr", + "aquamarine", + "array-bytes", + "bitflags 1.3.2", + "docify", + "environmental", + "frame-metadata 16.0.0", + "frame-support-procedural 30.0.4", + "impl-trait-for-tuples", + "k256", + "log", + "macro_magic", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "serde_json", + "smallvec", + "sp-api 34.0.0", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-genesis-builder 0.15.1", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-metadata-ir 0.7.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", + "sp-state-machine 0.43.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-tracing 17.0.1", + "sp-weights 31.0.0", + "static_assertions", + "tt-call", +] + +[[package]] +name = "frame-support-procedural" +version = "23.0.0" +dependencies = [ + "Inflector", + "cfg-expr", "derive-syn-parse", "docify", "expander", - "frame-support", - "frame-support-procedural-tools", - "frame-system", + "frame-support 28.0.0", + "frame-support-procedural-tools 10.0.0", + "frame-system 28.0.0", "itertools 0.11.0", "macro_magic", "parity-scale-codec", "pretty_assertions", - "proc-macro-warning 1.0.0", + "proc-macro-warning", "proc-macro2 1.0.86", "quote 1.0.37", "regex", @@ -6576,18 +7553,51 @@ dependencies = [ "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "static_assertions", - "syn 2.0.82", + "syn 2.0.87", +] + +[[package]] +name = "frame-support-procedural" +version = "30.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e8f9b6bc1517a6fcbf0b2377e5c8c6d39f5bb7862b191a59a9992081d63972d" +dependencies = [ + "Inflector", + "cfg-expr", + "derive-syn-parse", + "expander", + "frame-support-procedural-tools 13.0.0", + "itertools 0.11.0", + "macro_magic", + "proc-macro-warning", + "proc-macro2 1.0.86", + "quote 1.0.37", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 2.0.87", ] [[package]] name = "frame-support-procedural-tools" version = "10.0.0" dependencies = [ - "frame-support-procedural-tools-derive", + "frame-support-procedural-tools-derive 11.0.0", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bead15a320be1764cdd50458c4cfacb23e0cee65f64f500f8e34136a94c7eeca" +dependencies = [ + "frame-support-procedural-tools-derive 12.0.0", "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -6596,19 +7606,30 @@ version = "11.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed971c6435503a099bdac99fe4c5bea08981709e5b5a0a8535a1856f48561191" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "frame-support-test" version = "3.0.0" dependencies = [ - "frame-benchmarking", - "frame-executive", - "frame-metadata 16.0.0", - "frame-support", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata 18.0.0", + "frame-support 28.0.0", "frame-support-test-pallet", - "frame-system", + "frame-system 28.0.0", "parity-scale-codec", "pretty_assertions", "rustversion", @@ -6630,8 +7651,8 @@ dependencies = [ name = "frame-support-test-compile-pass" version = "4.0.0-dev" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -6643,8 +7664,8 @@ dependencies = [ name = "frame-support-test-pallet" version = "4.0.0-dev" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "serde", @@ -6656,7 +7677,7 @@ name = "frame-support-test-stg-frame-crate" version = "0.1.0" dependencies = [ "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk-frame 0.1.0", "scale-info", ] @@ -6667,7 +7688,7 @@ dependencies = [ "cfg-if", "criterion", "docify", - "frame-support", + "frame-support 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -6682,13 +7703,34 @@ dependencies = [ "substrate-test-runtime-client", ] +[[package]] +name = "frame-system" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c7fa02f8c305496d2ae52edaecdb9d165f11afa965e05686d7d7dd1ce93611" +dependencies = [ + "cfg-if", + "docify", + "frame-support 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-version 37.0.0", + "sp-weights 31.0.0", +] + [[package]] name = "frame-system-benchmarking" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -6698,6 +7740,21 @@ dependencies = [ "sp-version 29.0.0", ] +[[package]] +name = "frame-system-benchmarking" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9693b2a736beb076e673520e1e8dee4fc128b8d35b020ef3e8a4b1b5ad63d9f2" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "frame-system-rpc-runtime-api" version = "26.0.0" @@ -6707,16 +7764,39 @@ dependencies = [ "sp-api 26.0.0", ] +[[package]] +name = "frame-system-rpc-runtime-api" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475c4f8604ba7e4f05cd2c881ba71105093e638b9591ec71a8db14a64b3b4ec3" +dependencies = [ + "docify", + "parity-scale-codec", + "sp-api 34.0.0", +] + [[package]] name = "frame-try-runtime" version = "0.34.0" dependencies = [ - "frame-support", + "frame-support 28.0.0", "parity-scale-codec", "sp-api 26.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "frame-try-runtime" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c811a5a1f5429c7fb5ebbf6cf9502d8f9b673fd395c12cf46c44a30a7daf0e" +dependencies = [ + "frame-support 38.0.0", + "parity-scale-codec", + "sp-api 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "fs-err" version = "2.9.0" @@ -6739,7 +7819,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -6757,9 +7837,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -6772,9 +7852,9 @@ dependencies = [ [[package]] name = "futures-bounded" -version = "0.1.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b07bbbe7d7e78809544c6f718d875627addc73a7c3582447abc052cd3dc67e0" +checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e" dependencies = [ "futures-timer", "futures-util", @@ -6782,9 +7862,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -6792,15 +7872,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -6810,9 +7890,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -6844,36 +7924,37 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] name = "futures-rustls" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.21.7", + "rustls 0.23.18", + "rustls-pki-types", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -6882,14 +7963,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers", - "send_wrapper 0.4.0", + "send_wrapper", ] [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -6917,12 +7998,12 @@ name = "generate-bags" version = "28.0.0" dependencies = [ "chrono", - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "num-format", - "pallet-staking", - "sp-staking", + "pallet-staking 28.0.0", + "sp-staking 26.0.0", ] [[package]] @@ -7079,45 +8160,45 @@ dependencies = [ name = "glutton-westend-runtime" version = "3.0.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-timestamp", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "pallet-aura", - "pallet-glutton", - "pallet-message-queue", - "pallet-sudo", - "pallet-timestamp", - "parachains-common", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-timestamp 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", + "pallet-aura 27.0.0", + "pallet-glutton 14.0.0", + "pallet-message-queue 31.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "parachains-common 7.0.0", "parity-scale-codec", "scale-info", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] @@ -7161,7 +8242,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.9", - "indexmap 2.2.3", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -7180,7 +8261,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.3", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -7251,6 +8332,16 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", + "serde", +] + [[package]] name = "hashlink" version = "0.8.4" @@ -7301,6 +8392,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-conservative" @@ -7308,6 +8402,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec 0.7.4", +] + [[package]] name = "hex-literal" version = "0.4.1" @@ -7323,7 +8426,7 @@ dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner 0.6.0", + "enum-as-inner", "futures-channel", "futures-io", "futures-util", @@ -7331,6 +8434,7 @@ dependencies = [ "ipnet", "once_cell", "rand", + "socket2 0.5.7", "thiserror", "tinyvec", "tokio", @@ -7340,9 +8444,9 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" dependencies = [ "cfg-if", "futures-util", @@ -7582,7 +8686,7 @@ dependencies = [ "hyper 1.3.1", "hyper-util", "log", - "rustls 0.23.14", + "rustls 0.23.18", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -7665,17 +8769,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.4.0" @@ -7784,6 +8877,15 @@ dependencies = [ "uint 0.10.0", ] +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp 0.5.2", +] + [[package]] name = "impl-rlp" version = "0.4.0" @@ -7860,12 +8962,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", + "serde", ] [[package]] @@ -7940,7 +9043,7 @@ dependencies = [ "socket2 0.5.7", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -7979,7 +9082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.9", - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -8046,6 +9149,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -8100,9 +9212,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -8150,103 +9262,36 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" -dependencies = [ - "jsonrpsee-client-transport 0.22.5", - "jsonrpsee-core 0.22.5", - "jsonrpsee-http-client 0.22.5", - "jsonrpsee-types 0.22.5", -] - -[[package]] -name = "jsonrpsee" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" -dependencies = [ - "jsonrpsee-core 0.23.2", - "jsonrpsee-types 0.23.2", - "jsonrpsee-ws-client 0.23.2", -] - -[[package]] -name = "jsonrpsee" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" +checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" dependencies = [ - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-http-client 0.24.3", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", "jsonrpsee-server", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types", "jsonrpsee-wasm-client", - "jsonrpsee-ws-client 0.24.3", - "tokio", - "tracing", -] - -[[package]] -name = "jsonrpsee-client-transport" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" -dependencies = [ - "futures-util", - "http 0.2.9", - "jsonrpsee-core 0.22.5", - "pin-project", - "rustls-native-certs 0.7.0", - "rustls-pki-types", - "soketto 0.7.1", - "thiserror", - "tokio", - "tokio-rustls 0.25.0", - "tokio-util", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-client-transport" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" -dependencies = [ - "base64 0.22.1", - "futures-util", - "http 1.1.0", - "jsonrpsee-core 0.23.2", - "pin-project", - "rustls 0.23.14", - "rustls-pki-types", - "rustls-platform-verifier", - "soketto 0.8.0", - "thiserror", + "jsonrpsee-ws-client", "tokio", - "tokio-rustls 0.26.0", - "tokio-util", "tracing", - "url", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" +checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" dependencies = [ "base64 0.22.1", "futures-channel", "futures-util", "gloo-net", "http 1.1.0", - "jsonrpsee-core 0.24.3", + "jsonrpsee-core", "pin-project", - "rustls 0.23.14", + "rustls 0.23.18", "rustls-pki-types", "rustls-platform-verifier", "soketto 0.8.0", @@ -8260,139 +9305,74 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.5" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" dependencies = [ - "anyhow", "async-trait", - "beef", + "bytes", "futures-timer", "futures-util", - "hyper 0.14.29", - "jsonrpsee-types 0.22.5", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "jsonrpsee-types", + "parking_lot 0.12.3", "pin-project", - "rustc-hash 1.1.0", + "rand", + "rustc-hash 2.0.0", "serde", "serde_json", "thiserror", "tokio", "tokio-stream", "tracing", + "wasm-bindgen-futures", ] [[package]] -name = "jsonrpsee-core" -version = "0.23.2" +name = "jsonrpsee-http-client" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ - "anyhow", "async-trait", - "beef", - "futures-timer", - "futures-util", - "jsonrpsee-types 0.23.2", - "pin-project", - "rustc-hash 1.1.0", + "base64 0.22.1", + "http-body 1.0.0", + "hyper 1.3.1", + "hyper-rustls 0.27.3", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls 0.23.18", + "rustls-platform-verifier", "serde", "serde_json", "thiserror", "tokio", - "tokio-stream", + "tower", "tracing", + "url", ] [[package]] -name = "jsonrpsee-core" -version = "0.24.3" +name = "jsonrpsee-proc-macros" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" -dependencies = [ - "async-trait", - "bytes", - "futures-timer", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "jsonrpsee-types 0.24.3", - "parking_lot 0.12.3", - "pin-project", - "rand", - "rustc-hash 2.0.0", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tracing", - "wasm-bindgen-futures", -] - -[[package]] -name = "jsonrpsee-http-client" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" -dependencies = [ - "async-trait", - "hyper 0.14.29", - "hyper-rustls 0.24.2", - "jsonrpsee-core 0.22.5", - "jsonrpsee-types 0.22.5", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-http-client" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" -dependencies = [ - "async-trait", - "base64 0.22.1", - "http-body 1.0.0", - "hyper 1.3.1", - "hyper-rustls 0.27.3", - "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", - "rustls 0.23.14", - "rustls-platform-verifier", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-proc-macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" -dependencies = [ - "heck 0.5.0", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 2.0.82", -] - -[[package]] -name = "jsonrpsee-server" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" +checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" +dependencies = [ + "heck 0.5.0", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" dependencies = [ "futures-util", "http 1.1.0", @@ -8400,8 +9380,8 @@ dependencies = [ "http-body-util", "hyper 1.3.1", "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core", + "jsonrpsee-types", "pin-project", "route-recognizer", "serde", @@ -8417,35 +9397,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" -dependencies = [ - "beef", - "http 1.1.0", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ "http 1.1.0", "serde", @@ -8455,38 +9409,25 @@ dependencies = [ [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0470d0ae043ffcb0cd323797a631e637fb4b55fe3eaa6002934819458bba62a7" -dependencies = [ - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", -] - -[[package]] -name = "jsonrpsee-ws-client" -version = "0.23.2" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" +checksum = "1a01cd500915d24ab28ca17527e23901ef1be6d659a2322451e1045532516c25" dependencies = [ - "http 1.1.0", - "jsonrpsee-client-transport 0.23.2", - "jsonrpsee-core 0.23.2", - "jsonrpsee-types 0.23.2", - "url", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" +checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ "http 1.1.0", - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", "url", ] @@ -8527,13 +9468,23 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + [[package]] name = "keccak-hash" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +checksum = "3e1b8590eb6148af2ea2d75f38e7d29f5ca970d5a4df456b3ef19b8b415d0264" dependencies = [ - "primitive-types 0.12.2", + "primitive-types 0.13.1", "tiny-keccak", ] @@ -8563,13 +9514,13 @@ dependencies = [ "pallet-example-mbm", "pallet-example-tasks", "parity-scale-codec", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "primitive-types 0.13.1", "scale-info", "serde_json", "sp-debug-derive 14.0.0", "static_assertions", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -8609,7 +9560,7 @@ dependencies = [ "rand", "rustls 0.21.7", "rustls-pemfile 1.0.3", - "secrecy", + "secrecy 0.8.0", "serde", "serde_json", "serde_yaml", @@ -8820,9 +9771,31 @@ dependencies = [ "futures-timer", "getrandom", "instant", - "libp2p-allow-block-list", - "libp2p-connection-limits", - "libp2p-core", + "libp2p-allow-block-list 0.2.0", + "libp2p-connection-limits 0.2.1", + "libp2p-core 0.40.1", + "libp2p-identity", + "libp2p-swarm 0.43.7", + "multiaddr 0.18.1", + "pin-project", + "rw-stream-sink", + "thiserror", +] + +[[package]] +name = "libp2p" +version = "0.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbe80f9c7e00526cd6b838075b9c171919404a4732cb2fa8ece0a093223bfc4" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom", + "libp2p-allow-block-list 0.4.0", + "libp2p-connection-limits 0.4.0", + "libp2p-core 0.42.0", "libp2p-dns", "libp2p-identify", "libp2p-identity", @@ -8833,10 +9806,9 @@ dependencies = [ "libp2p-ping", "libp2p-quic", "libp2p-request-response", - "libp2p-swarm", + "libp2p-swarm 0.45.1", "libp2p-tcp", "libp2p-upnp", - "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", "multiaddr 0.18.1", @@ -8851,9 +9823,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55b46558c5c0bf99d3e2a1a38fd54ff5476ca66dd1737b12466a1824dd219311" dependencies = [ - "libp2p-core", + "libp2p-core 0.40.1", + "libp2p-identity", + "libp2p-swarm 0.43.7", + "void", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1027ccf8d70320ed77e984f273bc8ce952f623762cb9bf2d126df73caef8041" +dependencies = [ + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.45.1", "void", ] @@ -8863,9 +9847,21 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f5107ad45cb20b2f6c3628c7b6014b996fcb13a88053f4569c872c6e30abf58" dependencies = [ - "libp2p-core", + "libp2p-core 0.40.1", + "libp2p-identity", + "libp2p-swarm 0.43.7", + "void", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d003540ee8baef0d254f7b6bfd79bac3ddf774662ca0abf69186d517ef82ad8" +dependencies = [ + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.45.1", "void", ] @@ -8897,42 +9893,70 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-core" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61f26c83ed111104cd820fe9bc3aaabbac5f1652a1d213ed6e900b7918a1298" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr 0.18.1", + "multihash 0.19.1", + "multistream-select", + "once_cell", + "parking_lot 0.12.3", + "pin-project", + "quick-protobuf 0.8.1", + "rand", + "rw-stream-sink", + "smallvec", + "thiserror", + "tracing", + "unsigned-varint 0.8.0", + "void", + "web-time", +] + [[package]] name = "libp2p-dns" -version = "0.40.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a18db73084b4da2871438f6239fef35190b05023de7656e877c18a00541a3b" +checksum = "97f37f30d5c7275db282ecd86e54f29dd2176bd3ac656f06abf43bedb21eb8bd" dependencies = [ "async-trait", "futures", - "libp2p-core", + "hickory-resolver", + "libp2p-core 0.42.0", "libp2p-identity", - "log", "parking_lot 0.12.3", "smallvec", - "trust-dns-resolver", + "tracing", ] [[package]] name = "libp2p-identify" -version = "0.43.1" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a96638a0a176bec0a4bcaebc1afa8cf909b114477209d7456ade52c61cd9cd" +checksum = "1711b004a273be4f30202778856368683bd9a83c4c7dcc8f848847606831a4e3" dependencies = [ - "asynchronous-codec", + "asynchronous-codec 0.7.0", "either", "futures", "futures-bounded", "futures-timer", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", - "log", + "libp2p-swarm 0.45.1", "lru 0.12.3", "quick-protobuf 0.8.1", "quick-protobuf-codec", "smallvec", "thiserror", + "tracing", "void", ] @@ -8956,83 +9980,84 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.44.6" +version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ea178dabba6dde6ffc260a8e0452ccdc8f79becf544946692fff9d412fc29d" +checksum = "ced237d0bd84bbebb7c2cad4c073160dacb4fe40534963c32ed6d4c6bb7702a3" dependencies = [ "arrayvec 0.7.4", - "asynchronous-codec", + "asynchronous-codec 0.7.0", "bytes", "either", "fnv", "futures", + "futures-bounded", "futures-timer", - "instant", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", - "log", + "libp2p-swarm 0.45.1", "quick-protobuf 0.8.1", "quick-protobuf-codec", "rand", "sha2 0.10.8", "smallvec", "thiserror", + "tracing", "uint 0.9.5", - "unsigned-varint 0.7.2", "void", + "web-time", ] [[package]] name = "libp2p-mdns" -version = "0.44.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a2567c305232f5ef54185e9604579a894fd0674819402bb0ac0246da82f52a" +checksum = "14b8546b6644032565eb29046b42744aee1e9f261ed99671b2c93fb140dba417" dependencies = [ "data-encoding", "futures", + "hickory-proto", "if-watch", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", - "log", + "libp2p-swarm 0.45.1", "rand", "smallvec", "socket2 0.5.7", "tokio", - "trust-dns-proto 0.22.0", + "tracing", "void", ] [[package]] name = "libp2p-metrics" -version = "0.13.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239ba7d28f8d0b5d77760dc6619c05c7e88e74ec8fbbe97f856f20a56745e620" +checksum = "77ebafa94a717c8442d8db8d3ae5d1c6a15e30f2d347e0cd31d057ca72e42566" dependencies = [ - "instant", - "libp2p-core", + "futures", + "libp2p-core 0.42.0", "libp2p-identify", "libp2p-identity", "libp2p-kad", "libp2p-ping", - "libp2p-swarm", - "once_cell", + "libp2p-swarm 0.45.1", + "pin-project", "prometheus-client", + "web-time", ] [[package]] name = "libp2p-noise" -version = "0.43.2" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2eeec39ad3ad0677551907dd304b2f13f17208ccebe333bef194076cd2e8921" +checksum = "36b137cb1ae86ee39f8e5d6245a296518912014eaa87427d24e6ff58cfc1b28c" dependencies = [ + "asynchronous-codec 0.7.0", "bytes", "curve25519-dalek 4.1.3", "futures", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "log", "multiaddr 0.18.1", "multihash 0.19.1", "once_cell", @@ -9042,68 +10067,71 @@ dependencies = [ "snow", "static_assertions", "thiserror", + "tracing", "x25519-dalek", "zeroize", ] [[package]] name = "libp2p-ping" -version = "0.43.1" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e702d75cd0827dfa15f8fd92d15b9932abe38d10d21f47c50438c71dd1b5dae3" +checksum = "005a34420359223b974ee344457095f027e51346e992d1e0dcd35173f4cdd422" dependencies = [ "either", "futures", "futures-timer", - "instant", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", - "log", + "libp2p-swarm 0.45.1", "rand", + "tracing", "void", + "web-time", ] [[package]] name = "libp2p-quic" -version = "0.9.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130d451d83f21b81eb7b35b360bc7972aeafb15177784adc56528db082e6b927" +checksum = "46352ac5cd040c70e88e7ff8257a2ae2f891a4076abad2c439584a31c15fd24e" dependencies = [ "bytes", "futures", "futures-timer", "if-watch", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", "libp2p-tls", - "log", "parking_lot 0.12.3", - "quinn 0.10.2", + "quinn", "rand", - "ring 0.16.20", - "rustls 0.21.7", + "ring 0.17.8", + "rustls 0.23.18", "socket2 0.5.7", "thiserror", "tokio", + "tracing", ] [[package]] name = "libp2p-request-response" -version = "0.25.3" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e3b4d67870478db72bac87bfc260ee6641d0734e0e3e275798f089c3fecfd4" +checksum = "1356c9e376a94a75ae830c42cdaea3d4fe1290ba409a22c809033d1b7dcab0a6" dependencies = [ "async-trait", "futures", - "instant", - "libp2p-core", + "futures-bounded", + "futures-timer", + "libp2p-core 0.42.0", "libp2p-identity", - "libp2p-swarm", - "log", + "libp2p-swarm 0.45.1", "rand", "smallvec", + "tracing", "void", + "web-time", ] [[package]] @@ -9117,129 +10145,138 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm-derive", "log", "multistream-select", "once_cell", "rand", "smallvec", + "void", +] + +[[package]] +name = "libp2p-swarm" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dd6741793d2c1fb2088f67f82cf07261f25272ebe3c0b0c311e0c6b50e851a" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm-derive", + "lru 0.12.3", + "multistream-select", + "once_cell", + "rand", + "smallvec", "tokio", + "tracing", "void", + "web-time", ] [[package]] name = "libp2p-swarm-derive" -version = "0.33.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d5ec2a3df00c7836d7696c136274c9c59705bac69133253696a6c932cd1d74" +checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" dependencies = [ - "heck 0.4.1", - "proc-macro-warning 0.4.2", + "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] name = "libp2p-tcp" -version = "0.40.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b558dd40d1bcd1aaaed9de898e9ec6a436019ecc2420dd0016e712fbb61c5508" +checksum = "ad964f312c59dcfcac840acd8c555de8403e295d39edf96f5240048b5fcaa314" dependencies = [ "futures", "futures-timer", "if-watch", "libc", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "log", "socket2 0.5.7", "tokio", + "tracing", ] [[package]] name = "libp2p-tls" -version = "0.2.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8218d1d5482b122ccae396bbf38abdcb283ecc96fa54760e1dfd251f0546ac61" +checksum = "47b23dddc2b9c355f73c1e36eb0c3ae86f7dc964a3715f0731cfad352db4d847" dependencies = [ "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "rcgen", - "ring 0.16.20", - "rustls 0.21.7", + "rcgen 0.11.3", + "ring 0.17.8", + "rustls 0.23.18", "rustls-webpki 0.101.4", "thiserror", - "x509-parser 0.15.1", + "x509-parser", "yasna", ] [[package]] name = "libp2p-upnp" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82775a47b34f10f787ad3e2a22e2c1541e6ebef4fe9f28f3ac553921554c94c1" +checksum = "01bf2d1b772bd3abca049214a3304615e6a36fa6ffc742bdd1ba774486200b8f" dependencies = [ "futures", "futures-timer", "igd-next", - "libp2p-core", - "libp2p-swarm", - "log", + "libp2p-core 0.42.0", + "libp2p-swarm 0.45.1", "tokio", + "tracing", "void", ] [[package]] -name = "libp2p-wasm-ext" -version = "0.40.0" +name = "libp2p-websocket" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e5d8e3a9e07da0ef5b55a9f26c009c8fb3c725d492d8bb4b431715786eea79c" +checksum = "888b2ff2e5d8dcef97283daab35ad1043d18952b65e05279eecbe02af4c6e347" dependencies = [ - "futures", - "js-sys", - "libp2p-core", - "send_wrapper 0.6.0", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "libp2p-websocket" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004ee9c4a4631435169aee6aad2f62e3984dc031c43b6d29731e8e82a016c538" -dependencies = [ - "either", + "either", "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.42.0", "libp2p-identity", - "log", "parking_lot 0.12.3", "pin-project-lite", "rw-stream-sink", "soketto 0.8.0", "thiserror", + "tracing", "url", "webpki-roots 0.25.2", ] [[package]] name = "libp2p-yamux" -version = "0.44.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eedcb62824c4300efb9cfd4e2a6edaf3ca097b9e68b36dabe45a44469fd6a85" +checksum = "788b61c80789dba9760d8c669a5bedb642c8267555c803fabd8396e4ca5c5882" dependencies = [ + "either", "futures", - "libp2p-core", - "log", + "libp2p-core 0.42.0", "thiserror", - "yamux", + "tracing", + "yamux 0.12.1", + "yamux 0.13.3", ] [[package]] @@ -9364,9 +10401,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lioness" @@ -9400,9 +10437,9 @@ dependencies = [ [[package]] name = "litep2p" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ab2528b02b6dbbc3e6ec4b55ccde885647c622a315b7da45081ed2dfe4b813" +checksum = "2b0fef34af8847e816003bf7fdeac5ea50b9a7a88441ac927a6166b5e812ab79" dependencies = [ "async-trait", "bs58", @@ -9413,7 +10450,7 @@ dependencies = [ "futures-timer", "hex-literal", "hickory-resolver", - "indexmap 2.2.3", + "indexmap 2.7.0", "libc", "mockall 0.13.0", "multiaddr 0.17.1", @@ -9425,7 +10462,7 @@ dependencies = [ "prost 0.12.6", "prost-build", "rand", - "rcgen", + "rcgen 0.10.0", "ring 0.16.20", "rustls 0.20.9", "serde", @@ -9445,7 +10482,7 @@ dependencies = [ "unsigned-varint 0.8.0", "url", "x25519-dalek", - "x509-parser 0.16.0", + "x509-parser", "yasna", "zeroize", ] @@ -9476,6 +10513,15 @@ dependencies = [ "value-bag", ] +[[package]] +name = "lru" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" +dependencies = [ + "hashbrown 0.12.3", +] + [[package]] name = "lru" version = "0.11.0" @@ -9547,7 +10593,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -9561,7 +10607,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -9572,7 +10618,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -9583,7 +10629,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -9629,12 +10675,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matrixmultiply" version = "0.3.7" @@ -9707,15 +10747,15 @@ dependencies = [ [[package]] name = "merkleized-metadata" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f313fcff1d2a4bcaa2deeaa00bf7530d77d5f7bd0467a117dde2e29a75a7a17a" +checksum = "38c592efaf1b3250df14c8f3c2d952233f0302bb81d3586db2f303666c1cd607" dependencies = [ "array-bytes", "blake3", - "frame-metadata 16.0.0", + "frame-metadata 18.0.0", "parity-scale-codec", - "scale-decode", + "scale-decode 0.13.1", "scale-info", ] @@ -9737,7 +10777,7 @@ version = "0.1.0" dependencies = [ "async-std", "async-trait", - "bp-messages", + "bp-messages 0.7.0", "finality-relay", "futures", "hex", @@ -9769,9 +10809,9 @@ dependencies = [ "docify", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "minimal-template-runtime", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "serde_json", ] @@ -9781,7 +10821,7 @@ version = "0.0.0" dependencies = [ "pallet-minimal-template", "parity-scale-codec", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "scale-info", "serde_json", ] @@ -9846,9 +10886,9 @@ dependencies = [ "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-beefy", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", - "sp-mmr-primitives", + "sp-mmr-primitives 26.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-test-runtime-client", @@ -9859,14 +10899,14 @@ dependencies = [ name = "mmr-rpc" version = "28.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "parity-scale-codec", "serde", "serde_json", "sp-api 26.0.0", "sp-blockchain", "sp-core 28.0.0", - "sp-mmr-primitives", + "sp-mmr-primitives 26.0.0", "sp-runtime 31.0.1", ] @@ -9920,7 +10960,7 @@ dependencies = [ "cfg-if", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -10233,14 +11273,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "static_assertions", ] [[package]] @@ -10256,13 +11295,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.6.0", "cfg-if", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "libc", ] @@ -10283,8 +11322,9 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", + "async-trait", "clap 4.5.13", - "derive_more", + "derive_more 0.99.17", "fs_extra", "futures", "hash-db", @@ -10304,10 +11344,10 @@ dependencies = [ "serde_json", "sp-consensus", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "sp-trie 29.0.0", "tempfile", @@ -10325,7 +11365,7 @@ dependencies = [ name = "node-rpc" version = "3.0.0-dev" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "mmr-rpc", "node-primitives", "pallet-transaction-payment-rpc", @@ -10343,14 +11383,14 @@ dependencies = [ "sc-transaction-pool-api", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-beefy", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", "substrate-frame-rpc-system", "substrate-state-trie-migration-rpc", ] @@ -10382,19 +11422,19 @@ dependencies = [ name = "node-testing" version = "3.0.0-dev" dependencies = [ - "frame-metadata-hash-extension", - "frame-system", + "frame-metadata-hash-extension 0.1.0", + "frame-system 28.0.0", "fs_extra", "futures", "kitchensink-runtime", "log", "node-primitives", - "pallet-asset-conversion", - "pallet-asset-conversion-tx-payment", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-revive", - "pallet-skip-feeless-payment", + "pallet-asset-conversion 10.0.0", + "pallet-asset-conversion-tx-payment 10.0.0", + "pallet-asset-tx-payment 28.0.0", + "pallet-assets 29.1.0", + "pallet-revive 0.1.0", + "pallet-skip-feeless-payment 3.0.0", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -10403,16 +11443,16 @@ dependencies = [ "sc-executor 0.32.0", "sc-service", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "staging-node-cli", "substrate-test-client", "tempfile", @@ -10525,7 +11565,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -10573,9 +11613,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -10636,22 +11676,13 @@ dependencies = [ "memchr", ] -[[package]] -name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs 0.5.2", -] - [[package]] name = "oid-registry" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs", ] [[package]] @@ -10701,7 +11732,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -10752,7 +11783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7b1d40dd8f367db3c65bec8d3dd47d4a604ee8874480738f93191bddab4e0e0" dependencies = [ "expander", - "indexmap 2.2.3", + "indexmap 2.7.0", "itertools 0.11.0", "petgraph", "proc-macro-crate 3.1.0", @@ -10803,13 +11834,13 @@ name = "pallet-alliance" version = "27.0.0" dependencies = [ "array-bytes", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-collective", - "pallet-identity", + "pallet-balances 28.0.0", + "pallet-collective 28.0.0", + "pallet-identity 29.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -10818,16 +11849,36 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-alliance" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59378a648a0aa279a4b10650366c3389cd0a1239b1876f74bfecd268eecb086b" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-collective 38.0.0", + "pallet-identity 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-asset-conversion" version = "10.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-assets", - "pallet-balances", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", "parity-scale-codec", "primitive-types 0.13.1", "scale-info", @@ -10838,17 +11889,36 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-asset-conversion" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f0078659ae95efe6a1bf138ab5250bc41ab98f22ff3651d0208684f08ae797" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-asset-conversion-ops" version = "0.1.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", "parity-scale-codec", "primitive-types 0.13.1", "scale-info", @@ -10858,17 +11928,36 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-asset-conversion-ops" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edbeda834bcd6660f311d4eead3dabdf6d385b7308ac75b0fae941a960e6c3a" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-asset-conversion 20.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-asset-conversion-tx-payment" version = "10.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-transaction-payment", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -10877,14 +11966,29 @@ dependencies = [ "sp-storage 19.0.0", ] +[[package]] +name = "pallet-asset-conversion-tx-payment" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab66c4c22ac0f20e620a954ce7ba050118d6d8011e2d02df599309502064e98" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-asset-conversion 20.0.0", + "pallet-transaction-payment 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-asset-rate" version = "7.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -10892,17 +11996,32 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-asset-rate" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b2149aa741bc39466bbcc92d9d0ab6e9adcf39d2790443a735ad573b3191e7" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-asset-tx-payment" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-assets", - "pallet-authorship", - "pallet-balances", - "pallet-transaction-payment", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-assets 29.1.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", "scale-info", "serde", @@ -10913,16 +12032,34 @@ dependencies = [ "sp-storage 19.0.0", ] +[[package]] +name = "pallet-asset-tx-payment" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406a486466d15acc48c99420191f96f1af018f3381fde829c467aba489030f18" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-transaction-payment 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-assets" version = "29.1.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -10930,16 +12067,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-assets" +version = "40.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f45f4eb6027fc34c4650e0ed6a7e57ed3335cc364be74b4531f714237676bcee" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-assets-freezer" version = "0.1.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-assets", - "pallet-balances", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -10947,59 +12101,119 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-assets-freezer" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "127adc2250b89416b940850ce2175dab10a9297b503b1fcb05dc555bd9bd3207" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-assets 40.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-atomic-swap" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", + "polkadot-sdk-frame 0.1.0", "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", +] + +[[package]] +name = "pallet-atomic-swap" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15906a685adeabe6027e49c814a34066222dd6136187a8a79c213d0d739b6634" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", ] [[package]] name = "pallet-aura" version = "27.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 30.0.0", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-aura" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b31da6e794d655d1f9c4da6557a57399538d75905a7862a2ed3f7e5fb711d7e4" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-timestamp 37.0.0", + "parity-scale-codec", + "scale-info", + "sp-application-crypto 38.0.0", + "sp-consensus-aura 0.40.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-authority-discovery" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", - "pallet-session", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-session 28.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 30.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-authority-discovery" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb0208f0538d58dcb78ce1ff5e6e8641c5f37b23b20b05587e51da30ab13541" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-application-crypto 38.0.0", + "sp-authority-discovery 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-authorship" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", @@ -11008,31 +12222,69 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-authorship" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625d47577cabbe1318ccec5d612e2379002d1b6af1ab6edcef3243c66ec246df" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-babe" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-authorship", - "pallet-balances", - "pallet-offences", - "pallet-session", - "pallet-staking", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-offences 27.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 30.0.0", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", +] + +[[package]] +name = "pallet-babe" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee096c0def13832475b340d00121025e0225de29604d44bc6dfcaa294c995b4" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-authorship 38.0.0", + "pallet-session 38.0.0", + "pallet-timestamp 37.0.0", + "parity-scale-codec", + "scale-info", + "sp-application-crypto 38.0.0", + "sp-consensus-babe 0.40.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-staking 36.0.0", ] [[package]] @@ -11041,12 +12293,12 @@ version = "27.0.0" dependencies = [ "aquamarine", "docify", - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11055,13 +12307,35 @@ dependencies = [ "sp-tracing 16.0.0", ] +[[package]] +name = "pallet-bags-list" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd23a6f94ba9c1e57c8a7f8a41327d132903a79c55c0c83f36cbae19946cf10" +dependencies = [ + "aquamarine", + "docify", + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-tracing 17.0.1", +] + [[package]] name = "pallet-bags-list-fuzzer" version = "4.0.0-dev" dependencies = [ - "frame-election-provider-support", + "frame-election-provider-support 28.0.0", "honggfuzz", - "pallet-bags-list", + "pallet-bags-list 27.0.0", "rand", ] @@ -11069,13 +12343,13 @@ dependencies = [ name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" dependencies = [ - "frame-election-provider-support", + "frame-election-provider-support 28.0.0", "frame-remote-externalities", - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-bags-list", - "pallet-staking", + "pallet-bags-list 27.0.0", + "pallet-staking 28.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", @@ -11088,11 +12362,11 @@ name = "pallet-balances" version = "28.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-transaction-payment", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", "paste", "scale-info", @@ -11101,68 +12375,130 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-balances" +version = "39.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6945b078919acb14d126490e4b0973a688568b30142476ca69c6df2bed27ad" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-beefy" version = "28.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-authorship", - "pallet-balances", - "pallet-offences", - "pallet-session", - "pallet-staking", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-offences 27.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "serde", - "sp-consensus-beefy", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", "sp-state-machine 0.35.0", ] +[[package]] +name = "pallet-beefy" +version = "39.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "014d177a3aba19ac144fc6b2b5eb94930b9874734b91fd014902b6706288bb5f" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-authorship 38.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-beefy 22.1.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-beefy-mmr" version = "28.0.0" dependencies = [ "array-bytes", - "binary-merkle-tree", - "frame-benchmarking", - "frame-support", - "frame-system", + "binary-merkle-tree 13.0.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-beefy", - "pallet-mmr", - "pallet-session", + "pallet-beefy 28.0.0", + "pallet-mmr 27.0.0", + "pallet-session 28.0.0", "parity-scale-codec", "scale-info", "serde", "sp-api 26.0.0", - "sp-consensus-beefy", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-state-machine 0.35.0", ] +[[package]] +name = "pallet-beefy-mmr" +version = "39.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c64f536e7f04cf3a0a17fdf20870ddb3d63a7690419c40f75cfd2f72b6e6d22" +dependencies = [ + "array-bytes", + "binary-merkle-tree 15.0.1", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-beefy 39.0.0", + "pallet-mmr 38.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-consensus-beefy 22.1.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-state-machine 0.43.0", +] + [[package]] name = "pallet-bounties" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-treasury", + "pallet-balances 28.0.0", + "pallet-treasury 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11170,24 +12506,42 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-bounties" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1163f9cd8bbc47ec0c6900a3ca67689d8d7b40bedfa6aa22b1b3c6027b1090e" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-treasury 37.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-bridge-beefy" version = "0.1.0" dependencies = [ "bp-beefy", - "bp-runtime", - "bp-test-utils", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", "ckb-merkle-mountain-range", - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-beefy-mmr", - "pallet-mmr", + "pallet-beefy-mmr 28.0.0", + "pallet-mmr 27.0.0", "parity-scale-codec", "rand", "scale-info", "serde", - "sp-consensus-beefy", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", @@ -11198,36 +12552,56 @@ dependencies = [ name = "pallet-bridge-grandpa" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-runtime", - "bp-test-utils", - "frame-benchmarking", - "frame-support", - "frame-system", + "bp-header-chain 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", ] +[[package]] +name = "pallet-bridge-grandpa" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d825fbed9fb68bc5d344311653dc0f69caeabe647365abf79a539310b2245f6" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-runtime 0.18.0", + "bp-test-utils 0.18.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-consensus-grandpa 21.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pallet-bridge-messages" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-messages", - "bp-runtime", - "bp-test-utils", - "frame-benchmarking", - "frame-support", - "frame-system", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-bridge-grandpa", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11238,51 +12612,41 @@ dependencies = [ ] [[package]] -name = "pallet-bridge-parachains" -version = "0.7.0" +name = "pallet-bridge-messages" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1decdc9fb885e46eb17f850aa14f8cf39e17f31574aa6a5fa1a9e603cc526a2" dependencies = [ - "bp-header-chain", - "bp-parachains", - "bp-polkadot-core", - "bp-runtime", - "bp-test-utils", - "frame-benchmarking", - "frame-support", - "frame-system", + "bp-header-chain 0.18.1", + "bp-messages 0.18.0", + "bp-runtime 0.18.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", "log", - "pallet-bridge-grandpa", "parity-scale-codec", "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 37.0.0", ] [[package]] -name = "pallet-bridge-relayers" +name = "pallet-bridge-parachains" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", - "bp-test-utils", - "frame-benchmarking", - "frame-support", - "frame-system", - "log", - "pallet-balances", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-transaction-payment", - "pallet-utility", + "bp-header-chain 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "pallet-bridge-grandpa 0.7.0", "parity-scale-codec", "scale-info", - "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", @@ -11290,13 +12654,89 @@ dependencies = [ ] [[package]] -name = "pallet-broker" -version = "0.6.0" +name = "pallet-bridge-parachains" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41450a8d214f20eaff57aeca8e647b20c0df7d66871ee2262609b90824bd4cca" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-parachains 0.18.0", + "bp-polkadot-core 0.18.0", + "bp-runtime 0.18.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-bridge-grandpa 0.18.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pallet-bridge-relayers" +version = "0.7.0" +dependencies = [ + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-transaction-payment 28.0.0", + "pallet-utility 28.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-std 14.0.0", +] + +[[package]] +name = "pallet-bridge-relayers" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2faead05455a965a0a0ec69ffa779933479b599e40bda809c0aa1efa72a39281" +dependencies = [ + "bp-header-chain 0.18.1", + "bp-messages 0.18.0", + "bp-relayers 0.18.0", + "bp-runtime 0.18.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-bridge-grandpa 0.18.0", + "pallet-bridge-messages 0.18.0", + "pallet-bridge-parachains 0.18.0", + "pallet-transaction-payment 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pallet-broker" +version = "0.6.0" dependencies = [ "bitvec", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "pretty_assertions", @@ -11309,17 +12749,36 @@ dependencies = [ "sp-tracing 16.0.0", ] +[[package]] +name = "pallet-broker" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3043c90106d88cb93fcf0d9b6d19418f11f44cc2b11873414aec3b46044a24ea" +dependencies = [ + "bitvec", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-child-bounties" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-bounties", - "pallet-treasury", + "pallet-balances 28.0.0", + "pallet-bounties 27.0.0", + "pallet-treasury 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11327,40 +12786,79 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-child-bounties" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f3bc38ae6584b5f57e4de3e49e5184bfc0f20692829530ae1465ffe04e09e7" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-bounties 37.0.0", + "pallet-treasury 37.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-collator-selection" version = "9.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-session", - "pallet-timestamp", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", "parity-scale-codec", "rand", "scale-info", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", ] +[[package]] +name = "pallet-collator-selection" +version = "19.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658798d70c9054165169f6a6a96cfa9d6a5e7d24a524bc19825bf17fcbc5cc5a" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-authorship 38.0.0", + "pallet-balances 39.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "rand", + "scale-info", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-collective" version = "28.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11368,13 +12866,30 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-collective" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e149f1aefd444c9a1da6ec5a94bc8a7671d7a33078f85dd19ae5b06e3438e60" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-collective-content" version = "0.6.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11382,6 +12897,21 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-collective-content" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a6a5cbe781d9c711be74855ba32ef138f3779d6c54240c08e6d1b4bbba4d1d" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-contracts" version = "27.0.0" @@ -11390,21 +12920,21 @@ dependencies = [ "assert_matches", "bitflags 1.3.2", "environmental", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-assets", - "pallet-balances", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", "pallet-contracts-fixtures", - "pallet-contracts-proc-macro", - "pallet-contracts-uapi", - "pallet-insecure-randomness-collective-flip", - "pallet-message-queue", - "pallet-proxy", - "pallet-timestamp", - "pallet-utility", + "pallet-contracts-proc-macro 18.0.0", + "pallet-contracts-uapi 5.0.0", + "pallet-insecure-randomness-collective-flip 16.0.0", + "pallet-message-queue 31.0.0", + "pallet-proxy 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "paste", "pretty_assertions", @@ -11420,19 +12950,52 @@ dependencies = [ "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", "wasm-instrument", "wasmi 0.32.3", "wat", ] +[[package]] +name = "pallet-contracts" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df77077745d891c822b4275f273f336077a97e69e62a30134776aa721c96fee" +dependencies = [ + "bitflags 1.3.2", + "environmental", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-balances 39.0.0", + "pallet-contracts-proc-macro 23.0.1", + "pallet-contracts-uapi 12.0.0", + "parity-scale-codec", + "paste", + "rand", + "scale-info", + "serde", + "smallvec", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "wasm-instrument", + "wasmi 0.32.3", +] + [[package]] name = "pallet-contracts-fixtures" version = "1.0.0" dependencies = [ "anyhow", - "frame-system", + "frame-system 28.0.0", "parity-wasm", "sp-runtime 31.0.1", "tempfile", @@ -11445,24 +13008,24 @@ name = "pallet-contracts-mock-network" version = "3.0.0" dependencies = [ "assert_matches", - "frame-support", - "frame-system", - "pallet-assets", - "pallet-balances", - "pallet-contracts", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-contracts 27.0.0", "pallet-contracts-fixtures", - "pallet-contracts-proc-macro", - "pallet-contracts-uapi", - "pallet-insecure-randomness-collective-flip", - "pallet-message-queue", - "pallet-proxy", - "pallet-timestamp", - "pallet-utility", - "pallet-xcm", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", + "pallet-contracts-proc-macro 18.0.0", + "pallet-contracts-uapi 5.0.0", + "pallet-insecure-randomness-collective-flip 16.0.0", + "pallet-message-queue 31.0.0", + "pallet-proxy 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", "pretty_assertions", "scale-info", "sp-api 26.0.0", @@ -11471,10 +13034,46 @@ dependencies = [ "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "xcm-simulator", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "xcm-simulator 7.0.0", +] + +[[package]] +name = "pallet-contracts-mock-network" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "309666537ed001c61a99f59fa7b98680f4a6e4e361ed3bc64f7b0237da3e3e06" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-assets 40.0.0", + "pallet-balances 39.0.0", + "pallet-contracts 38.0.0", + "pallet-contracts-proc-macro 23.0.1", + "pallet-contracts-uapi 12.0.0", + "pallet-insecure-randomness-collective-flip 26.0.0", + "pallet-message-queue 41.0.1", + "pallet-proxy 38.0.0", + "pallet-timestamp 37.0.0", + "pallet-utility 38.0.0", + "pallet-xcm 17.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 14.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-parachains 17.0.1", + "scale-info", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", + "sp-tracing 17.0.1", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", + "xcm-simulator 17.0.0", ] [[package]] @@ -11483,7 +13082,18 @@ version = "18.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", +] + +[[package]] +name = "pallet-contracts-proc-macro" +version = "23.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94226cbd48516b7c310eb5dae8d50798c1ce73a7421dc0977c55b7fc2237a283" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -11496,16 +13106,29 @@ dependencies = [ "scale-info", ] +[[package]] +name = "pallet-contracts-uapi" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f74b000590c33fadea48585d3ae3f4b7867e99f0a524c444d5779f36b9a1b6" +dependencies = [ + "bitflags 1.3.2", + "parity-scale-codec", + "paste", + "polkavm-derive 0.9.1", + "scale-info", +] + [[package]] name = "pallet-conviction-voting" version = "28.0.0" dependencies = [ "assert_matches", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-scheduler", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-scheduler 29.0.0", "parity-scale-codec", "scale-info", "serde", @@ -11514,15 +13137,32 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-conviction-voting" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999c242491b74395b8c5409ef644e782fe426d87ae36ad92240ffbf21ff0a76e" +dependencies = [ + "assert_matches", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-core-fellowship" version = "12.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-ranked-collective", + "pallet-ranked-collective 28.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 23.0.0", @@ -11531,12 +13171,31 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-core-fellowship" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d063b41df454bd128d6fefd5800af8a71ac383c9dd6f20096832537efc110a8a" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-ranked-collective 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-default-config-example" version = "10.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -11548,36 +13207,52 @@ dependencies = [ name = "pallet-delegated-staking" version = "1.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-nomination-pools", - "pallet-staking", + "pallet-balances 28.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] +[[package]] +name = "pallet-delegated-staking" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117f003a97f980514c6db25a50c22aaec2a9ccb5664b3cb32f52fb990e0b0c12" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-democracy" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-preimage", - "pallet-scheduler", + "pallet-balances 28.0.0", + "pallet-preimage 28.0.0", + "pallet-scheduler 29.0.0", "parity-scale-codec", "scale-info", "serde", @@ -11586,14 +13261,32 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-democracy" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d1dc655f50b7c65bb2fb14086608ba11af02ef2936546f7a67db980ec1f133" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-dev-mode" version = "10.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11601,29 +13294,45 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-dev-mode" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d8050c09c5e003d502c1addc7fdfbde21a854bd57787e94447078032710c8" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-election-provider-e2e-test" version = "1.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-bags-list", - "pallet-balances", - "pallet-election-provider-multi-phase", - "pallet-nomination-pools", - "pallet-session", - "pallet-staking", - "pallet-timestamp", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-election-provider-multi-phase 27.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", + "pallet-timestamp 27.0.0", "parity-scale-codec", "parking_lot 0.12.3", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -11632,13 +13341,13 @@ dependencies = [ name = "pallet-election-provider-multi-phase" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-election-provider-support-benchmarking", + "pallet-balances 28.0.0", + "pallet-election-provider-support-benchmarking 27.0.0", "parity-scale-codec", "parking_lot 0.12.3", "rand", @@ -11646,59 +13355,115 @@ dependencies = [ "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", "strum 0.26.3", ] +[[package]] +name = "pallet-election-provider-multi-phase" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f9ad5ae0c13ba3727183dadf1825b6b7b0b0598ed5c366f8697e13fd540f7d" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-election-provider-support-benchmarking 37.0.0", + "parity-scale-codec", + "rand", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-npos-elections 34.0.0", + "sp-runtime 39.0.2", + "strum 0.26.3", +] + [[package]] name = "pallet-election-provider-support-benchmarking" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4111d0d27545c260c9dd0d6fc504961db59c1ec4b42e1bcdc28ebd478895c22" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "sp-npos-elections 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-elections-phragmen" version = "29.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] +[[package]] +name = "pallet-elections-phragmen" +version = "39.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "705c66d6c231340c6d085a0df0319a6ce42a150f248171e88e389ab1e3ce20f5" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-npos-elections 34.0.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-example-authorization-tx-extension" version = "1.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "pallet-verify-signature", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", ] @@ -11706,11 +13471,11 @@ dependencies = [ name = "pallet-example-basic" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11723,7 +13488,7 @@ name = "pallet-example-frame-crate" version = "0.0.1" dependencies = [ "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk-frame 0.1.0", "scale-info", ] @@ -11731,11 +13496,11 @@ dependencies = [ name = "pallet-example-kitchensink" version = "4.0.0-dev" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11747,11 +13512,11 @@ dependencies = [ name = "pallet-example-mbm" version = "0.1.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-migrations", + "pallet-migrations 1.0.0", "parity-scale-codec", "scale-info", "sp-io 30.0.0", @@ -11761,8 +13526,8 @@ dependencies = [ name = "pallet-example-offchain-worker" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "lite-json", "log", "parity-scale-codec", @@ -11778,12 +13543,12 @@ name = "pallet-example-single-block-migrations" version = "0.0.1" dependencies = [ "docify", - "frame-executive", - "frame-support", - "frame-system", - "frame-try-runtime", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-try-runtime 0.34.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11796,9 +13561,9 @@ dependencies = [ name = "pallet-example-split" version = "10.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -11810,9 +13575,9 @@ dependencies = [ name = "pallet-example-tasks" version = "1.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -11826,7 +13591,7 @@ name = "pallet-examples" version = "4.0.0-dev" dependencies = [ "pallet-default-config-example", - "pallet-dev-mode", + "pallet-dev-mode 10.0.0", "pallet-example-authorization-tx-extension", "pallet-example-basic", "pallet-example-frame-crate", @@ -11842,70 +13607,131 @@ name = "pallet-fast-unstake" version = "27.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-staking", + "pallet-balances 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] +[[package]] +name = "pallet-fast-unstake" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ee60e8ef10b3936f2700bd61fa45dcc190c61124becc63bed787addcfa0d20" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-glutton" version = "14.0.0" dependencies = [ "blake2 0.10.6", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-glutton" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1c79ab340890f6ab088a638c350ac1173a1b2a79c18004787523032025582b4" +dependencies = [ + "blake2 0.10.6", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-grandpa" version = "28.0.0" dependencies = [ "finality-grandpa", - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-offences", - "pallet-session", - "pallet-staking", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-offences 27.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 30.0.0", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", +] + +[[package]] +name = "pallet-grandpa" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3a570a4aac3173ea46b600408183ca2bcfdaadc077f802f11e6055963e2449" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-authorship 38.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-application-crypto 38.0.0", + "sp-consensus-grandpa 21.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-staking 36.0.0", ] [[package]] @@ -11913,11 +13739,11 @@ name = "pallet-identity" version = "29.0.0" dependencies = [ "enumflags2", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11926,47 +13752,101 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-identity" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a4288548de9a755e39fcb82ffb9024b6bb1ba0f582464a44423038dd7a892e" +dependencies = [ + "enumflags2", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-im-online" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-authorship", - "pallet-session", + "pallet-authorship 28.0.0", + "pallet-session 28.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 30.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", ] [[package]] -name = "pallet-indices" -version = "28.0.0" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", +name = "pallet-im-online" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fd95270cf029d16cb40fe6bd9f8ab9c78cd966666dccbca4d8bfec35c5bba5" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-authorship 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-application-crypto 38.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + +[[package]] +name = "pallet-indices" +version = "28.0.0" +dependencies = [ + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-indices" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e4b97de630427a39d50c01c9e81ab8f029a00e56321823958b39b438f7b940" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-keyring 39.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-insecure-randomness-collective-flip" version = "16.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "safe-mix", "scale-info", @@ -11975,15 +13855,29 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-insecure-randomness-collective-flip" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce7ad80675d78bd38a7a66ecbbf2d218dd32955e97f8e301d0afe6c87b0f251" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "safe-mix", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-lottery" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", "frame-support-test", - "frame-system", - "pallet-balances", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11991,13 +13885,27 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-lottery" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0920ee53cf7b0665cfb6d275759ae0537dc3850ec78da5f118d814c99d3562" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-membership" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -12006,14 +13914,31 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-membership" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868b5dca4bbfd1f4a222cbb80735a5197020712a71577b496bbb7e19aaa5394" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-message-queue" version = "31.0.0" dependencies = [ "environmental", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "rand", @@ -12029,23 +13954,43 @@ dependencies = [ "sp-weights 27.0.0", ] +[[package]] +name = "pallet-message-queue" +version = "41.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0faa48b29bf5a178580c164ef00de87319a37da7547a9cd6472dfd160092811a" +dependencies = [ + "environmental", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", +] + [[package]] name = "pallet-migrations" version = "1.0.0" dependencies = [ "cfg-if", "docify", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", "parity-scale-codec", "pretty_assertions", "scale-info", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", @@ -12053,12 +13998,30 @@ dependencies = [ "sp-version 29.0.0", ] +[[package]] +name = "pallet-migrations" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b417fc975636bce94e7c6d707e42d0706d67dfa513e72f5946918e1044beef1" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-minimal-template" version = "0.0.0" dependencies = [ "parity-scale-codec", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "scale-info", ] @@ -12066,9 +14029,9 @@ dependencies = [ name = "pallet-mixnet" version = "0.4.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -12076,51 +14039,105 @@ dependencies = [ "sp-application-crypto 30.0.0", "sp-arithmetic 23.0.0", "sp-io 30.0.0", - "sp-mixnet", + "sp-mixnet 0.4.0", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-mixnet" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3fa2b7f759a47f698a403ab40c54bc8935e2969387947224cbdb4e2bc8a28a" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-application-crypto 38.0.0", + "sp-arithmetic 26.0.0", + "sp-io 38.0.0", + "sp-mixnet 0.12.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-mmr" version = "27.0.0" dependencies = [ "array-bytes", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "itertools 0.11.0", "log", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-mmr-primitives", + "sp-mmr-primitives 26.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", ] +[[package]] +name = "pallet-mmr" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6932dfb85f77a57c2d1fdc28a7b3a59ffe23efd8d5bb02dc3039d91347e4a3b" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-mmr-primitives 34.1.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-multisig" version = "28.0.0" dependencies = [ "log", - "pallet-balances", + "pallet-balances 28.0.0", + "parity-scale-codec", + "polkadot-sdk-frame 0.1.0", + "scale-info", +] + +[[package]] +name = "pallet-multisig" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e5099c9a4442efcc1568d88ca1d22d624e81ab96358f99f616c67fbd82532d2" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", "parity-scale-codec", - "polkadot-sdk-frame", "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", ] [[package]] name = "pallet-nft-fractionalization" version = "10.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-assets", - "pallet-balances", - "pallet-nfts", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-nfts 22.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12129,16 +14146,33 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-nft-fractionalization" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168792cf95a32fa3baf9b874efec82a45124da0a79cee1ae3c98a823e6841959" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-assets 40.0.0", + "pallet-nfts 32.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-nfts" version = "22.0.0" dependencies = [ "enumflags2", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12147,23 +14181,52 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-nfts" +version = "32.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e2aad461a0849d7f0471576eeb1fe3151795bcf2ec9e15eca5cca5b9d743b2" +dependencies = [ + "enumflags2", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-nfts-runtime-api" version = "14.0.0" dependencies = [ - "pallet-nfts", + "pallet-nfts 22.0.0", "parity-scale-codec", "sp-api 26.0.0", ] +[[package]] +name = "pallet-nfts-runtime-api" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a1f50c217e19dc50ff586a71eb5915df6a05bc0b25564ea20674c8cd182c1f" +dependencies = [ + "pallet-nfts 32.0.0", + "parity-scale-codec", + "sp-api 34.0.0", +] + [[package]] name = "pallet-nis" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 23.0.0", @@ -12172,12 +14235,28 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-nis" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ac349e119880b7df1a7c4c36d919b33a498d0e9548af3c237365c654ae0c73d" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-node-authorization" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -12186,56 +14265,112 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-node-authorization" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec3133be9e767b8feafbb26edd805824faa59956da008d2dc7fcf4b4720e56" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-nomination-pools" version = "25.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", ] +[[package]] +name = "pallet-nomination-pools" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42906923f9f2b65b22f1211136b57c6878296ba6f6228a075c4442cc1fc1659" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", + "sp-tracing 17.0.1", +] + [[package]] name = "pallet-nomination-pools-benchmarking" version = "26.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", - "pallet-bags-list", - "pallet-balances", - "pallet-delegated-staking", - "pallet-nomination-pools", - "pallet-staking", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-delegated-staking 1.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", - "sp-staking", + "sp-staking 26.0.0", +] + +[[package]] +name = "pallet-nomination-pools-benchmarking" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d2eaca0349bcda923343226b8b64d25a80b67e0a1ebaaa5b0ab1e1b3b225bc" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-bags-list 37.0.0", + "pallet-delegated-staking 5.0.0", + "pallet-nomination-pools 35.0.0", + "pallet-staking 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "sp-runtime-interface 28.0.0", + "sp-staking 36.0.0", ] [[package]] name = "pallet-nomination-pools-fuzzer" version = "2.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "honggfuzz", "log", - "pallet-nomination-pools", + "pallet-nomination-pools 25.0.0", "rand", "sp-io 30.0.0", "sp-runtime 31.0.1", @@ -12246,32 +14381,43 @@ dependencies = [ name = "pallet-nomination-pools-runtime-api" version = "23.0.0" dependencies = [ - "pallet-nomination-pools", + "pallet-nomination-pools 25.0.0", "parity-scale-codec", "sp-api 26.0.0", ] +[[package]] +name = "pallet-nomination-pools-runtime-api" +version = "33.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9e1cb89cc2e6df06ce274a7fc814e5e688aad04c43902a10191fa3d2a56a96" +dependencies = [ + "pallet-nomination-pools 35.0.0", + "parity-scale-codec", + "sp-api 34.0.0", +] + [[package]] name = "pallet-nomination-pools-test-delegate-stake" version = "1.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-bags-list", - "pallet-balances", - "pallet-delegated-staking", - "pallet-nomination-pools", - "pallet-staking", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-delegated-staking 1.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -12280,22 +14426,22 @@ dependencies = [ name = "pallet-nomination-pools-test-transfer-stake" version = "1.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-bags-list", - "pallet-balances", - "pallet-nomination-pools", - "pallet-staking", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-std 14.0.0", "sp-tracing 16.0.0", ] @@ -12304,43 +14450,84 @@ dependencies = [ name = "pallet-offences" version = "27.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "serde", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", +] + +[[package]] +name = "pallet-offences" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c4379cf853465696c1c5c03e7e8ce80aeaca0a6139d698abe9ecb3223fd732a" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", ] [[package]] name = "pallet-offences-benchmarking" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", - "log", - "pallet-babe", - "pallet-balances", - "pallet-grandpa", - "pallet-im-online", - "pallet-offences", - "pallet-session", - "pallet-staking", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-grandpa 28.0.0", + "pallet-im-online 27.0.0", + "pallet-offences 27.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", +] + +[[package]] +name = "pallet-offences-benchmarking" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69aa1b24cdffc3fa8c89cdea32c83f1bf9c1c82a87fa00e57ae4be8e85f5e24f" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-babe 38.0.0", + "pallet-balances 39.0.0", + "pallet-grandpa 38.0.0", + "pallet-im-online 37.0.0", + "pallet-offences 37.0.0", + "pallet-session 38.0.0", + "pallet-staking 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", ] [[package]] @@ -12348,9 +14535,9 @@ name = "pallet-paged-list" version = "0.6.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12359,14 +14546,32 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-paged-list" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e099fb116068836b17ca4232dc52f762b69dc8cd4e33f509372d958de278b0" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-metadata-ir 0.7.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-paged-list-fuzzer" version = "0.1.0" dependencies = [ "arbitrary", - "frame-support", + "frame-support 28.0.0", "honggfuzz", - "pallet-paged-list", + "pallet-paged-list 0.6.0", "sp-io 30.0.0", ] @@ -12375,7 +14580,7 @@ name = "pallet-parachain-template" version = "0.0.0" dependencies = [ "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk-frame 0.1.0", "scale-info", ] @@ -12384,10 +14589,10 @@ name = "pallet-parameters" version = "0.1.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "pallet-example-basic", "parity-scale-codec", "paste", @@ -12398,15 +14603,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-parameters" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9aba424d55e17b2a2bec766a41586eab878137704d4803c04bebd6a4743db7b" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-preimage" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12414,24 +14637,56 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-preimage" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "407828bc48c6193ac076fdf909b2fadcaaecd65f42b0b0a04afe22fe8e563834" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-proxy" version = "28.0.0" dependencies = [ - "pallet-balances", - "pallet-utility", + "pallet-balances 28.0.0", + "pallet-utility 28.0.0", + "parity-scale-codec", + "polkadot-sdk-frame 0.1.0", + "scale-info", +] + +[[package]] +name = "pallet-proxy" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39df395f0dbcf07dafe842916adea3266a87ce36ed87b5132184b6bcd746393" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", "parity-scale-codec", - "polkadot-sdk-frame", "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", ] [[package]] name = "pallet-ranked-collective" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", "parity-scale-codec", @@ -12442,14 +14697,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-ranked-collective" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2b38708feaed202debf1ac6beffaa5e20c99a9825c5ca0991753c2d4eaaf3ac" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-recovery" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12457,18 +14731,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-recovery" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406a116aa6d05f88f3c10d79ff89cf577323680a48abd8e5550efb47317e67fa" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-referenda" version = "28.0.0" dependencies = [ "assert_matches", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-preimage", - "pallet-scheduler", + "pallet-balances 28.0.0", + "pallet-preimage 28.0.0", + "pallet-scheduler 29.0.0", "parity-scale-codec", "scale-info", "serde", @@ -12479,12 +14768,30 @@ dependencies = [ ] [[package]] -name = "pallet-remark" +name = "pallet-referenda" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3008c20531d1730c9b457ae77ecf0e3c9b07aaf8c4f5d798d61ef6f0b9e2d4b" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic 26.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + +[[package]] +name = "pallet-remark" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "serde", @@ -12493,41 +14800,54 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-remark" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e8cae0e20888065ec73dda417325c6ecabf797f4002329484b59c25ecc34d4" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-revive" version = "0.1.0" dependencies = [ "array-bytes", "assert_matches", - "bitflags 1.3.2", - "derive_more", + "derive_more 0.99.17", "environmental", - "ethereum-types", - "frame-benchmarking", - "frame-support", - "frame-system", + "ethereum-types 0.15.1", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex", "hex-literal", "impl-trait-for-tuples", - "jsonrpsee 0.24.3", - "log", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-proxy", - "pallet-revive-fixtures", - "pallet-revive-proc-macro", - "pallet-revive-uapi", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-utility", + "log", + "pallet-balances 28.0.0", + "pallet-proxy 28.0.0", + "pallet-revive-fixtures 0.1.0", + "pallet-revive-proc-macro 0.1.0", + "pallet-revive-uapi 0.1.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "paste", - "polkavm 0.13.0", + "polkavm 0.18.0", "pretty_assertions", "rlp 0.6.1", "scale-info", - "secp256k1", + "secp256k1 0.28.2", "serde", "serde_json", "sp-api 26.0.0", @@ -12538,12 +14858,42 @@ dependencies = [ "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", - "sp-weights 27.0.0", - "staging-xcm", - "staging-xcm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", "subxt-signer", ] +[[package]] +name = "pallet-revive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be02c94dcbadd206a910a244ec19b493aac793eed95e23d37d6699547234569f" +dependencies = [ + "bitflags 1.3.2", + "environmental", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-balances 39.0.0", + "pallet-revive-fixtures 0.2.0", + "pallet-revive-proc-macro 0.1.1", + "pallet-revive-uapi 0.1.1", + "parity-scale-codec", + "paste", + "polkavm 0.10.0", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", +] + [[package]] name = "pallet-revive-eth-rpc" version = "0.1.0" @@ -12551,25 +14901,23 @@ dependencies = [ "anyhow", "clap 4.5.13", "env_logger 0.11.3", + "ethabi", "futures", "hex", - "hex-literal", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", - "pallet-revive", - "pallet-revive-fixtures", + "pallet-revive 0.1.0", + "pallet-revive-fixtures 0.1.0", "parity-scale-codec", "rlp 0.6.1", "sc-cli", "sc-rpc", + "sc-rpc-api", "sc-service", - "scale-info", - "secp256k1", - "serde_json", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-runtime 31.0.1", "sp-weights 27.0.0", + "static_init", "substrate-cli-test-utils", "substrate-prometheus-endpoint", "subxt", @@ -12583,13 +14931,23 @@ name = "pallet-revive-fixtures" version = "0.1.0" dependencies = [ "anyhow", - "frame-system", - "log", - "parity-wasm", - "polkavm-linker 0.14.0", + "polkavm-linker 0.18.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-runtime 31.0.1", + "toml 0.8.12", +] + +[[package]] +name = "pallet-revive-fixtures" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a38c27f1531f36e5327f3084eb24cf1c9dd46b372e030c0169e843ce363105e" +dependencies = [ + "anyhow", + "frame-system 38.0.0", + "parity-wasm", + "polkavm-linker 0.10.0", + "sp-runtime 39.0.2", "tempfile", "toml 0.8.12", ] @@ -12599,35 +14957,65 @@ name = "pallet-revive-mock-network" version = "0.1.0" dependencies = [ "assert_matches", - "frame-support", - "frame-system", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-proxy", - "pallet-revive", - "pallet-revive-fixtures", - "pallet-revive-proc-macro", - "pallet-revive-uapi", - "pallet-timestamp", - "pallet-utility", - "pallet-xcm", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-revive 0.1.0", + "pallet-revive-fixtures 0.1.0", + "pallet-revive-uapi 0.1.0", + "pallet-timestamp 27.0.0", + "pallet-xcm 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", "pretty_assertions", "scale-info", - "sp-api 26.0.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "xcm-simulator", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "xcm-simulator 7.0.0", +] + +[[package]] +name = "pallet-revive-mock-network" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e74591d44dbd78db02c8593f5caa75bd61bcc4d63999302150223fb969ae37" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-assets 40.0.0", + "pallet-balances 39.0.0", + "pallet-message-queue 41.0.1", + "pallet-proxy 38.0.0", + "pallet-revive 0.2.0", + "pallet-revive-proc-macro 0.1.1", + "pallet-revive-uapi 0.1.1", + "pallet-timestamp 37.0.0", + "pallet-utility 38.0.0", + "pallet-xcm 17.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 14.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-parachains 17.0.1", + "scale-info", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", + "sp-tracing 17.0.1", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", + "xcm-simulator 17.0.0", ] [[package]] @@ -12636,7 +15024,18 @@ version = "0.1.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", +] + +[[package]] +name = "pallet-revive-proc-macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc16d1f7cee6a1ee6e8cd710e16230d59fb4935316c1704cf770e4d2335f8d4" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -12644,9 +15043,23 @@ name = "pallet-revive-uapi" version = "0.1.0" dependencies = [ "bitflags 1.3.2", + "pallet-revive-proc-macro 0.1.0", "parity-scale-codec", "paste", - "polkavm-derive 0.14.0", + "polkavm-derive 0.18.0", + "scale-info", +] + +[[package]] +name = "pallet-revive-uapi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb4686c8415619cc13e43fadef146ffff46424d9b4d037fe4c069de52708aac" +dependencies = [ + "bitflags 1.3.2", + "parity-scale-codec", + "paste", + "polkavm-derive 0.10.0", "scale-info", ] @@ -12654,29 +15067,45 @@ dependencies = [ name = "pallet-root-offences" version = "25.0.0" dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-session", - "pallet-staking", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-std 14.0.0", ] +[[package]] +name = "pallet-root-offences" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35774b830928daaeeca7196cead7c56eeed952a6616ad6dc5ec068d8c85c81a" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-session 38.0.0", + "pallet-staking 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-root-testing" version = "4.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12684,17 +15113,32 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-root-testing" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be95e7c320ac1d381715364cd721e67ab3152ab727f8e4defd3a92e41ebbc880" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-safe-mode" version = "9.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-proxy", - "pallet-utility", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-proxy 28.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 23.0.0", @@ -12703,15 +15147,34 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-safe-mode" +version = "19.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3e67dd4644c168cedbf257ac3dd2527aad81acf4a0d413112197094e549f76" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-balances 39.0.0", + "pallet-proxy 38.0.0", + "pallet-utility 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-salary" version = "13.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-ranked-collective", + "pallet-ranked-collective 28.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 23.0.0", @@ -12720,14 +15183,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-salary" +version = "23.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0544a71dba06a9a29da0778ba8cb37728c3b9a8377ac9737c4b1bc48c618bc2f" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-ranked-collective 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-sassafras" version = "0.3.5-dev" dependencies = [ "array-bytes", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -12743,11 +15225,11 @@ name = "pallet-scheduler" version = "29.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-preimage", + "pallet-preimage 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12757,13 +15239,31 @@ dependencies = [ "substrate-test-utils", ] +[[package]] +name = "pallet-scheduler" +version = "39.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26899a331e7ab5f7d5966cbf203e1cf5bd99cd110356d7ddcaa7597087cdc0b5" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", +] + [[package]] name = "pallet-scored-pool" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", - "pallet-balances", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12771,69 +15271,135 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-scored-pool" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f84b48bb4702712c902f43931c4077d3a1cb6773c8d8c290d4a6251f6bc2a5c" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-session" version = "28.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", "sp-state-machine 0.35.0", "sp-trie 29.0.0", ] +[[package]] +name = "pallet-session" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8474b62b6b7622f891e83d922a589e2ad5be5471f5ca47d45831a797dba0b3f4" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-timestamp 37.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-staking 36.0.0", + "sp-state-machine 0.43.0", + "sp-trie 37.0.0", +] + [[package]] name = "pallet-session-benchmarking" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-session", - "pallet-staking", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "rand", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", +] + +[[package]] +name = "pallet-session-benchmarking" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aadce7df0fee981721983795919642648b846dab5ab9096f82c2cea781007d0" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-session 38.0.0", + "pallet-staking 38.0.0", + "parity-scale-codec", + "rand", + "sp-runtime 39.0.2", + "sp-session 36.0.0", ] [[package]] name = "pallet-skip-feeless-payment" version = "3.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-skip-feeless-payment" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c2cb0dae13d2c2d2e76373f337d408468f571459df1900cbd7458f21cf6c01" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-society" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", "frame-support-test", - "frame-system", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "rand_chacha", "scale-info", @@ -12844,21 +15410,39 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-society" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1dc69fea8a8de343e71691f009d5fece6ae302ed82b7bb357882b2ea6454143" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "rand_chacha", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-staking" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-authorship", - "pallet-bags-list", - "pallet-balances", - "pallet-session", + "pallet-authorship 28.0.0", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-session 28.0.0", "pallet-staking-reward-curve", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "rand_chacha", "scale-info", @@ -12866,13 +15450,35 @@ dependencies = [ "sp-application-crypto 30.0.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", "substrate-test-utils", ] +[[package]] +name = "pallet-staking" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c870d123f4f053b56af808a4beae1ffc4309a696e829796c26837936c926db3b" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-authorship 38.0.0", + "pallet-session 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-application-crypto 38.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", +] + [[package]] name = "pallet-staking-reward-curve" version = "11.0.0" @@ -12881,7 +15487,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-runtime 31.0.1", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -12892,25 +15498,46 @@ dependencies = [ "sp-arithmetic 23.0.0", ] +[[package]] +name = "pallet-staking-reward-fn" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "988a7ebeacc84d4bdb0b12409681e956ffe35438447d8f8bc78db547cffb6ebc" +dependencies = [ + "log", + "sp-arithmetic 26.0.0", +] + [[package]] name = "pallet-staking-runtime-api" version = "14.0.0" dependencies = [ "parity-scale-codec", "sp-api 26.0.0", - "sp-staking", + "sp-staking 26.0.0", +] + +[[package]] +name = "pallet-staking-runtime-api" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7298559ef3a6b2f5dfbe9a3b8f3d22f2ff9b073c97f4c4853d2b316d973e72d" +dependencies = [ + "parity-scale-codec", + "sp-api 34.0.0", + "sp-staking 36.0.0", ] [[package]] name = "pallet-state-trie-migration" version = "29.0.0" dependencies = [ - "frame-benchmarking", + "frame-benchmarking 28.0.0", "frame-remote-externalities", - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "parking_lot 0.12.3", "scale-info", @@ -12925,21 +15552,56 @@ dependencies = [ "zstd 0.12.4", ] +[[package]] +name = "pallet-state-trie-migration" +version = "40.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138c15b4200b9dc4c3e031def6a865a235cdc76ff91ee96fba19ca1787c9dda6" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-statement" version = "10.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-api 26.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", +] + +[[package]] +name = "pallet-statement" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e03e147efa900e75cd106337f36da3d7dcd185bd9e5f5c3df474c08c3c37d16" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-statement-store 18.0.0", ] [[package]] @@ -12947,9 +15609,9 @@ name = "pallet-sudo" version = "28.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -12957,66 +15619,121 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-sudo" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1574fe2aed3d52db4a389b77b53d8c9758257b121e3e7bbe24c4904e11681e0e" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-template" version = "0.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", +] + +[[package]] +name = "pallet-timestamp" +version = "27.0.0" +dependencies = [ + "docify", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", "parity-scale-codec", "scale-info", "sp-core 28.0.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", + "sp-storage 19.0.0", + "sp-timestamp 26.0.0", +] + +[[package]] +name = "pallet-timestamp" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ba9b71bbfd33ae672f23ba7efaeed2755fdac37b8f946cb7474fc37841b7e1" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-storage 21.0.0", + "sp-timestamp 34.0.0", ] [[package]] -name = "pallet-timestamp" +name = "pallet-tips" version = "27.0.0" dependencies = [ - "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", + "pallet-balances 28.0.0", + "pallet-treasury 27.0.0", "parity-scale-codec", "scale-info", + "serde", "sp-core 28.0.0", - "sp-inherents", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-storage 19.0.0", - "sp-timestamp", ] [[package]] name = "pallet-tips" -version = "27.0.0" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1d4371a70c309ba11624933f8f5262fe4edad0149c556361d31f26190da936" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", "log", - "pallet-balances", - "pallet-treasury", + "pallet-treasury 37.0.0", "parity-scale-codec", "scale-info", "serde", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-storage 19.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", ] [[package]] name = "pallet-transaction-payment" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "serde", @@ -13026,12 +15743,28 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-transaction-payment" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b1aa3498107a30237f941b0f02180db3b79012c3488878ff01a4ac3e8ee04e" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-transaction-payment-rpc" version = "30.0.0" dependencies = [ - "jsonrpsee 0.24.3", - "pallet-transaction-payment-rpc-runtime-api", + "jsonrpsee", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", "parity-scale-codec", "sp-api 26.0.0", "sp-blockchain", @@ -13045,31 +15778,64 @@ dependencies = [ name = "pallet-transaction-payment-rpc-runtime-api" version = "28.0.0" dependencies = [ - "pallet-transaction-payment", + "pallet-transaction-payment 28.0.0", "parity-scale-codec", "sp-api 26.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", ] +[[package]] +name = "pallet-transaction-payment-rpc-runtime-api" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fdf5ab71e9dbcadcf7139736b6ea6bac8ec4a83985d46cbd130e1eec770e41" +dependencies = [ + "pallet-transaction-payment 38.0.0", + "parity-scale-codec", + "sp-api 34.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", +] + [[package]] name = "pallet-transaction-storage" version = "27.0.0" dependencies = [ "array-bytes", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "serde", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-transaction-storage-proof", + "sp-transaction-storage-proof 26.0.0", +] + +[[package]] +name = "pallet-transaction-storage" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c337a972a6a796c0a0acc6c03b5e02901c43ad721ce79eb87b45717d75c93b" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-transaction-storage-proof 34.0.0", ] [[package]] @@ -13077,13 +15843,13 @@ name = "pallet-treasury" version = "27.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-balances", - "pallet-utility", + "pallet-balances 28.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "scale-info", "serde", @@ -13092,17 +15858,36 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-treasury" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98bfdd3bb9b58fb010bcd419ff5bf940817a8e404cdbf7886a53ac730f5dda2b" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-tx-pause" version = "9.0.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-proxy", - "pallet-utility", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-proxy 28.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -13110,15 +15895,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-tx-pause" +version = "19.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee153f5be5efc84ebd53aa581e5361cde17dc3669ef80d8ad327f4041d89ebe" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-balances 39.0.0", + "pallet-proxy 38.0.0", + "pallet-utility 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-uniques" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -13127,17 +15930,32 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-uniques" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2b13cdaedf2d5bd913a5f6e637cb52b5973d8ed4b8d45e56d921bc4d627006f" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-utility" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-collective", - "pallet-root-testing", - "pallet-timestamp", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-collective 28.0.0", + "pallet-root-testing 4.0.0", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -13145,17 +15963,33 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-utility" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fdcade6efc0b66fc7fc4138964802c02d0ffb7380d894e26b9dd5073727d2b3" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-verify-signature" version = "1.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-collective", - "pallet-root-testing", - "pallet-timestamp", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-collective 28.0.0", + "pallet-root-testing 4.0.0", + "pallet-timestamp 27.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -13168,11 +16002,11 @@ dependencies = [ name = "pallet-vesting" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -13180,15 +16014,30 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-vesting" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "807df2ef13ab6bf940879352c3013bfa00b670458b4c125c2f60e5753f68e3d5" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-whitelist" version = "27.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-preimage", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-preimage 28.0.0", "parity-scale-codec", "scale-info", "sp-api 26.0.0", @@ -13197,88 +16046,170 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "pallet-whitelist" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef17df925290865cf37096dd0cb76f787df11805bba01b1d0ca3e106d06280b" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "pallet-xcm" version = "7.0.0" dependencies = [ "bounded-collections", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-assets", - "pallet-balances", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "serde", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", "tracing", - "xcm-runtime-apis", + "xcm-runtime-apis 0.1.0", +] + +[[package]] +name = "pallet-xcm" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1760b6589e53f4ad82216c72c0e38fcb4df149c37224ab3301dc240c85d1d4" +dependencies = [ + "bounded-collections", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", + "xcm-runtime-apis 0.4.0", ] [[package]] name = "pallet-xcm-benchmarks" version = "7.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-assets", - "pallet-balances", - "pallet-xcm", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-primitives", - "polkadot-runtime-common", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", "scale-info", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "pallet-xcm-benchmarks" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da423463933b42f4a4c74175f9e9295a439de26719579b894ce533926665e4a" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", ] [[package]] name = "pallet-xcm-bridge-hub" version = "0.2.0" dependencies = [ - "bp-header-chain", - "bp-messages", - "bp-runtime", - "bp-xcm-bridge-hub", - "frame-support", - "frame-system", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-runtime 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "bp-xcm-bridge-hub-router 0.6.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-bridge-messages", - "pallet-xcm-bridge-hub-router", + "pallet-balances 28.0.0", + "pallet-bridge-messages 0.7.0", + "pallet-xcm-bridge-hub-router 0.5.0", "parity-scale-codec", - "polkadot-parachain-primitives", + "polkadot-parachain-primitives 6.0.0", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "pallet-xcm-bridge-hub" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f9670065b7cba92771060a4a3925b6650ff67611443ccfccd5aa356f7d5aac" +dependencies = [ + "bp-messages 0.18.0", + "bp-runtime 0.18.0", + "bp-xcm-bridge-hub 0.4.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-bridge-messages 0.18.0", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", ] [[package]] name = "pallet-xcm-bridge-hub-router" version = "0.5.0" dependencies = [ - "bp-xcm-bridge-hub-router", - "frame-benchmarking", - "frame-support", - "frame-system", + "bp-xcm-bridge-hub-router 0.6.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -13286,8 +16217,28 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", +] + +[[package]] +name = "pallet-xcm-bridge-hub-router" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b5347c826b721098ef39afb0d750e621c77538044fc1e865af1a8747824fdf" +dependencies = [ + "bp-xcm-bridge-hub-router 0.14.1", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -13298,11 +16249,11 @@ dependencies = [ "color-print", "docify", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parachain-template-runtime", "parity-scale-codec", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "sc-tracing", "serde", "serde_json", @@ -13313,46 +16264,77 @@ dependencies = [ name = "parachain-template-runtime" version = "0.0.0" dependencies = [ - "cumulus-pallet-parachain-system", + "cumulus-pallet-parachain-system 0.7.0", "docify", "hex-literal", "log", "pallet-parachain-template", "parity-scale-codec", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "scale-info", "serde_json", "smallvec", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] name = "parachains-common" version = "7.0.0" dependencies = [ - "cumulus-primitives-core", - "cumulus-primitives-utility", - "frame-support", - "frame-system", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-utility 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-xcm", + "pallet-asset-tx-payment 28.0.0", + "pallet-assets 29.1.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "scale-info", - "sp-consensus-aura", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-executor", - "substrate-wasm-builder", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", +] + +[[package]] +name = "parachains-common" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9460a69f409be27c62161d8b4d36ffc32735d09a4f9097f9c789db0cca7196c" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "cumulus-primitives-utility 0.17.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-asset-tx-payment 38.0.0", + "pallet-assets 40.0.0", + "pallet-authorship 38.0.0", + "pallet-balances 39.0.0", + "pallet-collator-selection 19.0.0", + "pallet-message-queue 41.0.1", + "pallet-xcm 17.0.0", + "parity-scale-codec", + "polkadot-primitives 16.0.0", + "scale-info", + "sp-consensus-aura 0.40.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "staging-parachain-info 0.17.0", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", + "substrate-wasm-builder 24.0.1", ] [[package]] @@ -13361,7 +16343,7 @@ version = "0.1.0" dependencies = [ "async-std", "async-trait", - "bp-polkadot-core", + "bp-polkadot-core 0.7.0", "futures", "log", "parity-scale-codec", @@ -13374,30 +16356,63 @@ dependencies = [ name = "parachains-runtimes-test-utils" version = "7.0.0" dependencies = [ - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-test-relay-sproof-builder", - "frame-support", - "frame-system", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-parachain-inherent 0.7.0", + "cumulus-test-relay-sproof-builder 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex-literal", - "pallet-balances", - "pallet-collator-selection", - "pallet-session", - "pallet-timestamp", - "pallet-xcm", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "sp-consensus-aura", + "polkadot-parachain-primitives 6.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-executor", - "substrate-wasm-builder", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "xcm-runtime-apis 0.1.0", +] + +[[package]] +name = "parachains-runtimes-test-utils" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287d2db0a2d19466caa579a69f021bfdc6fa352f382c8395dade58d1d0c6adfe" +dependencies = [ + "cumulus-pallet-parachain-system 0.17.1", + "cumulus-pallet-xcmp-queue 0.17.0", + "cumulus-primitives-core 0.16.0", + "cumulus-primitives-parachain-inherent 0.16.0", + "cumulus-test-relay-sproof-builder 0.16.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-balances 39.0.0", + "pallet-collator-selection 19.0.0", + "pallet-session 38.0.0", + "pallet-timestamp 37.0.0", + "pallet-xcm 17.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 14.0.0", + "sp-consensus-aura 0.40.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-tracing 17.0.1", + "staging-parachain-info 0.17.0", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", + "substrate-wasm-builder 24.0.1", ] [[package]] @@ -13466,6 +16481,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parity-util-mem" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" +dependencies = [ + "cfg-if", + "ethereum-types 0.14.1", + "hashbrown 0.12.3", + "impl-trait-for-tuples", + "lru 0.8.1", + "parity-util-mem-derive", + "parking_lot 0.12.3", + "primitive-types 0.12.2", + "smallvec", + "winapi", +] + +[[package]] +name = "parity-util-mem-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" +dependencies = [ + "proc-macro2 1.0.86", + "syn 1.0.109", + "synstructure 0.12.6", +] + [[package]] name = "parity-wasm" version = "0.45.0" @@ -13556,6 +16600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", + "hmac 0.12.1", "password-hash", ] @@ -13588,210 +16633,213 @@ dependencies = [ name = "penpal-emulated-chain" version = "0.0.0" dependencies = [ - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "penpal-runtime", "sp-core 28.0.0", - "sp-keyring", - "staging-xcm", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", ] [[package]] name = "penpal-runtime" version = "0.14.0" dependencies = [ - "assets-common", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "assets-common 0.7.0", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-asset-conversion", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-common", + "pallet-asset-conversion 10.0.0", + "pallet-asset-tx-payment 28.0.0", + "pallet-assets 29.1.0", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-session 28.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", "primitive-types 0.12.2", "scale-info", "smallvec", + "snowbridge-router-primitives 0.9.0", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "people-rococo-emulated-chain" version = "0.1.0" dependencies = [ - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "people-rococo-runtime", "sp-core 28.0.0", - "testnet-parachains-constants", + "testnet-parachains-constants 1.0.0", ] [[package]] name = "people-rococo-integration-tests" version = "0.1.0" dependencies = [ - "asset-test-utils", + "asset-test-utils 7.0.0", "emulated-integration-tests-common", - "frame-support", - "pallet-balances", - "pallet-identity", - "pallet-message-queue", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "rococo-runtime-constants", + "frame-support 28.0.0", + "pallet-balances 28.0.0", + "pallet-identity 29.0.0", + "pallet-message-queue 31.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-runtime-common 7.0.0", + "rococo-runtime-constants 7.0.0", "rococo-system-emulated-network", "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", ] [[package]] name = "people-rococo-runtime" version = "0.1.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", "enumflags2", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-identity", - "pallet-message-queue", - "pallet-migrations", - "pallet-multisig", - "pallet-proxy", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "rococo-runtime-constants", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-identity 29.0.0", + "pallet-message-queue 31.0.0", + "pallet-migrations 1.0.0", + "pallet-multisig 28.0.0", + "pallet-proxy 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", + "rococo-runtime-constants 7.0.0", "scale-info", "serde", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "people-westend-emulated-chain" version = "0.1.0" dependencies = [ - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "emulated-integration-tests-common", - "frame-support", - "parachains-common", + "frame-support 28.0.0", + "parachains-common 7.0.0", "people-westend-runtime", "sp-core 28.0.0", - "testnet-parachains-constants", + "testnet-parachains-constants 1.0.0", ] [[package]] name = "people-westend-integration-tests" version = "0.1.0" dependencies = [ - "asset-test-utils", + "asset-test-utils 7.0.0", "emulated-integration-tests-common", - "frame-support", - "pallet-balances", - "pallet-identity", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "sp-runtime 31.0.1", - "staging-xcm", - "staging-xcm-executor", - "westend-runtime-constants", + "frame-support 28.0.0", + "pallet-balances 28.0.0", + "pallet-identity 29.0.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-runtime-common 7.0.0", + "sp-runtime 31.0.1", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "westend-runtime", + "westend-runtime-constants 7.0.0", "westend-system-emulated-network", ] @@ -13799,67 +16847,68 @@ dependencies = [ name = "people-westend-runtime" version = "0.1.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", "enumflags2", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-identity", - "pallet-message-queue", - "pallet-migrations", - "pallet-multisig", - "pallet-proxy", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-identity 29.0.0", + "pallet-message-queue 31.0.0", + "pallet-migrations 1.0.0", + "pallet-multisig 28.0.0", + "pallet-proxy 28.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "scale-info", "serde", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", - "westend-runtime-constants", - "xcm-runtime-apis", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -13898,7 +16947,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -13919,27 +16968,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.7.0", ] [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -14010,9 +17059,9 @@ version = "6.0.0" dependencies = [ "assert_cmd", "color-eyre", - "nix 0.28.0", + "nix 0.29.0", "polkadot-cli", - "polkadot-core-primitives", + "polkadot-core-primitives 7.0.0", "polkadot-node-core-pvf", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", @@ -14041,7 +17090,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "rand", "rand_chacha", @@ -14049,7 +17098,7 @@ dependencies = [ "sc-keystore", "schnorrkel 0.11.4", "sp-application-crypto 30.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-core 28.0.0", "sp-tracing 16.0.0", "tracing-gum", @@ -14069,13 +17118,13 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "rand", "rand_chacha", "sp-application-crypto 30.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", "tracing-gum", @@ -14086,7 +17135,7 @@ name = "polkadot-availability-distribution" version = "7.0.0" dependencies = [ "assert_matches", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "futures-timer", @@ -14097,7 +17146,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", "rand", @@ -14105,7 +17154,7 @@ dependencies = [ "sc-network", "schnellru", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", @@ -14129,7 +17178,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", "rand", @@ -14138,7 +17187,7 @@ dependencies = [ "schnellru", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-tracing 16.0.0", "thiserror", "tokio", @@ -14177,7 +17226,7 @@ dependencies = [ "sc-tracing", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-maybe-compressed-blob 11.0.0", "sp-runtime 31.0.1", "substrate-build-script-utils", @@ -14199,14 +17248,14 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "rstest", "sc-keystore", "sc-network", "schnellru", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", @@ -14225,6 +17274,18 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "polkadot-core-primitives" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2900d3b857e34c480101618a950c3a4fbcddc8c0d50573d48553376185908b8" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "polkadot-dispute-distribution" version = "7.0.0" @@ -14232,11 +17293,11 @@ dependencies = [ "assert_matches", "async-channel 1.9.0", "async-trait", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.7.0", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -14244,13 +17305,13 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sc-keystore", "sc-network", "schnellru", "sp-application-crypto 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", @@ -14264,7 +17325,7 @@ dependencies = [ "criterion", "parity-scale-codec", "polkadot-node-primitives", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "quickcheck", "reed-solomon-novelpoly", "sp-core 28.0.0", @@ -14285,18 +17346,18 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "quickcheck", "rand", "rand_chacha", "sc-network", "sc-network-common", "sp-application-crypto 30.0.0", - "sp-authority-discovery", - "sp-consensus-babe", + "sp-authority-discovery 26.0.0", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", "tracing-gum", @@ -14321,12 +17382,12 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sc-network", "sp-consensus", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "thiserror", "tracing-gum", ] @@ -14343,12 +17404,12 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "rstest", "schnellru", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-maybe-compressed-blob 11.0.0", "thiserror", "tracing-gum", @@ -14361,7 +17422,7 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "derive_more", + "derive_more 0.99.17", "futures", "futures-timer", "itertools 0.11.0", @@ -14376,7 +17437,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", "rand", @@ -14387,10 +17448,10 @@ dependencies = [ "schnorrkel 0.11.4", "sp-application-crypto 30.0.0", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-slots", + "sp-consensus-babe 0.32.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", @@ -14419,7 +17480,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", "rand", @@ -14429,10 +17490,10 @@ dependencies = [ "schnorrkel 0.11.4", "sp-application-crypto 30.0.0", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-slots", + "sp-consensus-babe 0.32.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", @@ -14459,11 +17520,11 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sp-consensus", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-tracing 16.0.0", "thiserror", "tracing-gum", @@ -14482,8 +17543,8 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-statement-table", "rstest", @@ -14491,7 +17552,7 @@ dependencies = [ "schnellru", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", @@ -14506,7 +17567,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sp-keystore 0.34.0", "thiserror", @@ -14530,13 +17591,13 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "rstest", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-maybe-compressed-blob 11.0.0", "tracing-gum", @@ -14554,7 +17615,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-types", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-client-api", "sc-consensus-babe", "sp-blockchain", @@ -14577,7 +17638,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sp-core 28.0.0", "thiserror", "tracing-gum", @@ -14598,13 +17659,13 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sc-keystore", "schnellru", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", @@ -14620,9 +17681,9 @@ dependencies = [ "futures-timer", "polkadot-node-subsystem", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sp-blockchain", - "sp-inherents", + "sp-inherents 26.0.0", "thiserror", "tracing-gum", ] @@ -14637,7 +17698,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "rand", "rstest", @@ -14659,7 +17720,7 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "rstest", "schnellru", @@ -14686,7 +17747,7 @@ dependencies = [ "libc", "parity-scale-codec", "pin-project", - "polkadot-core-primitives", + "polkadot-core-primitives 7.0.0", "polkadot-node-core-pvf", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", @@ -14694,13 +17755,15 @@ dependencies = [ "polkadot-node-metrics", "polkadot-node-primitives", "polkadot-node-subsystem", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-node-subsystem-test-helpers", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "procfs", "rand", "rococo-runtime", "rusty-fork", "sc-sysinfo", + "sc-tracing", "slotmap", "sp-core 28.0.0", "sp-maybe-compressed-blob 11.0.0", @@ -14724,12 +17787,12 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sc-keystore", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "thiserror", @@ -14745,10 +17808,10 @@ dependencies = [ "futures", "landlock", "libc", - "nix 0.28.0", + "nix 0.29.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "sc-executor 0.32.0", "sc-executor-common 0.29.0", "sc-executor-wasmtime 0.29.0", @@ -14770,12 +17833,12 @@ dependencies = [ "cfg-if", "cpu-time", "libc", - "nix 0.28.0", + "nix 0.29.0", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-node-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "sp-maybe-compressed-blob 11.0.0", "tracing-gum", ] @@ -14788,11 +17851,11 @@ dependencies = [ "cfg-if", "criterion", "libc", - "nix 0.28.0", + "nix 0.29.0", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-node-primitives", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "rayon", "rococo-runtime", "sc-executor-common 0.29.0", @@ -14815,13 +17878,13 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-types", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "schnellru", "sp-api 26.0.0", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "tracing-gum", ] @@ -14838,14 +17901,14 @@ dependencies = [ "hyper-util", "log", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-test-service", "prioritized-metered-channel", "prometheus-parse", "sc-cli", "sc-service", "sc-tracing", - "sp-keyring", + "sp-keyring 31.0.0", "substrate-prometheus-endpoint", "substrate-test-utils", "tempfile", @@ -14860,13 +17923,13 @@ dependencies = [ "async-channel 1.9.0", "async-trait", "bitvec", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "hex", "parity-scale-codec", "polkadot-node-primitives", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "rand", "rand_chacha", "sc-authority-discovery", @@ -14888,14 +17951,14 @@ dependencies = [ "futures-timer", "parity-scale-codec", "polkadot-erasure-coding", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "sc-keystore", "schnorrkel 0.11.4", "serde", "sp-application-crypto 30.0.0", - "sp-consensus-babe", - "sp-consensus-slots", + "sp-consensus-babe 0.32.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", "sp-keystore 0.34.0", "sp-maybe-compressed-blob 11.0.0", @@ -14923,13 +17986,13 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-client-api", "sc-keystore", "sc-utils", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", ] @@ -14939,13 +18002,13 @@ version = "7.0.0" dependencies = [ "async-trait", "bitvec", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "orchestra", "polkadot-node-network-protocol", "polkadot-node-primitives", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-statement-table", "sc-client-api", "sc-network", @@ -14953,11 +18016,10 @@ dependencies = [ "sc-transaction-pool-api", "smallvec", "sp-api 26.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-blockchain", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-runtime 31.0.1", - "strum 0.26.3", "substrate-prometheus-endpoint", "thiserror", ] @@ -14968,7 +18030,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "futures-channel", @@ -14989,7 +18051,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-types", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "prioritized-metered-channel", "rand", @@ -15028,27 +18090,28 @@ dependencies = [ "cumulus-client-consensus-relay-chain", "cumulus-client-parachain-inherent", "cumulus-client-service", - "cumulus-primitives-aura", - "cumulus-primitives-core", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", "cumulus-relay-chain-interface", + "cumulus-test-runtime", "docify", - "frame-benchmarking", + "frame-benchmarking 28.0.0", "frame-benchmarking-cli", - "frame-support", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-support 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", - "nix 0.28.0", - "pallet-transaction-payment", + "nix 0.29.0", + "pallet-transaction-payment 28.0.0", "pallet-transaction-payment-rpc", - "pallet-transaction-payment-rpc-runtime-api", - "parachains-common", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "parachains-common 7.0.0", "parity-scale-codec", "polkadot-cli", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-basic-authorship", "sc-chain-spec", "sc-cli", @@ -15059,29 +18122,35 @@ dependencies = [ "sc-executor 0.32.0", "sc-network", "sc-rpc", + "sc-runtime-utilities", "sc-service", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", + "scale-info", "serde", "serde_json", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-crypto-hashing 0.1.0", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-session", - "sp-timestamp", - "sp-transaction-pool", + "sp-session 27.0.0", + "sp-storage 19.0.0", + "sp-timestamp 26.0.0", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", "sp-weights 27.0.0", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-state-trie-migration-rpc", + "subxt-metadata", "tokio", "wait-timeout", ] @@ -15102,7 +18171,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-types", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "prioritized-metered-channel", "sc-client-api", @@ -15125,11 +18194,11 @@ dependencies = [ "contracts-rococo-runtime", "coretime-rococo-runtime", "coretime-westend-runtime", - "cumulus-primitives-core", + "cumulus-primitives-core 0.7.0", "glutton-westend-runtime", "hex-literal", "log", - "parachains-common", + "parachains-common 7.0.0", "penpal-runtime", "people-rococo-runtime", "people-westend-runtime", @@ -15141,9 +18210,9 @@ dependencies = [ "serde", "serde_json", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-keyring", - "staging-xcm", + "sp-genesis-builder 0.8.0", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", "substrate-build-script-utils", ] @@ -15152,9 +18221,9 @@ name = "polkadot-parachain-primitives" version = "6.0.0" dependencies = [ "bounded-collections", - "derive_more", + "derive_more 0.99.17", "parity-scale-codec", - "polkadot-core-primitives", + "polkadot-core-primitives 7.0.0", "scale-info", "serde", "sp-core 28.0.0", @@ -15162,6 +18231,23 @@ dependencies = [ "sp-weights 27.0.0", ] +[[package]] +name = "polkadot-parachain-primitives" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5648a2e8ce1f9a0f8c41c38def670cefd91932cd793468e1a5b0b0b4e4af1" +dependencies = [ + "bounded-collections", + "derive_more 0.99.17", + "parity-scale-codec", + "polkadot-core-primitives 15.0.0", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", +] + [[package]] name = "polkadot-primitives" version = "7.0.0" @@ -15170,35 +18256,89 @@ dependencies = [ "hex-literal", "log", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives-test-helpers", + "polkadot-core-primitives 7.0.0", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives-test-helpers", + "scale-info", + "serde", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", + "sp-authority-discovery 26.0.0", + "sp-consensus-slots 0.32.0", + "sp-core 28.0.0", + "sp-inherents 26.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-staking 26.0.0", + "sp-std 14.0.0", + "thiserror", +] + +[[package]] +name = "polkadot-primitives" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b57bc055fa389372ec5fc0001b99aeffd50f3fd379280ce572d935189bb58dd8" +dependencies = [ + "bitvec", + "hex-literal", + "log", + "parity-scale-codec", + "polkadot-core-primitives 15.0.0", + "polkadot-parachain-primitives 14.0.0", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-arithmetic 26.0.0", + "sp-authority-discovery 34.0.0", + "sp-consensus-slots 0.40.1", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", + "sp-staking 34.0.0", +] + +[[package]] +name = "polkadot-primitives" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb20b75d33212150242d39890d7ededab55f1084160c337f15d0eb8ca8c3ad4" +dependencies = [ + "bitvec", + "hex-literal", + "log", + "parity-scale-codec", + "polkadot-core-primitives 15.0.0", + "polkadot-parachain-primitives 14.0.0", "scale-info", "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-arithmetic 23.0.0", - "sp-authority-discovery", - "sp-consensus-slots", - "sp-core 28.0.0", - "sp-inherents", - "sp-io 30.0.0", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", - "sp-staking", - "sp-std 14.0.0", - "thiserror", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-arithmetic 26.0.0", + "sp-authority-discovery 34.0.0", + "sp-consensus-slots 0.40.1", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", ] [[package]] name = "polkadot-primitives-test-helpers" version = "1.0.0" dependencies = [ - "polkadot-primitives", + "polkadot-primitives 7.0.0", "rand", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", ] @@ -15206,10 +18346,10 @@ dependencies = [ name = "polkadot-rpc" version = "7.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "mmr-rpc", "pallet-transaction-payment-rpc", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sc-chain-spec", "sc-client-api", "sc-consensus-babe", @@ -15225,11 +18365,11 @@ dependencies = [ "sc-transaction-pool-api", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-beefy", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "substrate-frame-rpc-system", @@ -15241,53 +18381,103 @@ name = "polkadot-runtime-common" version = "7.0.0" dependencies = [ "bitvec", - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-support 28.0.0", "frame-support-test", - "frame-system", + "frame-system 28.0.0", "hex-literal", "impl-trait-for-tuples", "libsecp256k1", "log", - "pallet-asset-rate", - "pallet-authorship", - "pallet-babe", - "pallet-balances", - "pallet-broker", - "pallet-election-provider-multi-phase", - "pallet-fast-unstake", - "pallet-identity", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-fn", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-treasury", - "pallet-vesting", - "parity-scale-codec", - "polkadot-primitives", + "pallet-asset-rate 7.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-election-provider-multi-phase 27.0.0", + "pallet-fast-unstake 27.0.0", + "pallet-identity 29.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", + "pallet-staking-reward-fn 19.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-treasury 27.0.0", + "pallet-vesting 28.0.0", + "parity-scale-codec", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", - "polkadot-runtime-parachains", + "polkadot-runtime-parachains 7.0.0", "rustc-hex", "scale-info", "serde", "serde_derive", "serde_json", - "slot-range-helper", + "slot-range-helper 7.0.0", "sp-api 26.0.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "sp-session 27.0.0", + "sp-staking 26.0.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "static_assertions", +] + +[[package]] +name = "polkadot-runtime-common" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc15154ba5ca55d323fcf7af0f5dcd39d58dcb4dfac3d9b30404840a6d8bbde4" +dependencies = [ + "bitvec", + "frame-benchmarking 38.0.0", + "frame-election-provider-support 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "libsecp256k1", + "log", + "pallet-asset-rate 17.0.0", + "pallet-authorship 38.0.0", + "pallet-balances 39.0.0", + "pallet-broker 0.17.0", + "pallet-election-provider-multi-phase 37.0.0", + "pallet-fast-unstake 37.0.0", + "pallet-identity 38.0.0", + "pallet-session 38.0.0", + "pallet-staking 38.0.0", + "pallet-staking-reward-fn 22.0.0", + "pallet-timestamp 37.0.0", + "pallet-transaction-payment 38.0.0", + "pallet-treasury 37.0.0", + "pallet-vesting 38.0.0", + "parity-scale-codec", + "polkadot-primitives 16.0.0", + "polkadot-runtime-parachains 17.0.1", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "slot-range-helper 15.0.0", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-npos-elections 34.0.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-staking 36.0.0", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", "static_assertions", ] @@ -15296,12 +18486,25 @@ name = "polkadot-runtime-metrics" version = "7.0.0" dependencies = [ "bs58", - "frame-benchmarking", + "frame-benchmarking 28.0.0", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sp-tracing 16.0.0", ] +[[package]] +name = "polkadot-runtime-metrics" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c306f1ace7644a24de860479f92cf8d6467393bb0c9b0777c57e2d42c9d452a" +dependencies = [ + "bs58", + "frame-benchmarking 38.0.0", + "parity-scale-codec", + "polkadot-primitives 16.0.0", + "sp-tracing 17.0.1", +] + [[package]] name = "polkadot-runtime-parachains" version = "7.0.0" @@ -15309,32 +18512,32 @@ dependencies = [ "assert_matches", "bitflags 1.3.2", "bitvec", - "derive_more", - "frame-benchmarking", - "frame-support", + "derive_more 0.99.17", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", "frame-support-test", - "frame-system", + "frame-system 28.0.0", "futures", "hex-literal", "impl-trait-for-tuples", "log", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-balances", - "pallet-broker", - "pallet-message-queue", - "pallet-mmr", - "pallet-session", - "pallet-staking", - "pallet-timestamp", - "pallet-vesting", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", + "pallet-authority-discovery 28.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-message-queue 31.0.0", + "pallet-mmr 27.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-vesting 28.0.0", + "parity-scale-codec", + "polkadot-core-primitives 7.0.0", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", - "polkadot-runtime-metrics", + "polkadot-runtime-metrics 7.0.0", "rand", "rand_chacha", "rstest", @@ -15347,41 +18550,90 @@ dependencies = [ "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", "sp-std 14.0.0", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", "static_assertions", "thousands", ] +[[package]] +name = "polkadot-runtime-parachains" +version = "17.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd58e3a17e5df678f5737b018cbfec603af2c93bec56bbb9f8fb8b2b017b54b1" +dependencies = [ + "bitflags 1.3.2", + "bitvec", + "derive_more 0.99.17", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-authority-discovery 38.0.0", + "pallet-authorship 38.0.0", + "pallet-babe 38.0.0", + "pallet-balances 39.0.0", + "pallet-broker 0.17.0", + "pallet-message-queue 41.0.1", + "pallet-mmr 38.0.0", + "pallet-session 38.0.0", + "pallet-staking 38.0.0", + "pallet-timestamp 37.0.0", + "pallet-vesting 38.0.0", + "parity-scale-codec", + "polkadot-core-primitives 15.0.0", + "polkadot-parachain-primitives 14.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-metrics 17.0.0", + "rand", + "rand_chacha", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-staking 36.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", +] + [[package]] name = "polkadot-sdk" version = "0.1.0" dependencies = [ - "asset-test-utils", - "assets-common", - "binary-merkle-tree", - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", - "bp-test-utils", - "bp-xcm-bridge-hub", - "bp-xcm-bridge-hub-router", - "bridge-hub-common", - "bridge-hub-test-utils", - "bridge-runtime-common", + "asset-test-utils 7.0.0", + "assets-common 0.7.0", + "binary-merkle-tree 13.0.0", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot 0.5.0", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", + "bp-runtime 0.7.0", + "bp-test-utils 0.7.0", + "bp-xcm-bridge-hub 0.2.0", + "bp-xcm-bridge-hub-router 0.6.0", + "bridge-hub-common 0.1.0", + "bridge-hub-test-utils 0.7.0", + "bridge-runtime-common 0.7.0", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", @@ -15392,168 +18644,167 @@ dependencies = [ "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", - "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-parachain-system-proc-macro", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-solo-to-para", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-ping", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-primitives-proof-size-hostfunction", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-timestamp", - "cumulus-primitives-utility", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-dmp-queue 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-parachain-system-proc-macro 0.6.0", + "cumulus-pallet-session-benchmarking 9.0.0", + "cumulus-pallet-solo-to-para 0.7.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-ping 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-parachain-inherent 0.7.0", + "cumulus-primitives-proof-size-hostfunction 0.2.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-timestamp 0.7.0", + "cumulus-primitives-utility 0.7.0", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", - "cumulus-test-relay-sproof-builder", + "cumulus-test-relay-sproof-builder 0.7.0", "emulated-integration-tests-common", "fork-tree", - "frame-benchmarking", + "frame-benchmarking 28.0.0", "frame-benchmarking-cli", - "frame-benchmarking-pallet-pov", - "frame-election-provider-solution-type", - "frame-election-provider-support", - "frame-executive", - "frame-metadata-hash-extension", + "frame-benchmarking-pallet-pov 18.0.0", + "frame-election-provider-solution-type 13.0.0", + "frame-election-provider-support 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", "frame-remote-externalities", - "frame-support", - "frame-support-procedural", - "frame-support-procedural-tools", - "frame-support-procedural-tools-derive", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-support 28.0.0", + "frame-support-procedural 23.0.0", + "frame-support-procedural-tools 10.0.0", + "frame-support-procedural-tools-derive 11.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "generate-bags", "mmr-gadget", "mmr-rpc", - "pallet-alliance", - "pallet-asset-conversion", - "pallet-asset-conversion-ops", - "pallet-asset-conversion-tx-payment", - "pallet-asset-rate", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-assets-freezer", - "pallet-atomic-swap", - "pallet-aura", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-bags-list", - "pallet-balances", - "pallet-beefy", - "pallet-beefy-mmr", - "pallet-bounties", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-bridge-relayers", - "pallet-broker", - "pallet-child-bounties", - "pallet-collator-selection", - "pallet-collective", - "pallet-collective-content", - "pallet-contracts", - "pallet-contracts-mock-network", - "pallet-contracts-proc-macro", - "pallet-contracts-uapi", - "pallet-conviction-voting", - "pallet-core-fellowship", - "pallet-delegated-staking", - "pallet-democracy", - "pallet-dev-mode", - "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", - "pallet-fast-unstake", - "pallet-glutton", - "pallet-grandpa", - "pallet-identity", - "pallet-im-online", - "pallet-indices", - "pallet-insecure-randomness-collective-flip", - "pallet-lottery", - "pallet-membership", - "pallet-message-queue", - "pallet-migrations", - "pallet-mixnet", - "pallet-mmr", - "pallet-multisig", - "pallet-nft-fractionalization", - "pallet-nfts", - "pallet-nfts-runtime-api", - "pallet-nis", - "pallet-node-authorization", - "pallet-nomination-pools", - "pallet-nomination-pools-benchmarking", - "pallet-nomination-pools-runtime-api", - "pallet-offences", - "pallet-offences-benchmarking", - "pallet-paged-list", - "pallet-parameters", - "pallet-preimage", - "pallet-proxy", - "pallet-ranked-collective", - "pallet-recovery", - "pallet-referenda", - "pallet-remark", - "pallet-revive", + "pallet-alliance 27.0.0", + "pallet-asset-conversion 10.0.0", + "pallet-asset-conversion-ops 0.1.0", + "pallet-asset-conversion-tx-payment 10.0.0", + "pallet-asset-rate 7.0.0", + "pallet-asset-tx-payment 28.0.0", + "pallet-assets 29.1.0", + "pallet-assets-freezer 0.1.0", + "pallet-atomic-swap 28.0.0", + "pallet-aura 27.0.0", + "pallet-authority-discovery 28.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-beefy 28.0.0", + "pallet-beefy-mmr 28.0.0", + "pallet-bounties 27.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-bridge-relayers 0.7.0", + "pallet-broker 0.6.0", + "pallet-child-bounties 27.0.0", + "pallet-collator-selection 9.0.0", + "pallet-collective 28.0.0", + "pallet-collective-content 0.6.0", + "pallet-contracts 27.0.0", + "pallet-contracts-mock-network 3.0.0", + "pallet-contracts-proc-macro 18.0.0", + "pallet-contracts-uapi 5.0.0", + "pallet-conviction-voting 28.0.0", + "pallet-core-fellowship 12.0.0", + "pallet-delegated-staking 1.0.0", + "pallet-democracy 28.0.0", + "pallet-dev-mode 10.0.0", + "pallet-election-provider-multi-phase 27.0.0", + "pallet-election-provider-support-benchmarking 27.0.0", + "pallet-elections-phragmen 29.0.0", + "pallet-fast-unstake 27.0.0", + "pallet-glutton 14.0.0", + "pallet-grandpa 28.0.0", + "pallet-identity 29.0.0", + "pallet-im-online 27.0.0", + "pallet-indices 28.0.0", + "pallet-insecure-randomness-collective-flip 16.0.0", + "pallet-lottery 28.0.0", + "pallet-membership 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-migrations 1.0.0", + "pallet-mixnet 0.4.0", + "pallet-mmr 27.0.0", + "pallet-multisig 28.0.0", + "pallet-nft-fractionalization 10.0.0", + "pallet-nfts 22.0.0", + "pallet-nfts-runtime-api 14.0.0", + "pallet-nis 28.0.0", + "pallet-node-authorization 28.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-nomination-pools-benchmarking 26.0.0", + "pallet-nomination-pools-runtime-api 23.0.0", + "pallet-offences 27.0.0", + "pallet-offences-benchmarking 28.0.0", + "pallet-paged-list 0.6.0", + "pallet-parameters 0.1.0", + "pallet-preimage 28.0.0", + "pallet-proxy 28.0.0", + "pallet-ranked-collective 28.0.0", + "pallet-recovery 28.0.0", + "pallet-referenda 28.0.0", + "pallet-remark 28.0.0", + "pallet-revive 0.1.0", "pallet-revive-eth-rpc", - "pallet-revive-fixtures", - "pallet-revive-mock-network", - "pallet-revive-proc-macro", - "pallet-revive-uapi", - "pallet-root-offences", - "pallet-root-testing", - "pallet-safe-mode", - "pallet-salary", - "pallet-scheduler", - "pallet-scored-pool", - "pallet-session", - "pallet-session-benchmarking", - "pallet-skip-feeless-payment", - "pallet-society", - "pallet-staking", + "pallet-revive-mock-network 0.1.0", + "pallet-revive-proc-macro 0.1.0", + "pallet-revive-uapi 0.1.0", + "pallet-root-offences 25.0.0", + "pallet-root-testing 4.0.0", + "pallet-safe-mode 9.0.0", + "pallet-salary 13.0.0", + "pallet-scheduler 29.0.0", + "pallet-scored-pool 28.0.0", + "pallet-session 28.0.0", + "pallet-session-benchmarking 28.0.0", + "pallet-skip-feeless-payment 3.0.0", + "pallet-society 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-staking-reward-fn", - "pallet-staking-runtime-api", - "pallet-state-trie-migration", - "pallet-statement", - "pallet-sudo", - "pallet-timestamp", - "pallet-tips", - "pallet-transaction-payment", + "pallet-staking-reward-fn 19.0.0", + "pallet-staking-runtime-api 14.0.0", + "pallet-state-trie-migration 29.0.0", + "pallet-statement 10.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-tips 27.0.0", + "pallet-transaction-payment 28.0.0", "pallet-transaction-payment-rpc", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-transaction-storage", - "pallet-treasury", - "pallet-tx-pause", - "pallet-uniques", - "pallet-utility", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-transaction-storage 27.0.0", + "pallet-treasury 27.0.0", + "pallet-tx-pause 9.0.0", + "pallet-uniques 28.0.0", + "pallet-utility 28.0.0", "pallet-verify-signature", - "pallet-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub", - "pallet-xcm-bridge-hub-router", - "parachains-common", - "parachains-runtimes-test-utils", + "pallet-vesting 28.0.0", + "pallet-whitelist 27.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "pallet-xcm-bridge-hub 0.2.0", + "pallet-xcm-bridge-hub-router 0.5.0", + "parachains-common 7.0.0", + "parachains-runtimes-test-utils 7.0.0", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", - "polkadot-core-primitives", + "polkadot-core-primitives 7.0.0", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", @@ -15585,13 +18836,13 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-rpc", - "polkadot-runtime-common", - "polkadot-runtime-metrics", - "polkadot-runtime-parachains", - "polkadot-sdk-frame", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-metrics 7.0.0", + "polkadot-runtime-parachains 7.0.0", + "polkadot-sdk-frame 0.1.0", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", @@ -15637,6 +18888,7 @@ dependencies = [ "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", + "sc-runtime-utilities", "sc-service", "sc-state-db", "sc-statement-store", @@ -15649,38 +18901,38 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", - "slot-range-helper", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-ethereum", - "snowbridge-outbound-queue-merkle-tree", - "snowbridge-outbound-queue-runtime-api", - "snowbridge-pallet-ethereum-client", - "snowbridge-pallet-ethereum-client-fixtures", - "snowbridge-pallet-inbound-queue", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", - "snowbridge-runtime-common", - "snowbridge-runtime-test-common", - "snowbridge-system-runtime-api", + "slot-range-helper 7.0.0", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", + "snowbridge-ethereum 0.3.0", + "snowbridge-outbound-queue-merkle-tree 0.3.0", + "snowbridge-outbound-queue-runtime-api 0.2.0", + "snowbridge-pallet-ethereum-client 0.2.0", + "snowbridge-pallet-ethereum-client-fixtures 0.9.0", + "snowbridge-pallet-inbound-queue 0.2.0", + "snowbridge-pallet-inbound-queue-fixtures 0.10.0", + "snowbridge-pallet-outbound-queue 0.2.0", + "snowbridge-pallet-system 0.2.0", + "snowbridge-router-primitives 0.9.0", + "snowbridge-runtime-common 0.2.0", + "snowbridge-runtime-test-common 0.2.0", + "snowbridge-system-runtime-api 0.2.0", "sp-api 26.0.0", "sp-api-proc-macro 15.0.0", "sp-application-crypto 30.0.0", "sp-arithmetic 23.0.0", - "sp-authority-discovery", - "sp-block-builder", + "sp-authority-discovery 26.0.0", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-aura", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-consensus-grandpa", - "sp-consensus-pow", - "sp-consensus-slots", - "sp-core 28.0.0", - "sp-core-hashing", + "sp-consensus-aura 0.32.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", + "sp-consensus-grandpa 13.0.0", + "sp-consensus-pow 0.32.0", + "sp-consensus-slots 0.32.0", + "sp-core 28.0.0", + "sp-core-hashing 15.0.0", "sp-core-hashing-proc-macro", "sp-crypto-ec-utils 0.10.0", "sp-crypto-hashing 0.1.0", @@ -15688,32 +18940,32 @@ dependencies = [ "sp-database", "sp-debug-derive 14.0.0", "sp-externalities 0.25.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-maybe-compressed-blob 11.0.0", "sp-metadata-ir 0.6.0", - "sp-mixnet", - "sp-mmr-primitives", - "sp-npos-elections", - "sp-offchain", + "sp-mixnet 0.4.0", + "sp-mmr-primitives 26.0.0", + "sp-npos-elections 26.0.0", + "sp-offchain 26.0.0", "sp-panic-handler 13.0.0", "sp-rpc", "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-runtime-interface-proc-macro 17.0.0", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", "sp-state-machine 0.35.0", - "sp-statement-store", + "sp-statement-store 10.0.0", "sp-std 14.0.0", "sp-storage 19.0.0", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", - "sp-transaction-pool", - "sp-transaction-storage-proof", + "sp-transaction-pool 26.0.0", + "sp-transaction-storage-proof 26.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", "sp-version-proc-macro 13.0.0", @@ -15721,11 +18973,11 @@ dependencies = [ "sp-weights 27.0.0", "staging-chain-spec-builder", "staging-node-inspect", - "staging-parachain-info", + "staging-parachain-info 0.7.0", "staging-tracking-allocator", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", "subkey", "substrate-bip39 0.4.7", "substrate-build-script-utils", @@ -15734,14 +18986,246 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", - "substrate-wasm-builder", - "testnet-parachains-constants", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", "tracing-gum", "tracing-gum-proc-macro", "xcm-emulator", - "xcm-procedural", - "xcm-runtime-apis", - "xcm-simulator", + "xcm-procedural 7.0.0", + "xcm-runtime-apis 0.1.0", + "xcm-simulator 7.0.0", +] + +[[package]] +name = "polkadot-sdk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb819108697967452fa6d8d96ab4c0d48cbaa423b3156499dcb24f1cf95d6775" +dependencies = [ + "asset-test-utils 18.0.0", + "assets-common 0.18.0", + "binary-merkle-tree 15.0.1", + "bp-header-chain 0.18.1", + "bp-messages 0.18.0", + "bp-parachains 0.18.0", + "bp-polkadot 0.16.0", + "bp-polkadot-core 0.18.0", + "bp-relayers 0.18.0", + "bp-runtime 0.18.0", + "bp-test-utils 0.18.0", + "bp-xcm-bridge-hub 0.4.0", + "bp-xcm-bridge-hub-router 0.14.1", + "bridge-hub-common 0.10.0", + "bridge-hub-test-utils 0.18.0", + "bridge-runtime-common 0.18.0", + "cumulus-pallet-aura-ext 0.17.0", + "cumulus-pallet-dmp-queue 0.17.0", + "cumulus-pallet-parachain-system 0.17.1", + "cumulus-pallet-parachain-system-proc-macro 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cumulus-pallet-session-benchmarking 19.0.0", + "cumulus-pallet-solo-to-para 0.17.0", + "cumulus-pallet-xcm 0.17.0", + "cumulus-pallet-xcmp-queue 0.17.0", + "cumulus-ping 0.17.0", + "cumulus-primitives-aura 0.15.0", + "cumulus-primitives-core 0.16.0", + "cumulus-primitives-parachain-inherent 0.16.0", + "cumulus-primitives-proof-size-hostfunction 0.10.0", + "cumulus-primitives-storage-weight-reclaim 8.0.0", + "cumulus-primitives-timestamp 0.16.0", + "cumulus-primitives-utility 0.17.0", + "cumulus-test-relay-sproof-builder 0.16.0", + "frame-benchmarking 38.0.0", + "frame-benchmarking-pallet-pov 28.0.0", + "frame-election-provider-support 38.0.0", + "frame-executive 38.0.0", + "frame-metadata-hash-extension 0.6.0", + "frame-support 38.0.0", + "frame-support-procedural 30.0.4", + "frame-system 38.0.0", + "frame-system-benchmarking 38.0.0", + "frame-system-rpc-runtime-api 34.0.0", + "frame-try-runtime 0.44.0", + "pallet-alliance 37.0.0", + "pallet-asset-conversion 20.0.0", + "pallet-asset-conversion-ops 0.6.0", + "pallet-asset-conversion-tx-payment 20.0.0", + "pallet-asset-rate 17.0.0", + "pallet-asset-tx-payment 38.0.0", + "pallet-assets 40.0.0", + "pallet-assets-freezer 0.5.0", + "pallet-atomic-swap 38.0.0", + "pallet-aura 37.0.0", + "pallet-authority-discovery 38.0.0", + "pallet-authorship 38.0.0", + "pallet-babe 38.0.0", + "pallet-bags-list 37.0.0", + "pallet-balances 39.0.0", + "pallet-beefy 39.0.0", + "pallet-beefy-mmr 39.0.0", + "pallet-bounties 37.0.0", + "pallet-bridge-grandpa 0.18.0", + "pallet-bridge-messages 0.18.0", + "pallet-bridge-parachains 0.18.0", + "pallet-bridge-relayers 0.18.0", + "pallet-broker 0.17.0", + "pallet-child-bounties 37.0.0", + "pallet-collator-selection 19.0.0", + "pallet-collective 38.0.0", + "pallet-collective-content 0.16.0", + "pallet-contracts 38.0.0", + "pallet-contracts-mock-network 14.0.0", + "pallet-conviction-voting 38.0.0", + "pallet-core-fellowship 22.0.0", + "pallet-delegated-staking 5.0.0", + "pallet-democracy 38.0.0", + "pallet-dev-mode 20.0.0", + "pallet-election-provider-multi-phase 37.0.0", + "pallet-election-provider-support-benchmarking 37.0.0", + "pallet-elections-phragmen 39.0.0", + "pallet-fast-unstake 37.0.0", + "pallet-glutton 24.0.0", + "pallet-grandpa 38.0.0", + "pallet-identity 38.0.0", + "pallet-im-online 37.0.0", + "pallet-indices 38.0.0", + "pallet-insecure-randomness-collective-flip 26.0.0", + "pallet-lottery 38.0.0", + "pallet-membership 38.0.0", + "pallet-message-queue 41.0.1", + "pallet-migrations 8.0.0", + "pallet-mixnet 0.14.0", + "pallet-mmr 38.0.0", + "pallet-multisig 38.0.0", + "pallet-nft-fractionalization 21.0.0", + "pallet-nfts 32.0.0", + "pallet-nfts-runtime-api 24.0.0", + "pallet-nis 38.0.0", + "pallet-node-authorization 38.0.0", + "pallet-nomination-pools 35.0.0", + "pallet-nomination-pools-benchmarking 36.0.0", + "pallet-nomination-pools-runtime-api 33.0.0", + "pallet-offences 37.0.0", + "pallet-offences-benchmarking 38.0.0", + "pallet-paged-list 0.16.0", + "pallet-parameters 0.9.0", + "pallet-preimage 38.0.0", + "pallet-proxy 38.0.0", + "pallet-ranked-collective 38.0.0", + "pallet-recovery 38.0.0", + "pallet-referenda 38.0.0", + "pallet-remark 38.0.0", + "pallet-revive 0.2.0", + "pallet-revive-fixtures 0.2.0", + "pallet-revive-mock-network 0.2.0", + "pallet-root-offences 35.0.0", + "pallet-root-testing 14.0.0", + "pallet-safe-mode 19.0.0", + "pallet-salary 23.0.0", + "pallet-scheduler 39.0.0", + "pallet-scored-pool 38.0.0", + "pallet-session 38.0.0", + "pallet-session-benchmarking 38.0.0", + "pallet-skip-feeless-payment 13.0.0", + "pallet-society 38.0.0", + "pallet-staking 38.0.0", + "pallet-staking-reward-fn 22.0.0", + "pallet-staking-runtime-api 24.0.0", + "pallet-state-trie-migration 40.0.0", + "pallet-statement 20.0.0", + "pallet-sudo 38.0.0", + "pallet-timestamp 37.0.0", + "pallet-tips 37.0.0", + "pallet-transaction-payment 38.0.0", + "pallet-transaction-payment-rpc-runtime-api 38.0.0", + "pallet-transaction-storage 37.0.0", + "pallet-treasury 37.0.0", + "pallet-tx-pause 19.0.0", + "pallet-uniques 38.0.0", + "pallet-utility 38.0.0", + "pallet-vesting 38.0.0", + "pallet-whitelist 37.0.0", + "pallet-xcm 17.0.0", + "pallet-xcm-benchmarks 17.0.0", + "pallet-xcm-bridge-hub 0.13.0", + "pallet-xcm-bridge-hub-router 0.15.1", + "parachains-common 18.0.0", + "parachains-runtimes-test-utils 17.0.0", + "polkadot-core-primitives 15.0.0", + "polkadot-parachain-primitives 14.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-common 17.0.0", + "polkadot-runtime-metrics 17.0.0", + "polkadot-runtime-parachains 17.0.1", + "polkadot-sdk-frame 0.7.0", + "sc-executor 0.40.1", + "slot-range-helper 15.0.0", + "snowbridge-beacon-primitives 0.10.0", + "snowbridge-core 0.10.0", + "snowbridge-ethereum 0.9.0", + "snowbridge-outbound-queue-merkle-tree 0.9.1", + "snowbridge-outbound-queue-runtime-api 0.10.0", + "snowbridge-pallet-ethereum-client 0.10.0", + "snowbridge-pallet-ethereum-client-fixtures 0.18.0", + "snowbridge-pallet-inbound-queue 0.10.0", + "snowbridge-pallet-inbound-queue-fixtures 0.18.0", + "snowbridge-pallet-outbound-queue 0.10.0", + "snowbridge-pallet-system 0.10.0", + "snowbridge-router-primitives 0.16.0", + "snowbridge-runtime-common 0.10.0", + "snowbridge-runtime-test-common 0.10.0", + "snowbridge-system-runtime-api 0.10.0", + "sp-api 34.0.0", + "sp-api-proc-macro 20.0.0", + "sp-application-crypto 38.0.0", + "sp-arithmetic 26.0.0", + "sp-authority-discovery 34.0.0", + "sp-block-builder 34.0.0", + "sp-consensus-aura 0.40.0", + "sp-consensus-babe 0.40.0", + "sp-consensus-beefy 22.1.0", + "sp-consensus-grandpa 21.0.0", + "sp-consensus-pow 0.40.0", + "sp-consensus-slots 0.40.1", + "sp-core 34.0.0", + "sp-core-hashing 16.0.0", + "sp-crypto-ec-utils 0.14.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.29.0", + "sp-genesis-builder 0.15.1", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-keyring 39.0.0", + "sp-keystore 0.40.0", + "sp-metadata-ir 0.7.0", + "sp-mixnet 0.12.0", + "sp-mmr-primitives 34.1.0", + "sp-npos-elections 34.0.0", + "sp-offchain 34.0.0", + "sp-runtime 39.0.2", + "sp-runtime-interface 28.0.0", + "sp-session 36.0.0", + "sp-staking 36.0.0", + "sp-state-machine 0.43.0", + "sp-statement-store 18.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", + "sp-timestamp 34.0.0", + "sp-tracing 17.0.1", + "sp-transaction-pool 34.0.0", + "sp-transaction-storage-proof 34.0.0", + "sp-trie 37.0.0", + "sp-version 37.0.0", + "sp-wasm-interface 21.0.1", + "sp-weights 31.0.0", + "staging-parachain-info 0.17.0", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", + "substrate-bip39 0.6.0", + "testnet-parachains-constants 10.0.0", + "xcm-runtime-apis 0.4.0", ] [[package]] @@ -15750,56 +19234,57 @@ version = "0.0.1" dependencies = [ "assert_cmd", "chain-spec-guide-runtime", + "cmd_lib", "cumulus-client-service", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-primitives-proof-size-hostfunction", - "cumulus-primitives-storage-weight-reclaim", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-primitives-proof-size-hostfunction 0.2.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", "docify", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "kitchensink-runtime", "log", "minimal-template-runtime", - "pallet-asset-conversion-tx-payment", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-aura", - "pallet-authorship", - "pallet-babe", - "pallet-balances", - "pallet-broker", - "pallet-collective", - "pallet-contracts", + "pallet-asset-conversion-tx-payment 10.0.0", + "pallet-asset-tx-payment 28.0.0", + "pallet-assets 29.1.0", + "pallet-aura 27.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-broker 0.6.0", + "pallet-collective 28.0.0", + "pallet-contracts 27.0.0", "pallet-default-config-example", - "pallet-democracy", + "pallet-democracy 28.0.0", "pallet-example-authorization-tx-extension", "pallet-example-offchain-worker", "pallet-example-single-block-migrations", "pallet-examples", - "pallet-grandpa", - "pallet-multisig", - "pallet-nfts", - "pallet-preimage", - "pallet-proxy", - "pallet-referenda", - "pallet-scheduler", - "pallet-skip-feeless-payment", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-uniques", - "pallet-utility", - "pallet-xcm", + "pallet-grandpa 28.0.0", + "pallet-multisig 28.0.0", + "pallet-nfts 22.0.0", + "pallet-preimage 28.0.0", + "pallet-proxy 28.0.0", + "pallet-referenda 28.0.0", + "pallet-scheduler 29.0.0", + "pallet-skip-feeless-payment 3.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-uniques 28.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", "parachain-template-runtime", "parity-scale-codec", "polkadot-omni-node-lib", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "polkadot-sdk-docs-first-pallet", "polkadot-sdk-docs-first-runtime", - "polkadot-sdk-frame", + "polkadot-sdk-frame 0.1.0", "rand", "sc-chain-spec", "sc-cli", @@ -15822,10 +19307,10 @@ dependencies = [ "sp-api 26.0.0", "sp-arithmetic 23.0.0", "sp-core 28.0.0", - "sp-genesis-builder", + "sp-genesis-builder 0.8.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-std 14.0.0", @@ -15834,14 +19319,14 @@ dependencies = [ "sp-weights 27.0.0", "staging-chain-spec-builder", "staging-node-cli", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", "subkey", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", "xcm-docs", - "xcm-simulator", + "xcm-simulator 7.0.0", ] [[package]] @@ -15850,7 +19335,7 @@ version = "0.0.0" dependencies = [ "docify", "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk-frame 0.1.0", "scale-info", ] @@ -15859,18 +19344,18 @@ name = "polkadot-sdk-docs-first-runtime" version = "0.0.0" dependencies = [ "docify", - "pallet-balances", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", + "pallet-balances 28.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", "parity-scale-codec", "polkadot-sdk-docs-first-pallet", - "polkadot-sdk-frame", + "polkadot-sdk-frame 0.1.0", "scale-info", "serde_json", - "sp-keyring", - "substrate-wasm-builder", + "sp-keyring 31.0.0", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -15878,54 +19363,87 @@ name = "polkadot-sdk-frame" version = "0.1.0" dependencies = [ "docify", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "log", "pallet-examples", "parity-scale-codec", "scale-info", "sp-api 26.0.0", "sp-arithmetic 23.0.0", - "sp-block-builder", - "sp-consensus-aura", - "sp-consensus-grandpa", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", ] +[[package]] +name = "polkadot-sdk-frame" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdeb15ce08142082461afe1a62c15f7ce10a731d91b203ad6a8dc8d2e4a6a54" +dependencies = [ + "docify", + "frame-benchmarking 38.0.0", + "frame-executive 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "frame-system-benchmarking 38.0.0", + "frame-system-rpc-runtime-api 34.0.0", + "frame-try-runtime 0.44.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-arithmetic 26.0.0", + "sp-block-builder 34.0.0", + "sp-consensus-aura 0.40.0", + "sp-consensus-grandpa 21.0.0", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-io 38.0.0", + "sp-offchain 34.0.0", + "sp-runtime 39.0.2", + "sp-session 36.0.0", + "sp-storage 21.0.0", + "sp-transaction-pool 34.0.0", + "sp-version 37.0.0", +] + [[package]] name = "polkadot-service" version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "frame-benchmarking", + "frame-benchmarking 28.0.0", "frame-benchmarking-cli", - "frame-metadata-hash-extension", - "frame-system", - "frame-system-rpc-runtime-api", + "frame-metadata-hash-extension 0.1.0", + "frame-system 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", "futures", "is_executable", "kvdb", "kvdb-rocksdb", "log", "mmr-gadget", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", "parity-db", "parity-scale-codec", "parking_lot 0.12.3", @@ -15934,7 +19452,7 @@ dependencies = [ "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-collator-protocol", - "polkadot-core-primitives", + "polkadot-core-primitives 7.0.0", "polkadot-dispute-distribution", "polkadot-gossip-support", "polkadot-network-bridge", @@ -15961,14 +19479,14 @@ dependencies = [ "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-rpc", - "polkadot-runtime-parachains", + "polkadot-runtime-parachains 7.0.0", "polkadot-statement-distribution", "polkadot-test-client", "rococo-runtime", - "rococo-runtime-constants", + "rococo-runtime-constants 7.0.0", "sc-authority-discovery", "sc-basic-authorship", "sc-chain-spec", @@ -15991,37 +19509,36 @@ dependencies = [ "sc-transaction-pool-api", "serde", "serde_json", - "serial_test", "sp-api 26.0.0", - "sp-authority-discovery", - "sp-block-builder", + "sp-authority-discovery 26.0.0", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-consensus-grandpa", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-mmr-primitives", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-mmr-primitives 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-timestamp", + "sp-session 27.0.0", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", "sp-weights 27.0.0", - "staging-xcm", + "staging-xcm 7.0.0", "substrate-prometheus-endpoint", "tempfile", "thiserror", "tracing-gum", "westend-runtime", - "westend-runtime-constants", - "xcm-runtime-apis", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -16035,25 +19552,26 @@ dependencies = [ "fatality", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.7.0", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-subsystem-bench", "rand_chacha", + "rstest", "sc-keystore", "sc-network", "sp-application-crypto 30.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", - "sp-staking", + "sp-staking 26.0.0", "sp-tracing 16.0.0", "thiserror", "tracing-gum", @@ -16064,7 +19582,7 @@ name = "polkadot-statement-table" version = "7.0.0" dependencies = [ "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "sp-core 28.0.0", "tracing-gum", ] @@ -16108,7 +19626,7 @@ dependencies = [ "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-service", "polkadot-statement-distribution", @@ -16130,12 +19648,12 @@ dependencies = [ "sha1", "sp-application-crypto 30.0.0", "sp-consensus", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "strum 0.26.3", "substrate-prometheus-endpoint", @@ -16148,11 +19666,11 @@ dependencies = [ name = "polkadot-test-client" version = "1.0.0" dependencies = [ - "frame-benchmarking", + "frame-benchmarking 28.0.0", "futures", "parity-scale-codec", "polkadot-node-subsystem", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "polkadot-test-runtime", "polkadot-test-service", "sc-block-builder", @@ -16162,14 +19680,14 @@ dependencies = [ "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "sp-timestamp", + "sp-timestamp 26.0.0", "substrate-test-client", ] @@ -16197,7 +19715,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "rand", "sp-core 28.0.0", "sp-keystore 0.34.0", @@ -16209,58 +19727,58 @@ dependencies = [ name = "polkadot-test-runtime" version = "1.0.0" dependencies = [ - "frame-election-provider-support", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", + "frame-election-provider-support 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", "hex-literal", "log", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-balances", - "pallet-grandpa", - "pallet-indices", - "pallet-offences", - "pallet-session", - "pallet-staking", + "pallet-authority-discovery 28.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-grandpa 28.0.0", + "pallet-indices 28.0.0", + "pallet-offences 27.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", "pallet-staking-reward-curve", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-vesting", - "pallet-xcm", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-vesting 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-runtime-parachains", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "serde", "serde_json", "sp-api 26.0.0", - "sp-authority-discovery", - "sp-block-builder", - "sp-consensus-babe", - "sp-consensus-beefy", + "sp-authority-discovery 26.0.0", + "sp-block-builder 26.0.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-mmr-primitives", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-mmr-primitives 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", - "sp-transaction-pool", + "sp-session 27.0.0", + "sp-staking 26.0.0", + "sp-transaction-pool 26.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", "test-runtime-constants", "tiny-keccak", ] @@ -16269,20 +19787,20 @@ dependencies = [ name = "polkadot-test-service" version = "1.0.0" dependencies = [ - "frame-system", + "frame-system 28.0.0", "futures", "hex", - "pallet-balances", - "pallet-staking", - "pallet-transaction-payment", + "pallet-balances 28.0.0", + "pallet-staking 28.0.0", + "pallet-transaction-payment 28.0.0", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-rpc", - "polkadot-runtime-common", - "polkadot-runtime-parachains", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", "polkadot-service", "polkadot-test-runtime", "rand", @@ -16299,14 +19817,14 @@ dependencies = [ "sc-transaction-pool", "serde_json", "sp-arithmetic 23.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-grandpa", + "sp-consensus-babe 0.32.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", - "sp-inherents", - "sp-keyring", + "sp-inherents 26.0.0", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "substrate-test-client", @@ -16360,15 +19878,28 @@ dependencies = [ [[package]] name = "polkavm" -version = "0.13.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ec0c5935f2eff23cfc4653002f4f8d12b37f87a720e0631282d188c32089d6" +dependencies = [ + "libc", + "log", + "polkavm-assembler 0.10.0", + "polkavm-common 0.10.0", + "polkavm-linux-raw 0.10.0", +] + +[[package]] +name = "polkavm" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e79a14b15ed38cb5b9a1e38d02e933f19e3d180ae5b325fed606c5e5b9177e" +checksum = "dd044ab1d3b11567ab6b98ca71259a992b4034220d5972988a0e96518e5d343d" dependencies = [ "libc", "log", - "polkavm-assembler 0.13.0", - "polkavm-common 0.13.0", - "polkavm-linux-raw 0.13.0", + "polkavm-assembler 0.18.0", + "polkavm-common 0.18.0", + "polkavm-linux-raw 0.18.0", ] [[package]] @@ -16382,9 +19913,18 @@ dependencies = [ [[package]] name = "polkavm-assembler" -version = "0.13.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e4fd5a43100bf1afe9727b8130d01f966f5cfc9144d5604b21e795c2bcd80e" +dependencies = [ + "log", +] + +[[package]] +name = "polkavm-assembler" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8da55465000feb0a61bbf556ed03024db58f3420eca37721fc726b3b2136bf" +checksum = "eaad38dc420bfed79e6f731471c973ce5ff5e47ab403e63cf40358fef8a6368f" dependencies = [ "log", ] @@ -16406,19 +19946,23 @@ dependencies = [ [[package]] name = "polkavm-common" -version = "0.13.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084b4339aae7dfdaaa5aa7d634110afd95970e0737b6fb2a0cb10db8b56b753c" +checksum = "0097b48bc0bedf9f3f537ce8f37e8f1202d8d83f9b621bdb21ff2c59b9097c50" dependencies = [ "log", - "polkavm-assembler 0.13.0", + "polkavm-assembler 0.10.0", ] [[package]] name = "polkavm-common" -version = "0.14.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711952a783e9c5ad407cdacb1ed147f36d37c5d43417c1091d86456d2999417b" +checksum = "31ff33982a807d8567645d4784b9b5d7ab87bcb494f534a57cadd9012688e102" +dependencies = [ + "log", + "polkavm-assembler 0.18.0", +] [[package]] name = "polkavm-derive" @@ -16440,11 +19984,20 @@ dependencies = [ [[package]] name = "polkavm-derive" -version = "0.14.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dcc701385c08c31bdb0569f0c51a290c580d892fa77f1dd88a7352a62679ecf" +dependencies = [ + "polkavm-derive-impl-macro 0.10.0", +] + +[[package]] +name = "polkavm-derive" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4832a0aebf6cefc988bb7b2d74ea8c86c983164672e2fc96300f356a1babfc1" +checksum = "c2eb703f3b6404c13228402e98a5eae063fd16b8f58afe334073ec105ee4117e" dependencies = [ - "polkavm-derive-impl-macro 0.14.0", + "polkavm-derive-impl-macro 0.18.0", ] [[package]] @@ -16456,7 +20009,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16468,19 +20021,31 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] name = "polkavm-derive-impl" -version = "0.14.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7855353a5a783dd5d09e3b915474bddf66575f5a3cf45dec8d1c5e051ba320dc" +dependencies = [ + "polkavm-common 0.10.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e339fc7c11310fe5adf711d9342278ac44a75c9784947937cce12bd4f30842f2" +checksum = "12d2840cc62a0550156b1676fed8392271ddf2fab4a00661db56231424674624" dependencies = [ - "polkavm-common 0.14.0", + "polkavm-common 0.18.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16490,7 +20055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16500,17 +20065,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] name = "polkavm-derive-impl-macro" -version = "0.14.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9324fe036de37c17829af233b46ef6b5562d4a0c09bb7fdb9f8378856dee30cf" +dependencies = [ + "polkavm-derive-impl 0.10.0", + "syn 2.0.87", +] + +[[package]] +name = "polkavm-derive-impl-macro" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b569754b15060d03000c09e3bf11509d527f60b75d79b4c30c3625b5071d9702" +checksum = "48c16669ddc7433e34c1007d31080b80901e3e8e523cb9d4b441c3910cf9294b" dependencies = [ - "polkavm-derive-impl 0.14.0", - "syn 2.0.82", + "polkavm-derive-impl 0.18.0", + "syn 2.0.87", ] [[package]] @@ -16530,15 +20105,31 @@ dependencies = [ [[package]] name = "polkavm-linker" -version = "0.14.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d704edfe7bdcc876784f19436d53d515b65eb07bc9a0fae77085d552c2dbbb5" +dependencies = [ + "gimli 0.28.0", + "hashbrown 0.14.5", + "log", + "object 0.36.1", + "polkavm-common 0.10.0", + "regalloc2 0.9.3", + "rustc-demangle", +] + +[[package]] +name = "polkavm-linker" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0959ac3b0f4fd5caf5c245c637705f19493efe83dba31a83bbba928b93b0116a" +checksum = "e9bfe793b094d9ea5c99b7c43ba46e277b0f8f48f4bbfdbabf8d3ebf701a4bd3" dependencies = [ + "dirs", "gimli 0.31.1", "hashbrown 0.14.5", "log", "object 0.36.1", - "polkavm-common 0.14.0", + "polkavm-common 0.18.0", "regalloc2 0.9.3", "rustc-demangle", ] @@ -16551,9 +20142,15 @@ checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" [[package]] name = "polkavm-linux-raw" -version = "0.13.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26e45fa59c7e1bb12ef5289080601e9ec9b31435f6e32800a5c90c132453d126" + +[[package]] +name = "polkavm-linux-raw" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686c4dd9c9c16cc22565b51bdbb269792318d0fd2e6b966b5f6c788534cad0e9" +checksum = "23eff02c070c70f31878a3d915e88a914ecf3e153741e2fb572dde28cce20fde" [[package]] name = "polling" @@ -16580,7 +20177,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.25", + "rustix 0.38.21", "tracing", "windows-sys 0.52.0", ] @@ -16640,7 +20237,7 @@ dependencies = [ "findshlibs", "libc", "log", - "nix 0.26.2", + "nix 0.26.4", "once_cell", "parking_lot 0.12.3", "smallvec", @@ -16727,7 +20324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2 1.0.86", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16739,6 +20336,7 @@ dependencies = [ "fixed-hash", "impl-codec 0.6.0", "impl-num-traits 0.1.2", + "impl-rlp 0.3.0", "impl-serde 0.4.0", "scale-info", "uint 0.9.5", @@ -16753,7 +20351,7 @@ dependencies = [ "fixed-hash", "impl-codec 0.7.0", "impl-num-traits 0.2.0", - "impl-rlp", + "impl-rlp 0.4.0", "impl-serde 0.5.0", "scale-info", "uint 0.10.0", @@ -16767,7 +20365,7 @@ checksum = "a172e6cc603231f2cf004232eabcecccc0da53ba576ab286ef7baa0cfc7927ad" dependencies = [ "coarsetime", "crossbeam-queue", - "derive_more", + "derive_more 0.99.17", "futures", "futures-timer", "nanorand", @@ -16837,7 +20435,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16846,17 +20444,6 @@ version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" -[[package]] -name = "proc-macro-warning" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 2.0.82", -] - [[package]] name = "proc-macro-warning" version = "1.0.0" @@ -16865,7 +20452,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16898,7 +20485,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.25", + "rustix 0.38.21", ] [[package]] @@ -16928,9 +20515,9 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.21.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", @@ -16946,7 +20533,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -16975,7 +20562,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -17019,7 +20606,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -17028,7 +20615,7 @@ dependencies = [ "prost 0.13.2", "prost-types", "regex", - "syn 2.0.82", + "syn 2.0.87", "tempfile", ] @@ -17055,7 +20642,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -17065,10 +20652,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -17101,7 +20688,7 @@ dependencies = [ "log", "names", "prost 0.11.9", - "reqwest 0.11.20", + "reqwest 0.11.27", "thiserror", "url", "winapi", @@ -17161,15 +20748,15 @@ dependencies = [ [[package]] name = "quick-protobuf-codec" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" dependencies = [ - "asynchronous-codec", + "asynchronous-codec 0.7.0", "bytes", "quick-protobuf 0.8.1", "thiserror", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -17194,24 +20781,6 @@ dependencies = [ "rand", ] -[[package]] -name = "quinn" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" -dependencies = [ - "bytes", - "futures-io", - "pin-project-lite", - "quinn-proto 0.10.6", - "quinn-udp 0.4.1", - "rustc-hash 1.1.0", - "rustls 0.21.7", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "quinn" version = "0.11.5" @@ -17219,34 +20788,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", + "futures-io", "pin-project-lite", - "quinn-proto 0.11.8", - "quinn-udp 0.5.4", + "quinn-proto", + "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.14", + "rustls 0.23.18", "socket2 0.5.7", "thiserror", "tokio", "tracing", ] -[[package]] -name = "quinn-proto" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" -dependencies = [ - "bytes", - "rand", - "ring 0.16.20", - "rustc-hash 1.1.0", - "rustls 0.21.7", - "slab", - "thiserror", - "tinyvec", - "tracing", -] - [[package]] name = "quinn-proto" version = "0.11.8" @@ -17255,28 +20808,15 @@ checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", - "ring 0.17.7", + "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.14", + "rustls 0.23.18", "slab", "thiserror", "tinyvec", "tracing", ] -[[package]] -name = "quinn-udp" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" -dependencies = [ - "bytes", - "libc", - "socket2 0.5.7", - "tracing", - "windows-sys 0.48.0", -] - [[package]] name = "quinn-udp" version = "0.5.4" @@ -17323,6 +20863,7 @@ dependencies = [ "libc", "rand_chacha", "rand_core 0.6.4", + "serde", ] [[package]] @@ -17446,19 +20987,15 @@ dependencies = [ ] [[package]] -name = "reconnecting-jsonrpsee-ws-client" -version = "0.4.3" +name = "rcgen" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06fa4f17e09edfc3131636082faaec633c7baa269396b4004040bc6c52f49f65" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" dependencies = [ - "cfg_aliases 0.2.1", - "finito", - "futures", - "jsonrpsee 0.23.2", - "serde_json", - "thiserror", - "tokio", - "tracing", + "pem 3.0.4", + "ring 0.16.20", + "time", + "yasna", ] [[package]] @@ -17505,7 +21042,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87413ebb313323d431e85d0afc5a68222aaed972843537cbfe5f061cf1b4bcab" dependencies = [ - "derive_more", + "derive_more 0.99.17", "fs-err", "static_init", "thiserror", @@ -17528,7 +21065,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -17558,14 +21095,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.2", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -17585,13 +21122,13 @@ checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -17602,9 +21139,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -17618,19 +21155,19 @@ version = "0.1.0" dependencies = [ "async-std", "async-trait", - "bp-header-chain", - "bp-messages", - "bp-polkadot-core", - "bp-runtime", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-runtime 0.7.0", "finality-relay", - "frame-support", + "frame-support 28.0.0", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "num-traits", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-utility 28.0.0", "parity-scale-codec", "quick_cache", "rand", @@ -17640,14 +21177,14 @@ dependencies = [ "sc-transaction-pool-api", "scale-info", "serde_json", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-rpc", "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", - "staging-xcm", + "staging-xcm 7.0.0", "thiserror", "tokio", ] @@ -17660,7 +21197,7 @@ dependencies = [ "async-std", "async-trait", "backoff", - "bp-runtime", + "bp-runtime 0.7.0", "console", "futures", "isahc", @@ -17683,21 +21220,21 @@ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ "clap 4.5.13", - "frame-system", + "frame-system 28.0.0", "log", "pallet-bags-list-remote-tests", "sp-core 28.0.0", "sp-tracing 16.0.0", "tokio", "westend-runtime", - "westend-runtime-constants", + "westend-runtime-constants 7.0.0", ] [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", @@ -17723,6 +21260,8 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", @@ -17732,14 +21271,14 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.25.2", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -17759,14 +21298,14 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "quinn 0.11.5", - "rustls 0.23.14", + "quinn", + "rustls 0.23.18", "rustls-pemfile 2.0.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tokio-rustls 0.26.0", "tower-service", @@ -17775,7 +21314,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.26.3", - "winreg 0.52.0", + "windows-registry", ] [[package]] @@ -17832,16 +21371,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -17894,138 +21434,138 @@ name = "rococo-emulated-chain" version = "0.0.0" dependencies = [ "emulated-integration-tests-common", - "parachains-common", - "polkadot-primitives", + "parachains-common 7.0.0", + "polkadot-primitives 7.0.0", "rococo-runtime", - "rococo-runtime-constants", + "rococo-runtime-constants 7.0.0", "sc-consensus-grandpa", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", + "sp-authority-discovery 26.0.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", ] [[package]] name = "rococo-parachain-runtime" version = "0.6.0" dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-ping", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", - "pallet-assets", - "pallet-aura", - "pallet-balances", - "pallet-message-queue", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "cumulus-pallet-aura-ext 0.7.0", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcm 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-ping 0.7.0", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-storage-weight-reclaim 1.0.0", + "cumulus-primitives-utility 0.7.0", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "pallet-assets 29.1.0", + "pallet-aura 27.0.0", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-xcm 7.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", "scale-info", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-transaction-pool", + "sp-session 27.0.0", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "testnet-parachains-constants", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] name = "rococo-runtime" version = "7.0.0" dependencies = [ - "binary-merkle-tree", + "binary-merkle-tree 13.0.0", "bitvec", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", "frame-remote-externalities", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-asset-rate", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-balances", - "pallet-beefy", - "pallet-beefy-mmr", - "pallet-bounties", - "pallet-child-bounties", - "pallet-collective", - "pallet-conviction-voting", - "pallet-democracy", - "pallet-elections-phragmen", - "pallet-grandpa", - "pallet-identity", - "pallet-indices", - "pallet-membership", - "pallet-message-queue", - "pallet-migrations", - "pallet-mmr", - "pallet-multisig", - "pallet-nis", - "pallet-offences", - "pallet-parameters", - "pallet-preimage", - "pallet-proxy", - "pallet-ranked-collective", - "pallet-recovery", - "pallet-referenda", - "pallet-root-testing", - "pallet-scheduler", - "pallet-session", - "pallet-society", - "pallet-staking", - "pallet-state-trie-migration", - "pallet-sudo", - "pallet-timestamp", - "pallet-tips", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-treasury", - "pallet-utility", - "pallet-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-runtime-parachains", - "rococo-runtime-constants", + "pallet-asset-rate 7.0.0", + "pallet-authority-discovery 28.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-beefy 28.0.0", + "pallet-beefy-mmr 28.0.0", + "pallet-bounties 27.0.0", + "pallet-child-bounties 27.0.0", + "pallet-collective 28.0.0", + "pallet-conviction-voting 28.0.0", + "pallet-democracy 28.0.0", + "pallet-elections-phragmen 29.0.0", + "pallet-grandpa 28.0.0", + "pallet-identity 29.0.0", + "pallet-indices 28.0.0", + "pallet-membership 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-migrations 1.0.0", + "pallet-mmr 27.0.0", + "pallet-multisig 28.0.0", + "pallet-nis 28.0.0", + "pallet-offences 27.0.0", + "pallet-parameters 0.1.0", + "pallet-preimage 28.0.0", + "pallet-proxy 28.0.0", + "pallet-ranked-collective 28.0.0", + "pallet-recovery 28.0.0", + "pallet-referenda 28.0.0", + "pallet-root-testing 4.0.0", + "pallet-scheduler 29.0.0", + "pallet-session 28.0.0", + "pallet-society 28.0.0", + "pallet-staking 28.0.0", + "pallet-state-trie-migration 29.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-tips 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-treasury 27.0.0", + "pallet-utility 28.0.0", + "pallet-vesting 28.0.0", + "pallet-whitelist 27.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", + "rococo-runtime-constants 7.0.0", "scale-info", "separator", "serde", @@ -18034,49 +21574,66 @@ dependencies = [ "smallvec", "sp-api 26.0.0", "sp-arithmetic 23.0.0", - "sp-authority-discovery", - "sp-block-builder", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-consensus-grandpa", - "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-authority-discovery 26.0.0", + "sp-block-builder 26.0.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", + "sp-consensus-grandpa 13.0.0", + "sp-core 28.0.0", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-mmr-primitives", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-mmr-primitives 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", "static_assertions", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", "tiny-keccak", "tokio", - "xcm-runtime-apis", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "rococo-runtime-constants" version = "7.0.0" dependencies = [ - "frame-support", - "polkadot-primitives", - "polkadot-runtime-common", + "frame-support 28.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", "smallvec", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", - "staging-xcm", - "staging-xcm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", +] + +[[package]] +name = "rococo-runtime-constants" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ec6683a2e52fe3be2eaf942a80619abd99eb36e973c5ab4489a2f3b100db5c" +dependencies = [ + "frame-support 38.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-common 17.0.0", + "smallvec", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -18148,7 +21705,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.82", + "syn 2.0.87", "unicode-ident", ] @@ -18297,14 +21854,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.11", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -18338,7 +21895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle 2.5.0", @@ -18347,13 +21904,13 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ "log", "once_cell", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle 2.5.0", @@ -18419,9 +21976,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-platform-verifier" @@ -18434,7 +21991,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.14", + "rustls 0.23.18", "rustls-native-certs 0.7.0", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", @@ -18466,7 +22023,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", ] @@ -18502,13 +22059,12 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" dependencies = [ "byteorder", - "derive_more", - "twox-hash", + "derive_more 0.99.17", ] [[package]] @@ -18546,6 +22102,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "same-file" version = "1.0.6" @@ -18573,7 +22138,19 @@ checksum = "a3f01218e73ea57916be5f08987995ac802d6f4ede4ea5ce0242e468c590e4e2" dependencies = [ "log", "sp-core 33.0.1", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", + "thiserror", +] + +[[package]] +name = "sc-allocator" +version = "29.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b975ee3a95eaacb611e7b415737a7fa2db4d8ad7b880cc1b97371b04e95c7903" +dependencies = [ + "log", + "sp-core 34.0.0", + "sp-wasm-interface 21.0.1", "thiserror", ] @@ -18585,7 +22162,6 @@ dependencies = [ "futures", "futures-timer", "ip_network", - "libp2p", "linked_hash_set", "log", "multihash 0.19.1", @@ -18598,7 +22174,7 @@ dependencies = [ "sc-network", "sc-network-types", "sp-api 26.0.0", - "sp-authority-discovery", + "sp-authority-discovery 26.0.0", "sp-blockchain", "sp-core 28.0.0", "sp-keystore 0.34.0", @@ -18628,7 +22204,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -18640,10 +22216,10 @@ version = "0.33.0" dependencies = [ "parity-scale-codec", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-trie 29.0.0", @@ -18670,12 +22246,12 @@ dependencies = [ "serde_json", "sp-application-crypto 30.0.0", "sp-blockchain", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-genesis-builder", + "sp-genesis-builder 0.8.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-tracing 16.0.0", @@ -18689,7 +22265,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -18725,7 +22301,7 @@ dependencies = [ "serde_json", "sp-blockchain", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-panic-handler 13.0.0", "sp-runtime 31.0.1", @@ -18756,7 +22332,7 @@ dependencies = [ "sp-externalities 0.25.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "sp-statement-store", + "sp-statement-store 10.0.0", "sp-storage 19.0.0", "sp-test-primitives", "sp-trie 29.0.0", @@ -18841,17 +22417,17 @@ dependencies = [ "sc-telemetry", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-aura", - "sp-consensus-slots", + "sp-consensus-aura 0.32.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", - "sp-inherents", - "sp-keyring", + "sp-inherents 26.0.0", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -18883,18 +22459,18 @@ dependencies = [ "sc-transaction-pool-api", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", - "sp-consensus-slots", + "sp-consensus-babe 0.32.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-inherents", - "sp-keyring", + "sp-inherents 26.0.0", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -18907,7 +22483,7 @@ name = "sc-consensus-babe-rpc" version = "0.34.0" dependencies = [ "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "sc-consensus", "sc-consensus-babe", "sc-consensus-epochs", @@ -18920,9 +22496,9 @@ dependencies = [ "sp-application-crypto 30.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-babe", + "sp-consensus-babe 0.32.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "substrate-test-runtime-client", @@ -18957,13 +22533,13 @@ dependencies = [ "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-beefy", - "sp-consensus-grandpa", + "sp-consensus-beefy 13.0.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", - "sp-mmr-primitives", + "sp-mmr-primitives 26.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", @@ -18979,7 +22555,7 @@ name = "sc-consensus-beefy-rpc" version = "13.0.0" dependencies = [ "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -18988,7 +22564,7 @@ dependencies = [ "serde", "serde_json", "sp-application-crypto 30.0.0", - "sp-consensus-beefy", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "substrate-test-runtime-client", @@ -19045,10 +22621,10 @@ dependencies = [ "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", @@ -19064,7 +22640,7 @@ version = "0.19.0" dependencies = [ "finality-grandpa", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "sc-block-builder", @@ -19073,9 +22649,9 @@ dependencies = [ "sc-rpc", "serde", "sp-blockchain", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "substrate-test-runtime-client", "thiserror", @@ -19090,7 +22666,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "sc-basic-authorship", @@ -19105,14 +22681,14 @@ dependencies = [ "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-aura", - "sp-consensus-babe", - "sp-consensus-slots", + "sp-consensus-aura 0.32.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", @@ -19133,12 +22709,12 @@ dependencies = [ "sc-client-api", "sc-consensus", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-pow", + "sp-consensus-pow 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "thiserror", @@ -19159,9 +22735,9 @@ dependencies = [ "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-slots", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "substrate-test-runtime-client", @@ -19226,7 +22802,31 @@ dependencies = [ "sp-runtime-interface 27.0.0", "sp-trie 35.0.0", "sp-version 35.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", + "tracing", +] + +[[package]] +name = "sc-executor" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0cc0a3728fd033589183460c5a49b2e7545d09dc89a098216ef9e9aadcd9dc" +dependencies = [ + "parity-scale-codec", + "parking_lot 0.12.3", + "sc-executor-common 0.35.0", + "sc-executor-polkavm 0.32.0", + "sc-executor-wasmtime 0.35.0", + "schnellru", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-externalities 0.29.0", + "sp-io 38.0.0", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime-interface 28.0.0", + "sp-trie 37.0.0", + "sp-version 37.0.0", + "sp-wasm-interface 21.0.1", "tracing", ] @@ -19234,7 +22834,7 @@ dependencies = [ name = "sc-executor-common" version = "0.29.0" dependencies = [ - "polkavm 0.9.3", + "polkavm 0.18.0", "sc-allocator 23.0.0", "sp-maybe-compressed-blob 11.0.0", "sp-wasm-interface 20.0.0", @@ -19251,7 +22851,21 @@ dependencies = [ "polkavm 0.9.3", "sc-allocator 28.0.0", "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", + "thiserror", + "wasm-instrument", +] + +[[package]] +name = "sc-executor-common" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3b703a33dcb7cddf19176fdf12294b9a6408125836b0f4afee3e6969e7f190" +dependencies = [ + "polkavm 0.9.3", + "sc-allocator 29.0.0", + "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-wasm-interface 21.0.1", "thiserror", "wasm-instrument", ] @@ -19261,7 +22875,7 @@ name = "sc-executor-polkavm" version = "0.29.0" dependencies = [ "log", - "polkavm 0.9.3", + "polkavm 0.18.0", "sc-executor-common 0.29.0", "sp-wasm-interface 20.0.0", ] @@ -19275,7 +22889,19 @@ dependencies = [ "log", "polkavm 0.9.3", "sc-executor-common 0.34.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", +] + +[[package]] +name = "sc-executor-polkavm" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fe58d9cacfab73e5595fa84b80f7bd03efebe54a0574daaeb221a1d1f7ab80" +dependencies = [ + "log", + "polkavm 0.9.3", + "sc-executor-common 0.35.0", + "sp-wasm-interface 21.0.1", ] [[package]] @@ -19317,7 +22943,26 @@ dependencies = [ "sc-allocator 28.0.0", "sc-executor-common 0.34.0", "sp-runtime-interface 27.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", + "wasmtime", +] + +[[package]] +name = "sc-executor-wasmtime" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd498f2f77ec1f861c30804f5bfd796d4afcc8ce44ea1f11bfbe2847551d161" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "log", + "parking_lot 0.12.3", + "rustix 0.36.15", + "sc-allocator 29.0.0", + "sc-executor-common 0.35.0", + "sp-runtime-interface 28.0.0", + "sp-wasm-interface 21.0.1", "wasmtime", ] @@ -19374,7 +23019,7 @@ dependencies = [ "sp-consensus", "sp-core 28.0.0", "sp-keystore 0.34.0", - "sp-mixnet", + "sp-mixnet 0.4.0", "sp-runtime 31.0.1", "thiserror", ] @@ -19387,15 +23032,16 @@ dependencies = [ "assert_matches", "async-channel 1.9.0", "async-trait", - "asynchronous-codec", + "asynchronous-codec 0.6.2", "bytes", "cid 0.9.0", + "criterion", "either", "fnv", "futures", "futures-timer", "ip_network", - "libp2p", + "libp2p 0.54.1", "linked_hash_set", "litep2p", "log", @@ -19411,6 +23057,7 @@ dependencies = [ "rand", "sc-block-builder", "sc-client-api", + "sc-consensus", "sc-network-common", "sc-network-light", "sc-network-sync", @@ -19456,7 +23103,7 @@ dependencies = [ "sc-consensus", "sc-network-types", "sp-consensus", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-runtime 31.0.1", "tempfile", ] @@ -19519,7 +23166,7 @@ dependencies = [ "sc-network-types", "sp-consensus", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", "substrate-prometheus-endpoint", ] @@ -19551,7 +23198,7 @@ dependencies = [ "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-test-primitives", @@ -19570,7 +23217,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "libp2p", + "libp2p 0.54.1", "log", "parking_lot 0.12.3", "rand", @@ -19617,8 +23264,10 @@ name = "sc-network-types" version = "0.10.0" dependencies = [ "bs58", + "bytes", "ed25519-dalek", "libp2p-identity", + "libp2p-kad", "litep2p", "log", "multiaddr 0.18.1", @@ -19649,7 +23298,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "rand", - "rustls 0.23.14", + "rustls 0.23.18", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -19664,7 +23313,7 @@ dependencies = [ "sp-core 28.0.0", "sp-externalities 0.25.0", "sp-keystore 0.34.0", - "sp-offchain", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-test-runtime-client", @@ -19687,7 +23336,7 @@ version = "29.0.0" dependencies = [ "assert_matches", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19711,11 +23360,11 @@ dependencies = [ "sp-crypto-hashing 0.1.0", "sp-io 30.0.0", "sp-keystore 0.34.0", - "sp-offchain", + "sp-offchain 26.0.0", "sp-rpc", "sp-runtime 31.0.1", - "sp-session", - "sp-statement-store", + "sp-session 27.0.0", + "sp-statement-store 10.0.0", "sp-version 29.0.0", "substrate-test-runtime-client", "tokio", @@ -19725,7 +23374,7 @@ dependencies = [ name = "sc-rpc-api" version = "0.33.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "parity-scale-codec", "sc-chain-spec", "sc-mixnet", @@ -19752,7 +23401,7 @@ dependencies = [ "http-body-util", "hyper 1.3.1", "ip_network", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "sc-rpc-api", "serde", @@ -19769,10 +23418,12 @@ version = "0.34.0" dependencies = [ "array-bytes", "assert_matches", + "async-trait", "futures", "futures-util", "hex", - "jsonrpsee 0.24.3", + "itertools 0.11.0", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19814,7 +23465,26 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", +] + +[[package]] +name = "sc-runtime-utilities" +version = "0.1.0" +dependencies = [ + "cumulus-primitives-proof-size-hostfunction 0.2.0", + "cumulus-test-runtime", + "parity-scale-codec", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-state-machine 0.35.0", + "sp-version 29.0.0", + "sp-wasm-interface 20.0.0", + "subxt", + "thiserror", ] [[package]] @@ -19826,7 +23496,7 @@ dependencies = [ "exit-future", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19864,11 +23534,11 @@ dependencies = [ "sp-externalities 0.25.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-state-machine 0.35.0", "sp-storage 19.0.0", - "sp-transaction-pool", - "sp-transaction-storage-proof", + "sp-transaction-pool 26.0.0", + "sp-transaction-storage-proof 26.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", "static_init", @@ -19941,7 +23611,7 @@ dependencies = [ "sp-blockchain", "sp-core 28.0.0", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "tempfile", @@ -19964,7 +23634,7 @@ dependencies = [ name = "sc-sync-state-rpc" version = "0.34.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "parity-scale-codec", "sc-chain-spec", "sc-client-api", @@ -19982,7 +23652,7 @@ dependencies = [ name = "sc-sysinfo" version = "27.0.0" dependencies = [ - "derive_more", + "derive_more 0.99.17", "futures", "libc", "log", @@ -20005,7 +23675,7 @@ version = "15.0.0" dependencies = [ "chrono", "futures", - "libp2p", + "libp2p 0.54.1", "log", "parking_lot 0.12.3", "pin-project", @@ -20054,7 +23724,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -20067,7 +23737,7 @@ dependencies = [ "criterion", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.7.0", "itertools 0.11.0", "linked-hash-map", "log", @@ -20085,7 +23755,7 @@ dependencies = [ "sp-crypto-hashing 0.1.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime", "substrate-test-runtime-client", @@ -20143,9 +23813,22 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" dependencies = [ - "derive_more", + "derive_more 0.99.17", "parity-scale-codec", - "primitive-types 0.12.2", + "scale-bits", + "scale-type-resolver", + "smallvec", +] + +[[package]] +name = "scale-decode" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ae9cc099ae85ff28820210732b00f019546f36f33225f509fe25d5816864a0" +dependencies = [ + "derive_more 1.0.0", + "parity-scale-codec", + "primitive-types 0.13.1", "scale-bits", "scale-decode-derive", "scale-type-resolver", @@ -20154,25 +23837,25 @@ dependencies = [ [[package]] name = "scale-decode-derive" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb22f574168103cdd3133b19281639ca65ad985e24612728f727339dcaf4021" +checksum = "5ed9401effa946b493f9f84dc03714cca98119b230497df6f3df6b84a2b03648" dependencies = [ - "darling 0.14.4", + "darling", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] name = "scale-encode" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ba0b9c48dc0eb20c60b083c29447c0c4617cb7c4a4c9fef72aa5c5bc539e15e" +checksum = "5f9271284d05d0749c40771c46180ce89905fd95aa72a2a2fddb4b7c0aa424db" dependencies = [ - "derive_more", + "derive_more 1.0.0", "parity-scale-codec", - "primitive-types 0.12.2", + "primitive-types 0.13.1", "scale-bits", "scale-encode-derive", "scale-type-resolver", @@ -20181,26 +23864,26 @@ dependencies = [ [[package]] name = "scale-encode-derive" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ab7e60e2d9c8d47105f44527b26f04418e5e624ffc034f6b4a86c0ba19c5bf" +checksum = "102fbc6236de6c53906c0b262f12c7aa69c2bdc604862c12728f5f4d370bc137" dependencies = [ - "darling 0.14.4", - "proc-macro-crate 1.3.1", + "darling", + "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] name = "scale-info" -version = "2.11.3" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ "bitvec", "cfg-if", - "derive_more", + "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", "serde", @@ -20208,14 +23891,14 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.3" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -20230,31 +23913,30 @@ dependencies = [ [[package]] name = "scale-typegen" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "498d1aecf2ea61325d4511787c115791639c0fd21ef4f8e11e49dd09eff2bbac" +checksum = "0dc4c70c7fea2eef1740f0081d3fe385d8bee1eef11e9272d3bec7dc8e5438e0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scale-info", - "syn 2.0.82", + "syn 2.0.87", "thiserror", ] [[package]] name = "scale-value" -version = "0.16.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4d772cfb7569e03868400344a1695d16560bf62b86b918604773607d39ec84" +checksum = "f5e0ef2a0ee1e02a69ada37feb87ea1616ce9808aca072befe2d3131bf28576e" dependencies = [ "base58", "blake2 0.10.6", - "derive_more", + "derive_more 1.0.0", "either", - "frame-metadata 15.1.0", "parity-scale-codec", "scale-bits", - "scale-decode", + "scale-decode 0.14.0", "scale-encode", "scale-info", "scale-type-resolver", @@ -20359,6 +24041,18 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "password-hash", + "pbkdf2", + "salsa20", + "sha2 0.10.8", +] + [[package]] name = "sct" version = "0.7.0" @@ -20399,7 +24093,18 @@ version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "secp256k1-sys", + "secp256k1-sys 0.9.2", +] + +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes 0.14.0", + "rand", + "secp256k1-sys 0.10.1", ] [[package]] @@ -20411,6 +24116,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -20421,6 +24135,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.0" @@ -20502,12 +24225,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - [[package]] name = "separator" version = "0.4.1" @@ -20516,9 +24233,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -20553,13 +24270,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -20588,7 +24305,7 @@ version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -20622,7 +24339,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.7.0", "itoa", "ryu", "serde", @@ -20639,31 +24356,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serial_test" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" -dependencies = [ - "dashmap", - "futures", - "lazy_static", - "log", - "parking_lot 0.12.3", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 2.0.82", -] - [[package]] name = "sha-1" version = "0.9.8" @@ -20734,6 +24426,16 @@ dependencies = [ "keccak", ] +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -20848,6 +24550,18 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "slot-range-helper" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e34f1146a457a5c554dedeae6c7273aa54c3b031f3e9eb0abd037b5511e2ce9" +dependencies = [ + "enumn", + "parity-scale-codec", + "paste", + "sp-runtime 39.0.2", +] + [[package]] name = "slotmap" version = "1.0.6" @@ -20932,7 +24646,7 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more", + "derive_more 0.99.17", "ed25519-zebra 4.0.3", "either", "event-listener 2.5.3", @@ -20973,34 +24687,33 @@ dependencies = [ [[package]] name = "smoldot" -version = "0.16.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d1eaa97d77be4d026a1e7ffad1bb3b78448763b357ea6f8188d3e6f736a9b9" +checksum = "966e72d77a3b2171bb7461d0cb91f43670c63558c62d7cf42809cae6c8b6b818" dependencies = [ "arrayvec 0.7.4", "async-lock 3.4.0", "atomic-take", - "base64 0.21.7", + "base64 0.22.1", "bip39", "blake2-rfc", "bs58", "chacha20", "crossbeam-queue", - "derive_more", + "derive_more 0.99.17", "ed25519-zebra 4.0.3", "either", - "event-listener 4.0.3", + "event-listener 5.3.1", "fnv", "futures-lite 2.3.0", "futures-util", "hashbrown 0.14.5", "hex", "hmac 0.12.1", - "itertools 0.12.1", + "itertools 0.13.0", "libm", "libsecp256k1", "merlin", - "no-std-net", "nom", "num-bigint", "num-rational", @@ -21010,7 +24723,7 @@ dependencies = [ "poly1305", "rand", "rand_chacha", - "ruzstd 0.5.0", + "ruzstd 0.6.0", "schnorrkel 0.11.4", "serde", "serde_json", @@ -21019,9 +24732,9 @@ dependencies = [ "siphasher 1.0.1", "slab", "smallvec", - "soketto 0.7.1", + "soketto 0.8.0", "twox-hash", - "wasmi 0.31.2", + "wasmi 0.32.3", "x25519-dalek", "zeroize", ] @@ -21036,7 +24749,7 @@ dependencies = [ "async-lock 2.8.0", "base64 0.21.7", "blake2-rfc", - "derive_more", + "derive_more 0.99.17", "either", "event-listener 2.5.3", "fnv", @@ -21064,27 +24777,27 @@ dependencies = [ [[package]] name = "smoldot-light" -version = "0.14.0" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7" +checksum = "2a33b06891f687909632ce6a4e3fd7677b24df930365af3d0bcb078310129f3f" dependencies = [ "async-channel 2.3.0", "async-lock 3.4.0", - "base64 0.21.7", + "base64 0.22.1", "blake2-rfc", - "derive_more", + "bs58", + "derive_more 0.99.17", "either", - "event-listener 4.0.3", + "event-listener 5.3.1", "fnv", "futures-channel", "futures-lite 2.3.0", "futures-util", "hashbrown 0.14.5", "hex", - "itertools 0.12.1", + "itertools 0.13.0", "log", "lru 0.12.3", - "no-std-net", "parking_lot 0.12.3", "pin-project", "rand", @@ -21094,7 +24807,7 @@ dependencies = [ "siphasher 1.0.1", "slab", "smol 2.0.2", - "smoldot 0.16.0", + "smoldot 0.18.0", "zeroize", ] @@ -21115,7 +24828,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek 4.1.3", "rand_core 0.6.4", - "ring 0.17.7", + "ring 0.17.8", "rustc_version 0.4.0", "sha2 0.10.8", "subtle 2.5.0", @@ -21136,14 +24849,14 @@ name = "snowbridge-beacon-primitives" version = "0.2.0" dependencies = [ "byte-slice-cast", - "frame-support", + "frame-support 28.0.0", "hex", "hex-literal", "parity-scale-codec", "rlp 0.6.1", "scale-info", "serde", - "snowbridge-ethereum", + "snowbridge-ethereum 0.3.0", "snowbridge-milagro-bls", "sp-core 28.0.0", "sp-io 30.0.0", @@ -21153,37 +24866,84 @@ dependencies = [ "ssz_rs_derive", ] +[[package]] +name = "snowbridge-beacon-primitives" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bd720997e558beb556d354238fa90781deb38241cf31c1b6368738ef21c279" +dependencies = [ + "byte-slice-cast", + "frame-support 38.0.0", + "hex", + "parity-scale-codec", + "rlp 0.5.2", + "scale-info", + "serde", + "snowbridge-ethereum 0.9.0", + "snowbridge-milagro-bls", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ssz_rs", + "ssz_rs_derive", +] + [[package]] name = "snowbridge-core" version = "0.2.0" dependencies = [ - "ethabi-decode", - "frame-support", - "frame-system", + "ethabi-decode 2.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex", "hex-literal", "parity-scale-codec", - "polkadot-parachain-primitives", + "polkadot-parachain-primitives 6.0.0", "scale-info", "serde", - "snowbridge-beacon-primitives", + "snowbridge-beacon-primitives 0.2.0", "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "snowbridge-core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6be61e4db95d1e253a1d5e722953b2d2f6605e5f9761f0a919e5d3fbdbff9da9" +dependencies = [ + "ethabi-decode 1.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "hex-literal", + "parity-scale-codec", + "polkadot-parachain-primitives 14.0.0", + "scale-info", + "serde", + "snowbridge-beacon-primitives 0.10.0", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", ] [[package]] name = "snowbridge-ethereum" version = "0.3.0" dependencies = [ - "ethabi-decode", - "ethbloom", - "ethereum-types", + "ethabi-decode 2.0.0", + "ethbloom 0.14.1", + "ethereum-types 0.15.1", "hex-literal", "parity-bytes", "parity-scale-codec", @@ -21192,11 +24952,32 @@ dependencies = [ "scale-info", "serde", "serde-big-array", - "serde_json", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0", - "wasm-bindgen-test", + "serde_json", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-std 14.0.0", + "wasm-bindgen-test", +] + +[[package]] +name = "snowbridge-ethereum" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3d6d549c57df27cf89ec852f932fa4008eea877a6911a87e03e8002104eabd" +dependencies = [ + "ethabi-decode 1.0.0", + "ethbloom 0.13.0", + "ethereum-types 0.14.1", + "hex-literal", + "parity-bytes", + "parity-scale-codec", + "rlp 0.5.2", + "scale-info", + "serde", + "serde-big-array", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -21229,83 +25010,174 @@ dependencies = [ "sp-tracing 16.0.0", ] +[[package]] +name = "snowbridge-outbound-queue-merkle-tree" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c6a9b65fa61711b704f0c6afb3663c6288288e8822ddae5cc1146fe3ad9ce8" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "snowbridge-outbound-queue-runtime-api" version = "0.2.0" dependencies = [ - "frame-support", + "frame-support 28.0.0", "parity-scale-codec", - "snowbridge-core", - "snowbridge-outbound-queue-merkle-tree", + "snowbridge-core 0.2.0", + "snowbridge-outbound-queue-merkle-tree 0.3.0", "sp-api 26.0.0", "sp-std 14.0.0", ] +[[package]] +name = "snowbridge-outbound-queue-runtime-api" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d27b8d9cb8022637a5ce4f52692520fa75874f393e04ef5cd75bd8795087f6" +dependencies = [ + "frame-support 38.0.0", + "parity-scale-codec", + "snowbridge-core 0.10.0", + "snowbridge-outbound-queue-merkle-tree 0.9.1", + "sp-api 34.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "snowbridge-pallet-ethereum-client" version = "0.2.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex-literal", "log", - "pallet-timestamp", + "pallet-timestamp 27.0.0", "parity-scale-codec", "rand", "scale-info", "serde", "serde_json", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-ethereum", - "snowbridge-pallet-ethereum-client-fixtures", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", + "snowbridge-ethereum 0.3.0", + "snowbridge-pallet-ethereum-client-fixtures 0.9.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", "static_assertions", ] +[[package]] +name = "snowbridge-pallet-ethereum-client" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d53d32d8470c643f9f8c1f508e1e34263f76297e4c9150e10e8f2e0b63992e1" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-timestamp 37.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "snowbridge-beacon-primitives 0.10.0", + "snowbridge-core 0.10.0", + "snowbridge-ethereum 0.9.0", + "snowbridge-pallet-ethereum-client-fixtures 0.18.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions", +] + [[package]] name = "snowbridge-pallet-ethereum-client-fixtures" version = "0.9.0" dependencies = [ "hex-literal", - "snowbridge-beacon-primitives", - "snowbridge-core", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", "sp-core 28.0.0", "sp-std 14.0.0", ] +[[package]] +name = "snowbridge-pallet-ethereum-client-fixtures" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3984b98465af1d862d4e87ba783e1731f2a3f851b148d6cb98d526cebd351185" +dependencies = [ + "hex-literal", + "snowbridge-beacon-primitives 0.10.0", + "snowbridge-core 0.10.0", + "sp-core 34.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "snowbridge-pallet-inbound-queue" version = "0.2.0" dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "frame-benchmarking", - "frame-support", - "frame-system", + "alloy-core", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex-literal", "log", - "pallet-balances", + "pallet-balances 28.0.0", "parity-scale-codec", "scale-info", "serde", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-pallet-ethereum-client", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-router-primitives", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", + "snowbridge-pallet-ethereum-client 0.2.0", + "snowbridge-pallet-inbound-queue-fixtures 0.10.0", + "snowbridge-router-primitives 0.9.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "snowbridge-pallet-inbound-queue" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e6a9d00e60e3744e6b6f0c21fea6694b9c6401ac40e41340a96e561dcf1935" +dependencies = [ + "alloy-primitives 0.4.2", + "alloy-sol-types 0.4.2", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "snowbridge-beacon-primitives 0.10.0", + "snowbridge-core 0.10.0", + "snowbridge-pallet-inbound-queue-fixtures 0.18.0", + "snowbridge-router-primitives 0.16.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", ] [[package]] @@ -21313,122 +25185,248 @@ name = "snowbridge-pallet-inbound-queue-fixtures" version = "0.10.0" dependencies = [ "hex-literal", - "snowbridge-beacon-primitives", - "snowbridge-core", + "snowbridge-beacon-primitives 0.2.0", + "snowbridge-core 0.2.0", "sp-core 28.0.0", "sp-std 14.0.0", ] +[[package]] +name = "snowbridge-pallet-inbound-queue-fixtures" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b099db83f4c10c0bf84e87deb1596019f91411ea1c8c9733ea9a7f2e7e967073" +dependencies = [ + "hex-literal", + "snowbridge-beacon-primitives 0.10.0", + "snowbridge-core 0.10.0", + "sp-core 34.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "snowbridge-pallet-outbound-queue" version = "0.2.0" dependencies = [ - "bridge-hub-common", - "ethabi-decode", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-message-queue", + "bridge-hub-common 0.1.0", + "ethabi-decode 2.0.0", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-message-queue 31.0.0", "parity-scale-codec", "scale-info", "serde", - "snowbridge-core", - "snowbridge-outbound-queue-merkle-tree", + "snowbridge-core 0.2.0", + "snowbridge-outbound-queue-merkle-tree 0.3.0", "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", ] +[[package]] +name = "snowbridge-pallet-outbound-queue" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d49478041b6512c710d0d4655675d146fe00a8e0c1624e5d8a1d6c161d490f" +dependencies = [ + "bridge-hub-common 0.10.0", + "ethabi-decode 1.0.0", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "snowbridge-core 0.10.0", + "snowbridge-outbound-queue-merkle-tree 0.9.1", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "snowbridge-pallet-system" version = "0.2.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex", "hex-literal", "log", - "pallet-balances", - "pallet-message-queue", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", "parity-scale-codec", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "scale-info", - "snowbridge-core", - "snowbridge-pallet-outbound-queue", + "snowbridge-core 0.2.0", + "snowbridge-pallet-outbound-queue 0.2.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "snowbridge-pallet-system" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "674db59b3c8013382e5c07243ad9439b64d81d2e8b3c4f08d752b55aa5de697e" +dependencies = [ + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "parity-scale-codec", + "scale-info", + "snowbridge-core 0.10.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", ] [[package]] name = "snowbridge-router-primitives" version = "0.9.0" dependencies = [ - "frame-support", + "frame-support 28.0.0", "hex-literal", "log", "parity-scale-codec", "scale-info", - "snowbridge-core", + "snowbridge-core 0.2.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "snowbridge-router-primitives" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "025f1e6805753821b1db539369f1fb183fd59fd5df7023f7633a4c0cfd3e62f9" +dependencies = [ + "frame-support 38.0.0", + "hex-literal", + "log", + "parity-scale-codec", + "scale-info", + "snowbridge-core 0.10.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", ] [[package]] name = "snowbridge-runtime-common" version = "0.2.0" dependencies = [ - "frame-support", + "frame-support 28.0.0", "log", "parity-scale-codec", - "snowbridge-core", + "snowbridge-core 0.2.0", "sp-arithmetic 23.0.0", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "snowbridge-runtime-common" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093f0e73d6cfdd2eea8712155d1d75b5063fc9b1d854d2665b097b4bb29570d" +dependencies = [ + "frame-support 38.0.0", + "log", + "parity-scale-codec", + "snowbridge-core 0.10.0", + "sp-arithmetic 26.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", ] [[package]] name = "snowbridge-runtime-test-common" version = "0.2.0" dependencies = [ - "cumulus-pallet-parachain-system", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-timestamp", - "pallet-utility", - "pallet-xcm", - "parachains-runtimes-test-utils", - "parity-scale-codec", - "snowbridge-core", - "snowbridge-pallet-ethereum-client", - "snowbridge-pallet-ethereum-client-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", + "cumulus-pallet-parachain-system 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "pallet-balances 28.0.0", + "pallet-collator-selection 9.0.0", + "pallet-message-queue 31.0.0", + "pallet-session 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-utility 28.0.0", + "pallet-xcm 7.0.0", + "parachains-runtimes-test-utils 7.0.0", + "parity-scale-codec", + "snowbridge-core 0.2.0", + "snowbridge-pallet-ethereum-client 0.2.0", + "snowbridge-pallet-ethereum-client-fixtures 0.9.0", + "snowbridge-pallet-outbound-queue 0.2.0", + "snowbridge-pallet-system 0.2.0", "sp-core 28.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-executor", + "staging-parachain-info 0.7.0", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "snowbridge-runtime-test-common" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "893480d6cde2489051c65efb5d27fa87efe047b3b61216d8e27bb2f0509b7faf" +dependencies = [ + "cumulus-pallet-parachain-system 0.17.1", + "frame-support 38.0.0", + "frame-system 38.0.0", + "pallet-balances 39.0.0", + "pallet-collator-selection 19.0.0", + "pallet-message-queue 41.0.1", + "pallet-session 38.0.0", + "pallet-timestamp 37.0.0", + "pallet-utility 38.0.0", + "pallet-xcm 17.0.0", + "parachains-runtimes-test-utils 17.0.0", + "parity-scale-codec", + "snowbridge-core 0.10.0", + "snowbridge-pallet-ethereum-client 0.10.0", + "snowbridge-pallet-ethereum-client-fixtures 0.18.0", + "snowbridge-pallet-outbound-queue 0.10.0", + "snowbridge-pallet-system 0.10.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-keyring 39.0.0", + "sp-runtime 39.0.2", + "staging-parachain-info 0.17.0", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", ] [[package]] @@ -21436,10 +25434,23 @@ name = "snowbridge-system-runtime-api" version = "0.2.0" dependencies = [ "parity-scale-codec", - "snowbridge-core", + "snowbridge-core 0.2.0", "sp-api 26.0.0", "sp-std 14.0.0", - "staging-xcm", + "staging-xcm 7.0.0", +] + +[[package]] +name = "snowbridge-system-runtime-api" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b8b83b3db781c49844312a23965073e4d93341739a35eafe526c53b578d3b7" +dependencies = [ + "parity-scale-codec", + "snowbridge-core 0.10.0", + "sp-api 34.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", ] [[package]] @@ -21499,11 +25510,11 @@ version = "0.0.0" dependencies = [ "clap 4.5.13", "frame-benchmarking-cli", - "frame-metadata-hash-extension", - "frame-system", + "frame-metadata-hash-extension 0.1.0", + "frame-system 28.0.0", "futures", - "jsonrpsee 0.24.3", - "pallet-transaction-payment", + "jsonrpsee", + "pallet-transaction-payment 28.0.0", "pallet-transaction-payment-rpc", "sc-basic-authorship", "sc-cli", @@ -21521,17 +25532,17 @@ dependencies = [ "serde_json", "solochain-template-runtime", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", - "sp-consensus-aura", - "sp-consensus-grandpa", + "sp-consensus-aura 0.32.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", "substrate-build-script-utils", "substrate-frame-rpc-system", ] @@ -21540,40 +25551,40 @@ dependencies = [ name = "solochain-template-runtime" version = "0.0.0" dependencies = [ - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "pallet-aura", - "pallet-balances", - "pallet-grandpa", - "pallet-sudo", + "frame-benchmarking 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", + "pallet-aura 27.0.0", + "pallet-balances 28.0.0", + "pallet-grandpa 28.0.0", + "pallet-sudo 28.0.0", "pallet-template", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", "parity-scale-codec", "scale-info", "serde_json", "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", - "sp-consensus-grandpa", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-keyring", - "sp-offchain", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-storage 19.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -21621,6 +25632,29 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-api" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbce492e0482134128b7729ea36f5ef1a9f9b4de2d48ff8dde7b5e464e28ce75" +dependencies = [ + "docify", + "hash-db", + "log", + "parity-scale-codec", + "scale-info", + "sp-api-proc-macro 20.0.0", + "sp-core 34.0.0", + "sp-externalities 0.29.0", + "sp-metadata-ir 0.7.0", + "sp-runtime 39.0.2", + "sp-runtime-interface 28.0.0", + "sp-state-machine 0.43.0", + "sp-trie 37.0.0", + "sp-version 37.0.0", + "thiserror", +] + [[package]] name = "sp-api-proc-macro" version = "15.0.0" @@ -21632,7 +25666,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -21647,7 +25681,22 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", +] + +[[package]] +name = "sp-api-proc-macro" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9aadf9e97e694f0e343978aa632938c5de309cbcc8afed4136cb71596737278" +dependencies = [ + "Inflector", + "blake2 0.10.6", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -21664,6 +25713,7 @@ dependencies = [ "sp-api 26.0.0", "sp-consensus", "sp-core 28.0.0", + "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-tracing 16.0.0", @@ -21686,44 +25736,43 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "33.0.0" +version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13ca6121c22c8bd3d1dce1f05c479101fd0d7b159bef2a3e8c834138d839c75c" +checksum = "57541120624a76379cc993cbb85064a5148957a92da032567e54bce7977f51fc" dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 31.0.0", - "sp-io 33.0.0", + "sp-core 32.0.0", + "sp-io 35.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sp-application-crypto" -version = "35.0.0" +version = "36.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57541120624a76379cc993cbb85064a5148957a92da032567e54bce7977f51fc" +checksum = "296282f718f15d4d812664415942665302a484d3495cf8d2e2ab3192b32d2c73" dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 32.0.0", - "sp-io 35.0.0", + "sp-core 33.0.1", + "sp-io 36.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sp-application-crypto" -version = "36.0.0" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "296282f718f15d4d812664415942665302a484d3495cf8d2e2ab3192b32d2c73" +checksum = "0d8133012faa5f75b2f0b1619d9f720c1424ac477152c143e5f7dbde2fe1a958" dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 33.0.1", - "sp-io 36.0.0", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-core 34.0.0", + "sp-io 38.0.0", ] [[package]] @@ -21754,21 +25803,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "sp-arithmetic" -version = "25.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910c07fa263b20bf7271fdd4adcb5d3217dfdac14270592e0780223542e7e114" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "scale-info", - "serde", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions", -] - [[package]] name = "sp-arithmetic" version = "26.0.0" @@ -21825,15 +25859,39 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-authority-discovery" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519c33af0e25ba2dd2eb3790dc404d634b6e4ce0801bcc8fa3574e07c365e734" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-block-builder" version = "26.0.0" dependencies = [ "sp-api 26.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", ] +[[package]] +name = "sp-block-builder" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74738809461e3d4bd707b5b94e0e0c064a623a74a6a8fe5c98514417a02858dd" +dependencies = [ + "sp-api 34.0.0", + "sp-inherents 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-blockchain" version = "28.0.0" @@ -21860,7 +25918,7 @@ dependencies = [ "futures", "log", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-test-primitives", @@ -21876,10 +25934,27 @@ dependencies = [ "scale-info", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-consensus-slots", - "sp-inherents", + "sp-consensus-slots 0.32.0", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-timestamp 26.0.0", +] + +[[package]] +name = "sp-consensus-aura" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8faaa05bbcb9c41f0cc535c4c1315abf6df472b53eae018678d1b4d811ac47" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-consensus-slots 0.40.1", + "sp-inherents 34.0.0", + "sp-runtime 39.0.2", + "sp-timestamp 34.0.0", ] [[package]] @@ -21892,48 +25967,107 @@ dependencies = [ "serde", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-consensus-slots", + "sp-consensus-slots 0.32.0", + "sp-core 28.0.0", + "sp-inherents 26.0.0", + "sp-runtime 31.0.1", + "sp-timestamp 26.0.0", +] + +[[package]] +name = "sp-consensus-babe" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ee95e17ee8dcd14db7d584b899a426565ca9abe5a266ab82277977fc547f86" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-consensus-slots 0.40.1", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-runtime 39.0.2", + "sp-timestamp 34.0.0", +] + +[[package]] +name = "sp-consensus-beefy" +version = "13.0.0" +dependencies = [ + "array-bytes", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-inherents", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-mmr-primitives 26.0.0", "sp-runtime 31.0.1", - "sp-timestamp", + "sp-weights 27.0.0", + "strum 0.26.3", + "w3f-bls", +] + +[[package]] +name = "sp-consensus-beefy" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d97e8cd75d85d15cda6f1923cf3834e848f80d5a6de1cf4edbbc5f0ad607eb" +dependencies = [ + "lazy_static", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-core 34.0.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-io 38.0.0", + "sp-keystore 0.40.0", + "sp-mmr-primitives 34.1.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", + "strum 0.26.3", ] [[package]] -name = "sp-consensus-beefy" +name = "sp-consensus-grandpa" version = "13.0.0" dependencies = [ - "array-bytes", + "finality-grandpa", + "log", "parity-scale-codec", "scale-info", "serde", "sp-api 26.0.0", "sp-application-crypto 30.0.0", "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0", - "sp-io 30.0.0", "sp-keystore 0.34.0", - "sp-mmr-primitives", "sp-runtime 31.0.1", - "sp-weights 27.0.0", - "strum 0.26.3", - "w3f-bls", ] [[package]] name = "sp-consensus-grandpa" -version = "13.0.0" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "587b791efe6c5f18e09dbbaf1ece0ee7b5fe51602c233e7151a3676b0de0260b" dependencies = [ "finality-grandpa", "log", "parity-scale-codec", "scale-info", "serde", - "sp-api 26.0.0", - "sp-application-crypto 30.0.0", - "sp-core 28.0.0", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-core 34.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", ] [[package]] @@ -21946,6 +26080,18 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-consensus-pow" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa6b7d199a1c16cea1b74ee7cee174bf08f2120ab66a87bee7b12353100b47c" +dependencies = [ + "parity-scale-codec", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-consensus-sassafras" version = "0.3.4-dev" @@ -21955,7 +26101,7 @@ dependencies = [ "serde", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-consensus-slots", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", "sp-runtime 31.0.1", ] @@ -21967,7 +26113,19 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-timestamp", + "sp-timestamp 26.0.0", +] + +[[package]] +name = "sp-consensus-slots" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbafb7ed44f51c22fa277fb39b33dc601fa426133a8e2b53f3f46b10f07fba43" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-timestamp 34.0.0", ] [[package]] @@ -22001,8 +26159,8 @@ dependencies = [ "regex", "scale-info", "schnorrkel 0.11.4", - "secp256k1", - "secrecy", + "secp256k1 0.28.2", + "secrecy 0.8.0", "serde", "serde_json", "sp-crypto-hashing 0.1.0", @@ -22049,8 +26207,8 @@ dependencies = [ "rand", "scale-info", "schnorrkel 0.11.4", - "secp256k1", - "secrecy", + "secp256k1 0.28.2", + "secrecy 0.8.0", "serde", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -22096,8 +26254,8 @@ dependencies = [ "rand", "scale-info", "schnorrkel 0.11.4", - "secp256k1", - "secrecy", + "secp256k1 0.28.2", + "secrecy 0.8.0", "serde", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -22143,8 +26301,8 @@ dependencies = [ "rand", "scale-info", "schnorrkel 0.11.4", - "secp256k1", - "secrecy", + "secp256k1 0.28.2", + "secrecy 0.8.0", "serde", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -22160,6 +26318,53 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sp-core" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c961a5e33fb2962fa775c044ceba43df9c6f917e2c35d63bfe23738468fa76a7" +dependencies = [ + "array-bytes", + "bitflags 1.3.2", + "blake2 0.10.6", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra 4.0.3", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde 0.4.0", + "itertools 0.11.0", + "k256", + "libsecp256k1", + "log", + "merlin", + "parity-bip39", + "parity-scale-codec", + "parking_lot 0.12.3", + "paste", + "primitive-types 0.12.2", + "rand", + "scale-info", + "schnorrkel 0.11.4", + "secp256k1 0.28.2", + "secrecy 0.8.0", + "serde", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.29.0", + "sp-runtime-interface 28.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", + "ss58-registry", + "substrate-bip39 0.6.0", + "thiserror", + "tracing", + "w3f-bls", + "zeroize", +] + [[package]] name = "sp-core-fuzz" version = "0.0.0" @@ -22176,6 +26381,15 @@ dependencies = [ "sp-crypto-hashing 0.1.0", ] +[[package]] +name = "sp-core-hashing" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f812cb2dff962eb378c507612a50f1c59f52d92eb97b710f35be3c2346a3cd7" +dependencies = [ + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sp-core-hashing-proc-macro" version = "15.0.0" @@ -22186,7 +26400,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -22223,6 +26437,27 @@ dependencies = [ "sp-runtime-interface 24.0.0", ] +[[package]] +name = "sp-crypto-ec-utils" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acb24f8a607a48a87f0ee4c090fc5d577eee49ff39ced6a3c491e06eca03c37" +dependencies = [ + "ark-bls12-377", + "ark-bls12-377-ext", + "ark-bls12-381", + "ark-bls12-381-ext", + "ark-bw6-761", + "ark-bw6-761-ext", + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ed-on-bls12-377-ext", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", + "ark-scale 0.0.12", + "sp-runtime-interface 28.0.0", +] + [[package]] name = "sp-crypto-hashing" version = "0.1.0" @@ -22257,7 +26492,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22268,7 +26503,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.82", + "syn 2.0.87", ] [[package]] @@ -22286,7 +26521,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22295,7 +26530,7 @@ version = "14.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22306,7 +26541,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22352,6 +26587,17 @@ dependencies = [ "sp-storage 21.0.0", ] +[[package]] +name = "sp-externalities" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a904407d61cb94228c71b55a9d3708e9d6558991f9e83bd42bd91df37a159d30" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-storage 21.0.0", +] + [[package]] name = "sp-genesis-builder" version = "0.8.0" @@ -22363,6 +26609,19 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-genesis-builder" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a646ed222fd86d5680faa4a8967980eb32f644cae6c8523e1c689a6deda3e8" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde_json", + "sp-api 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-inherents" version = "26.0.0" @@ -22376,6 +26635,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-inherents" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afffbddc380d99a90c459ba1554bbbc01d62e892de9f1485af6940b89c4c0d57" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", + "thiserror", +] + [[package]] name = "sp-io" version = "30.0.0" @@ -22386,9 +26659,9 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive 0.18.0", "rustversion", - "secp256k1", + "secp256k1 0.28.2", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", @@ -22403,9 +26676,9 @@ dependencies = [ [[package]] name = "sp-io" -version = "33.0.0" +version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e09bba780b55bd9e67979cd8f654a31e4a6cf45426ff371394a65953d2177f2" +checksum = "8b64ab18a0e29def6511139a8c45a59c14a846105aab6f9cc653523bd3b81f55" dependencies = [ "bytes", "ed25519-dalek", @@ -22414,25 +26687,25 @@ dependencies = [ "parity-scale-codec", "polkavm-derive 0.9.1", "rustversion", - "secp256k1", - "sp-core 31.0.0", + "secp256k1 0.28.2", + "sp-core 32.0.0", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-externalities 0.27.0", - "sp-keystore 0.37.0", - "sp-runtime-interface 26.0.0", - "sp-state-machine 0.38.0", + "sp-externalities 0.28.0", + "sp-keystore 0.38.0", + "sp-runtime-interface 27.0.0", + "sp-state-machine 0.40.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-tracing 16.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-trie 32.0.0", + "sp-tracing 17.0.1", + "sp-trie 34.0.0", "tracing", "tracing-core", ] [[package]] name = "sp-io" -version = "35.0.0" +version = "36.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b64ab18a0e29def6511139a8c45a59c14a846105aab6f9cc653523bd3b81f55" +checksum = "e7a31ce27358b73656a09b4933f09a700019d63afa15ede966f7c9893c1d4db5" dependencies = [ "bytes", "ed25519-dalek", @@ -22441,43 +26714,43 @@ dependencies = [ "parity-scale-codec", "polkavm-derive 0.9.1", "rustversion", - "secp256k1", - "sp-core 32.0.0", + "secp256k1 0.28.2", + "sp-core 33.0.1", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-externalities 0.28.0", - "sp-keystore 0.38.0", + "sp-keystore 0.39.0", "sp-runtime-interface 27.0.0", - "sp-state-machine 0.40.0", + "sp-state-machine 0.41.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-tracing 17.0.0", - "sp-trie 34.0.0", + "sp-tracing 17.0.1", + "sp-trie 35.0.0", "tracing", "tracing-core", ] [[package]] name = "sp-io" -version = "36.0.0" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a31ce27358b73656a09b4933f09a700019d63afa15ede966f7c9893c1d4db5" +checksum = "59ef7eb561bb4839cc8424ce58c5ea236cbcca83f26fcc0426d8decfe8aa97d4" dependencies = [ "bytes", + "docify", "ed25519-dalek", "libsecp256k1", "log", "parity-scale-codec", "polkavm-derive 0.9.1", "rustversion", - "secp256k1", - "sp-core 33.0.1", + "secp256k1 0.28.2", + "sp-core 34.0.0", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-externalities 0.28.0", - "sp-keystore 0.39.0", - "sp-runtime-interface 27.0.0", - "sp-state-machine 0.41.0", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-tracing 17.0.0", - "sp-trie 35.0.0", + "sp-externalities 0.29.0", + "sp-keystore 0.40.0", + "sp-runtime-interface 28.0.0", + "sp-state-machine 0.43.0", + "sp-tracing 17.0.1", + "sp-trie 37.0.0", "tracing", "tracing-core", ] @@ -22491,6 +26764,17 @@ dependencies = [ "strum 0.26.3", ] +[[package]] +name = "sp-keyring" +version = "39.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c0e20624277f578b27f44ecfbe2ebc2e908488511ee2c900c5281599f700ab3" +dependencies = [ + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "strum 0.26.3", +] + [[package]] name = "sp-keystore" version = "0.34.0" @@ -22505,38 +26789,38 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbab8b61bd61d5f8625a0c75753b5d5a23be55d3445419acd42caf59cf6236b" +checksum = "4e6c7a7abd860a5211a356cf9d5fcabf0eb37d997985e5d722b6b33dcc815528" dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", - "sp-core 31.0.0", - "sp-externalities 0.27.0", + "sp-core 32.0.0", + "sp-externalities 0.28.0", ] [[package]] name = "sp-keystore" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6c7a7abd860a5211a356cf9d5fcabf0eb37d997985e5d722b6b33dcc815528" +checksum = "92a909528663a80829b95d582a20dd4c9acd6e575650dee2bcaf56f4740b305e" dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", - "sp-core 32.0.0", + "sp-core 33.0.1", "sp-externalities 0.28.0", ] [[package]] name = "sp-keystore" -version = "0.39.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a909528663a80829b95d582a20dd4c9acd6e575650dee2bcaf56f4740b305e" +checksum = "0248b4d784cb4a01472276928977121fa39d977a5bb24793b6b15e64b046df42" dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", - "sp-core 33.0.1", - "sp-externalities 0.28.0", + "sp-core 34.0.0", + "sp-externalities 0.29.0", ] [[package]] @@ -22561,7 +26845,7 @@ dependencies = [ name = "sp-metadata-ir" version = "0.6.0" dependencies = [ - "frame-metadata 16.0.0", + "frame-metadata 18.0.0", "parity-scale-codec", "scale-info", ] @@ -22587,6 +26871,18 @@ dependencies = [ "sp-application-crypto 30.0.0", ] +[[package]] +name = "sp-mixnet" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0b017dd54823b6e62f9f7171a1df350972e5c6d0bf17e0c2f78680b5c31942" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", +] + [[package]] name = "sp-mmr-primitives" version = "26.0.0" @@ -22604,6 +26900,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-mmr-primitives" +version = "34.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a12dd76e368f1e48144a84b4735218b712f84b3f976970e2f25a29b30440e10" +dependencies = [ + "log", + "parity-scale-codec", + "polkadot-ckb-merkle-mountain-range", + "scale-info", + "serde", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime 39.0.2", + "thiserror", +] + [[package]] name = "sp-npos-elections" version = "26.0.0" @@ -22618,6 +26932,20 @@ dependencies = [ "substrate-test-utils", ] +[[package]] +name = "sp-npos-elections" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af922f112c7c1ed199eabe14f12a82ceb75e1adf0804870eccfbcf3399492847" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" @@ -22625,7 +26953,7 @@ dependencies = [ "clap 4.5.13", "honggfuzz", "rand", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", ] @@ -22638,6 +26966,17 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-offchain" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9de237d72ecffd07f90826eef18360208b16d8de939d54e61591fac0fcbf99" +dependencies = [ + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-panic-handler" version = "13.0.0" @@ -22671,7 +27010,7 @@ dependencies = [ name = "sp-runtime" version = "31.0.1" dependencies = [ - "binary-merkle-tree", + "binary-merkle-tree 13.0.0", "docify", "either", "hash256-std-hasher", @@ -22703,9 +27042,9 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "34.0.0" +version = "36.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3cb126971e7db2f0fcf8053dce740684c438c7180cfca1959598230f342c58" +checksum = "a6b85cb874b78ebb17307a910fc27edf259a0455ac5155d87eaed8754c037e07" dependencies = [ "docify", "either", @@ -22718,44 +27057,45 @@ dependencies = [ "scale-info", "serde", "simple-mermaid 0.1.1", - "sp-application-crypto 33.0.0", - "sp-arithmetic 25.0.0", - "sp-core 31.0.0", - "sp-io 33.0.0", + "sp-application-crypto 35.0.0", + "sp-arithmetic 26.0.0", + "sp-core 32.0.0", + "sp-io 35.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-weights 30.0.0", + "sp-weights 31.0.0", ] [[package]] name = "sp-runtime" -version = "36.0.0" +version = "37.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6b85cb874b78ebb17307a910fc27edf259a0455ac5155d87eaed8754c037e07" +checksum = "1c2a6148bf0ba74999ecfea9b4c1ade544f0663e0baba19630bb7761b2142b19" dependencies = [ "docify", "either", "hash256-std-hasher", "impl-trait-for-tuples", "log", + "num-traits", "parity-scale-codec", "paste", "rand", "scale-info", "serde", "simple-mermaid 0.1.1", - "sp-application-crypto 35.0.0", + "sp-application-crypto 36.0.0", "sp-arithmetic 26.0.0", - "sp-core 32.0.0", - "sp-io 35.0.0", + "sp-core 33.0.1", + "sp-io 36.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-weights 31.0.0", ] [[package]] name = "sp-runtime" -version = "37.0.0" +version = "39.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c2a6148bf0ba74999ecfea9b4c1ade544f0663e0baba19630bb7761b2142b19" +checksum = "658f23be7c79a85581029676a73265c107c5469157e3444c8c640fdbaa8bfed0" dependencies = [ "docify", "either", @@ -22769,12 +27109,13 @@ dependencies = [ "scale-info", "serde", "simple-mermaid 0.1.1", - "sp-application-crypto 36.0.0", + "sp-application-crypto 38.0.0", "sp-arithmetic 26.0.0", - "sp-core 33.0.1", - "sp-io 36.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-weights 31.0.0", + "tracing", ] [[package]] @@ -22802,7 +27143,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive 0.18.0", "primitive-types 0.13.1", "rustversion", "sp-core 28.0.0", @@ -22854,21 +27195,41 @@ dependencies = [ "sp-runtime-interface-proc-macro 18.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-storage 21.0.0", - "sp-tracing 17.0.0", - "sp-wasm-interface 21.0.0", + "sp-tracing 17.0.1", + "sp-wasm-interface 21.0.1", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985eb981f40c689c6a0012c937b68ed58dabb4341d06f2dfe4dfd5ed72fa4017" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive 0.9.1", + "primitive-types 0.12.2", + "sp-externalities 0.29.0", + "sp-runtime-interface-proc-macro 18.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", + "sp-tracing 17.0.1", + "sp-wasm-interface 21.0.1", "static_assertions", ] [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "Inflector", "proc-macro-crate 1.3.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22880,7 +27241,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22894,7 +27255,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -22921,7 +27282,7 @@ dependencies = [ "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime-interface 24.0.0", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -22931,7 +27292,7 @@ dependencies = [ "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime-interface 24.0.0", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -22944,7 +27305,22 @@ dependencies = [ "sp-core 28.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-staking", + "sp-staking 26.0.0", +] + +[[package]] +name = "sp-session" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00a3a307fedc423fb8cd2a7726a3bbb99014f1b4b52f26153993e2aae3338fe6" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-core 34.0.0", + "sp-keystore 0.40.0", + "sp-runtime 39.0.2", + "sp-staking 36.0.0", ] [[package]] @@ -22959,6 +27335,34 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-staking" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143a764cacbab58347d8b2fd4c8909031fb0888d7b02a0ec9fa44f81f780d732" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + +[[package]] +name = "sp-staking" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a73eedb4b85f4cd420d31764827546aa22f82ce1646d0fd258993d051de7a90" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-state-machine" version = "0.35.0" @@ -22980,14 +27384,14 @@ dependencies = [ "sp-trie 29.0.0", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", ] [[package]] name = "sp-state-machine" -version = "0.38.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eae0eac8034ba14437e772366336f579398a46d101de13dbb781ab1e35e67c5" +checksum = "18084cb996c27d5d99a88750e0a8eb4af6870a40df97872a5923e6d293d95fb9" dependencies = [ "hash-db", "log", @@ -22995,21 +27399,20 @@ dependencies = [ "parking_lot 0.12.3", "rand", "smallvec", - "sp-core 31.0.0", - "sp-externalities 0.27.0", + "sp-core 32.0.0", + "sp-externalities 0.28.0", "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-trie 32.0.0", + "sp-trie 34.0.0", "thiserror", "tracing", - "trie-db 0.28.0", + "trie-db", ] [[package]] name = "sp-state-machine" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18084cb996c27d5d99a88750e0a8eb4af6870a40df97872a5923e6d293d95fb9" +checksum = "6f6ac196ea92c4d0613c071e1a050765dbfa30107a990224a4aba02c7dbcd063" dependencies = [ "hash-db", "log", @@ -23017,20 +27420,20 @@ dependencies = [ "parking_lot 0.12.3", "rand", "smallvec", - "sp-core 32.0.0", + "sp-core 33.0.1", "sp-externalities 0.28.0", "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-trie 34.0.0", + "sp-trie 35.0.0", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", ] [[package]] name = "sp-state-machine" -version = "0.41.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f6ac196ea92c4d0613c071e1a050765dbfa30107a990224a4aba02c7dbcd063" +checksum = "930104d6ae882626e8880d9b1578da9300655d337a3ffb45e130c608b6c89660" dependencies = [ "hash-db", "log", @@ -23038,13 +27441,13 @@ dependencies = [ "parking_lot 0.12.3", "rand", "smallvec", - "sp-core 33.0.1", - "sp-externalities 0.28.0", + "sp-core 34.0.0", + "sp-externalities 0.29.0", "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-trie 35.0.0", + "sp-trie 37.0.0", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", ] [[package]] @@ -23070,6 +27473,31 @@ dependencies = [ "x25519-dalek", ] +[[package]] +name = "sp-statement-store" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c219bc34ef4d1f9835f3ed881f965643c32034fcc030eb33b759dadbc802c1c2" +dependencies = [ + "aes-gcm", + "curve25519-dalek 4.1.3", + "ed25519-dalek", + "hkdf", + "parity-scale-codec", + "rand", + "scale-info", + "sha2 0.10.8", + "sp-api 34.0.0", + "sp-application-crypto 38.0.0", + "sp-core 34.0.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.29.0", + "sp-runtime 39.0.2", + "sp-runtime-interface 28.0.0", + "thiserror", + "x25519-dalek", +] + [[package]] name = "sp-std" version = "8.0.0" @@ -23154,11 +27582,24 @@ version = "26.0.0" dependencies = [ "async-trait", "parity-scale-codec", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "thiserror", ] +[[package]] +name = "sp-timestamp" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a1cb4df653d62ccc0dbce1db45d1c9443ec60247ee9576962d24da4c9c6f07" +dependencies = [ + "async-trait", + "parity-scale-codec", + "sp-inherents 34.0.0", + "sp-runtime 39.0.2", + "thiserror", +] + [[package]] name = "sp-tracing" version = "10.0.0" @@ -23196,14 +27637,14 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "17.0.0" +version = "17.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90b3decf116db9f1dfaf1f1597096b043d0e12c952d3bcdc018c6d6b77deec7e" +checksum = "cf641a1d17268c8fcfdb8e0fa51a79c2d4222f4cfda5f3944dbdbc384dced8d5" dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.18", ] [[package]] @@ -23214,6 +27655,16 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-transaction-pool" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4bf251059485a7dd38fe4afeda8792983511cc47f342ff4695e2dcae6b5247" +dependencies = [ + "sp-api 34.0.0", + "sp-runtime 39.0.2", +] + [[package]] name = "sp-transaction-storage-proof" version = "26.0.0" @@ -23222,11 +27673,26 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-trie 29.0.0", ] +[[package]] +name = "sp-transaction-storage-proof" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c765c2e9817d95f13d42a9f2295c60723464669765c6e5acbacebd2f54932f67" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-inherents 34.0.0", + "sp-runtime 39.0.2", + "sp-trie 37.0.0", +] + [[package]] name = "sp-trie" version = "29.0.0" @@ -23248,16 +27714,16 @@ dependencies = [ "thiserror", "tracing", "trie-bench", - "trie-db 0.29.1", + "trie-db", "trie-root", "trie-standardmap", ] [[package]] name = "sp-trie" -version = "32.0.0" +version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1aa91ad26c62b93d73e65f9ce7ebd04459c4bad086599348846a81988d6faa4" +checksum = "87727eced997f14d0f79e3a5186a80e38a9de87f6e9dc0baea5ebf8b7f9d8b66" dependencies = [ "ahash 0.8.11", "hash-db", @@ -23269,20 +27735,19 @@ dependencies = [ "rand", "scale-info", "schnellru", - "sp-core 31.0.0", - "sp-externalities 0.27.0", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-core 32.0.0", + "sp-externalities 0.28.0", "thiserror", "tracing", - "trie-db 0.28.0", + "trie-db", "trie-root", ] [[package]] name = "sp-trie" -version = "34.0.0" +version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87727eced997f14d0f79e3a5186a80e38a9de87f6e9dc0baea5ebf8b7f9d8b66" +checksum = "a61ab0c3e003f457203702e4753aa5fe9e762380543fada44650b1217e4aa5a5" dependencies = [ "ahash 0.8.11", "hash-db", @@ -23294,19 +27759,19 @@ dependencies = [ "rand", "scale-info", "schnellru", - "sp-core 32.0.0", + "sp-core 33.0.1", "sp-externalities 0.28.0", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", "trie-root", ] [[package]] name = "sp-trie" -version = "35.0.0" +version = "37.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61ab0c3e003f457203702e4753aa5fe9e762380543fada44650b1217e4aa5a5" +checksum = "6282aef9f4b6ecd95a67a45bcdb67a71f4a4155c09a53c10add4ffe823db18cd" dependencies = [ "ahash 0.8.11", "hash-db", @@ -23318,11 +27783,11 @@ dependencies = [ "rand", "scale-info", "schnellru", - "sp-core 33.0.1", - "sp-externalities 0.28.0", + "sp-core 34.0.0", + "sp-externalities 0.29.0", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", "trie-root", ] @@ -23360,16 +27825,34 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-version" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d521a405707b5be561367cd3d442ff67588993de24062ce3adefcf8437ee9fe1" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-version-proc-macro 14.0.0", + "thiserror", +] + [[package]] name = "sp-version-proc-macro" version = "13.0.0" dependencies = [ "parity-scale-codec", - "proc-macro-warning 1.0.0", + "proc-macro-warning", "proc-macro2 1.0.86", "quote 1.0.37", "sp-version 29.0.0", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -23381,7 +27864,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -23424,9 +27907,9 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "21.0.0" +version = "21.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b04b919e150b4736d85089d49327eab65507deb1485eec929af69daa2278eb3" +checksum = "b066baa6d57951600b14ffe1243f54c47f9c23dd89c262e17ca00ae8dca58be9" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -23449,22 +27932,6 @@ dependencies = [ "sp-debug-derive 14.0.0", ] -[[package]] -name = "sp-weights" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af6c661fe3066b29f9e1d258000f402ff5cc2529a9191972d214e5871d0ba87" -dependencies = [ - "bounded-collections", - "parity-scale-codec", - "scale-info", - "serde", - "smallvec", - "sp-arithmetic 25.0.0", - "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sp-weights" version = "31.0.0" @@ -23582,16 +28049,16 @@ dependencies = [ "clap_complete", "criterion", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.28.0", + "nix 0.29.0", "node-primitives", "node-rpc", "node-testing", "parity-scale-codec", "platforms", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "pretty_assertions", "rand", "regex", @@ -23600,7 +28067,7 @@ dependencies = [ "serde", "serde_json", "soketto 0.8.0", - "sp-keyring", + "sp-keyring 31.0.0", "staging-node-inspect", "substrate-cli-test-utils", "subxt-signer", @@ -23624,7 +28091,7 @@ dependencies = [ "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", "thiserror", ] @@ -23632,14 +28099,28 @@ dependencies = [ name = "staging-parachain-info" version = "0.7.0" dependencies = [ - "cumulus-primitives-core", - "frame-support", - "frame-system", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "scale-info", "sp-runtime 31.0.1", ] +[[package]] +name = "staging-parachain-info" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d28266dfddbfff721d70ad2f873380845b569adfab32f257cf97d9cedd894b68" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-runtime 39.0.2", +] + [[package]] name = "staging-tracking-allocator" version = "2.0.0" @@ -23652,6 +28133,7 @@ dependencies = [ "bounded-collections", "derivative", "environmental", + "frame-support 28.0.0", "hex", "hex-literal", "impl-trait-for-tuples", @@ -23663,7 +28145,27 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", - "xcm-procedural", + "xcm-procedural 7.0.0", +] + +[[package]] +name = "staging-xcm" +version = "14.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bee7cd999e9cdf10f8db72342070d456e21e82a0f5962ff3b87edbd5f2b20e" +dependencies = [ + "array-bytes", + "bounded-collections", + "derivative", + "environmental", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", + "xcm-procedural 10.1.0", ] [[package]] @@ -23671,20 +28173,20 @@ name = "staging-xcm-builder" version = "7.0.0" dependencies = [ "assert_matches", - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-salary", - "pallet-transaction-payment", - "pallet-xcm", + "pallet-asset-conversion 10.0.0", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-salary 13.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", "polkadot-test-runtime", "primitive-types 0.13.1", "scale-info", @@ -23693,8 +28195,31 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "staging-xcm-builder" +version = "17.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3746adbbae27b1e6763f0cca622e15482ebcb94835a9e078c212dd7be896e35" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "impl-trait-for-tuples", + "log", + "pallet-asset-conversion 20.0.0", + "pallet-transaction-payment 38.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 14.0.0", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", ] [[package]] @@ -23702,8 +28227,8 @@ name = "staging-xcm-executor" version = "7.0.0" dependencies = [ "environmental", - "frame-benchmarking", - "frame-support", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", @@ -23712,7 +28237,28 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", - "staging-xcm", + "staging-xcm 7.0.0", + "tracing", +] + +[[package]] +name = "staging-xcm-executor" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79dd0c5332a5318e58f0300b20768b71cf9427c906f94a743c9dc7c3ee9e7fa9" +dependencies = [ + "environmental", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-arithmetic 26.0.0", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", + "staging-xcm 14.2.0", "tracing", ] @@ -23850,7 +28396,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -23863,7 +28409,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -23934,7 +28480,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "futures", - "nix 0.28.0", + "nix 0.29.0", "node-primitives", "regex", "sc-cli", @@ -23966,9 +28512,9 @@ dependencies = [ name = "substrate-frame-rpc-support" version = "29.0.0" dependencies = [ - "frame-support", - "frame-system", - "jsonrpsee 0.24.3", + "frame-support 28.0.0", + "frame-system 28.0.0", + "jsonrpsee", "parity-scale-codec", "sc-rpc-api", "scale-info", @@ -23985,16 +28531,16 @@ version = "28.0.0" dependencies = [ "assert_matches", "docify", - "frame-system-rpc-runtime-api", + "frame-system-rpc-runtime-api 26.0.0", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "sc-rpc-api", "sc-transaction-pool", "sc-transaction-pool-api", "sp-api 26.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-blockchain", "sp-core 28.0.0", "sp-runtime 31.0.1", @@ -24023,34 +28569,34 @@ dependencies = [ "anyhow", "async-std", "async-trait", - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", + "bp-header-chain 0.7.0", + "bp-messages 0.7.0", + "bp-parachains 0.7.0", + "bp-polkadot-core 0.7.0", + "bp-relayers 0.7.0", + "bp-runtime 0.7.0", "equivocation-detector", "finality-relay", - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "futures", "hex", "log", "messages-relay", "num-traits", - "pallet-balances", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-grandpa", - "pallet-transaction-payment", + "pallet-balances 28.0.0", + "pallet-bridge-grandpa 0.7.0", + "pallet-bridge-messages 0.7.0", + "pallet-bridge-parachains 0.7.0", + "pallet-grandpa 28.0.0", + "pallet-transaction-payment 28.0.0", "parachains-relay", "parity-scale-codec", "rbtag", "relay-substrate-client", "relay-utils", "scale-info", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-trie 29.0.0", @@ -24064,7 +28610,7 @@ name = "substrate-rpc-client" version = "0.33.0" dependencies = [ "async-trait", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "sc-rpc-api", "serde", @@ -24085,7 +28631,7 @@ dependencies = [ "sp-core 32.0.0", "sp-io 35.0.0", "sp-runtime 36.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "thiserror", ] @@ -24093,7 +28639,7 @@ dependencies = [ name = "substrate-state-trie-migration-rpc" version = "27.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "parity-scale-codec", "sc-client-api", "sc-rpc-api", @@ -24103,7 +28649,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-trie 29.0.0", - "trie-db 0.29.1", + "trie-db", ] [[package]] @@ -24125,7 +28671,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", @@ -24137,16 +28683,16 @@ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ "array-bytes", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", "futures", "log", - "pallet-babe", - "pallet-balances", - "pallet-timestamp", + "pallet-babe 28.0.0", + "pallet-balances 28.0.0", + "pallet-timestamp 27.0.0", "parity-scale-codec", "sc-block-builder", "sc-chain-spec", @@ -24158,30 +28704,30 @@ dependencies = [ "serde_json", "sp-api 26.0.0", "sp-application-crypto 30.0.0", - "sp-block-builder", + "sp-block-builder 26.0.0", "sp-consensus", - "sp-consensus-aura", - "sp-consensus-babe", - "sp-consensus-grandpa", + "sp-consensus-aura 0.32.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-grandpa 13.0.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", - "sp-genesis-builder", - "sp-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", + "sp-session 27.0.0", "sp-state-machine 0.35.0", "sp-tracing 16.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-trie 29.0.0", "sp-version 29.0.0", "substrate-test-runtime-client", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", "tracing", - "trie-db 0.29.1", + "trie-db", ] [[package]] @@ -24236,12 +28782,12 @@ dependencies = [ "cargo_metadata", "console", "filetime", - "frame-metadata 16.0.0", + "frame-metadata 18.0.0", "jobserver", "merkleized-metadata", "parity-scale-codec", "parity-wasm", - "polkavm-linker 0.9.2", + "polkavm-linker 0.18.0", "sc-executor 0.32.0", "shlex", "sp-core 28.0.0", @@ -24256,6 +28802,27 @@ dependencies = [ "wasm-opt", ] +[[package]] +name = "substrate-wasm-builder" +version = "24.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf035ffe7335fb24053edfe4d0a5780250eda772082a1b80ae25835dd4c09265" +dependencies = [ + "build-helper", + "cargo_metadata", + "console", + "filetime", + "jobserver", + "parity-wasm", + "polkavm-linker 0.9.2", + "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strum 0.26.3", + "tempfile", + "toml 0.8.12", + "walkdir", + "wasm-opt", +] + [[package]] name = "subtle" version = "1.0.0" @@ -24286,7 +28853,7 @@ dependencies = [ "log", "num-format", "rand", - "reqwest 0.12.5", + "reqwest 0.12.9", "scale-info", "semver 1.0.18", "serde", @@ -24302,101 +28869,99 @@ dependencies = [ [[package]] name = "subxt" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a160cba1edbf3ec4fbbeaea3f1a185f70448116a6bccc8276bb39adb3b3053bd" +checksum = "c53029d133e4e0cb7933f1fe06f2c68804b956de9bb8fa930ffca44e9e5e4230" dependencies = [ "async-trait", "derive-where", "either", - "frame-metadata 16.0.0", + "finito", + "frame-metadata 17.0.0", "futures", "hex", - "impl-serde 0.4.0", - "instant", - "jsonrpsee 0.22.5", + "impl-serde 0.5.0", + "jsonrpsee", "parity-scale-codec", - "primitive-types 0.12.2", - "reconnecting-jsonrpsee-ws-client", + "polkadot-sdk 0.7.0", + "primitive-types 0.13.1", "scale-bits", - "scale-decode", + "scale-decode 0.14.0", "scale-encode", "scale-info", "scale-value", "serde", "serde_json", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subxt-core", "subxt-lightclient", "subxt-macro", "subxt-metadata", "thiserror", + "tokio", "tokio-util", "tracing", "url", + "wasm-bindgen-futures", + "web-time", ] [[package]] name = "subxt-codegen" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d703dca0905cc5272d7cc27a4ac5f37dcaae7671acc7fef0200057cc8c317786" +checksum = "3cfcfb7d9589f3df0ac87c4988661cf3fb370761fcb19f2fd33104cc59daf22a" dependencies = [ - "frame-metadata 16.0.0", "heck 0.5.0", - "hex", - "jsonrpsee 0.22.5", "parity-scale-codec", "proc-macro2 1.0.86", "quote 1.0.37", "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.82", + "syn 2.0.87", "thiserror", - "tokio", ] [[package]] name = "subxt-core" -version = "0.37.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af3b36405538a36b424d229dc908d1396ceb0994c90825ce928709eac1a159a" +checksum = "7ea28114366780d23684bd55ab879cd04c9d4cbba3b727a3854a3eca6bf29a1a" dependencies = [ "base58", "blake2 0.10.6", "derive-where", - "frame-metadata 16.0.0", + "frame-decode", + "frame-metadata 17.0.0", "hashbrown 0.14.5", "hex", - "impl-serde 0.4.0", + "impl-serde 0.5.0", + "keccak-hash", "parity-scale-codec", - "primitive-types 0.12.2", + "polkadot-sdk 0.7.0", + "primitive-types 0.13.1", "scale-bits", - "scale-decode", + "scale-decode 0.14.0", "scale-encode", "scale-info", "scale-value", "serde", "serde_json", - "sp-core 31.0.0", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-runtime 34.0.0", "subxt-metadata", "tracing", ] [[package]] name = "subxt-lightclient" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9406fbdb9548c110803cb8afa750f8b911d51eefdf95474b11319591d225d9" +checksum = "534d4b725183a9fa09ce0e0f135674473297fdd97dee4d683f41117f365ae997" dependencies = [ "futures", "futures-util", "serde", "serde_json", - "smoldot-light 0.14.0", + "smoldot-light 0.16.2", "thiserror", "tokio", "tokio-stream", @@ -24405,56 +28970,74 @@ dependencies = [ [[package]] name = "subxt-macro" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c195f803d70687e409aba9be6c87115b5da8952cd83c4d13f2e043239818fcd" +checksum = "228db9a5c95a6d8dc6152b4d6cdcbabc4f60821dd3f482a4f8791e022b7caadb" dependencies = [ - "darling 0.20.10", + "darling", "parity-scale-codec", - "proc-macro-error", + "proc-macro-error2", "quote 1.0.37", "scale-typegen", "subxt-codegen", - "syn 2.0.82", + "subxt-utils-fetchmetadata", + "syn 2.0.87", ] [[package]] name = "subxt-metadata" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738be5890fdeff899bbffff4d9c0f244fe2a952fb861301b937e3aa40ebb55da" +checksum = "ee13e6862eda035557d9a2871955306aff540d2b89c06e0a62a1136a700aed28" dependencies = [ - "frame-metadata 16.0.0", + "frame-decode", + "frame-metadata 17.0.0", "hashbrown 0.14.5", "parity-scale-codec", + "polkadot-sdk 0.7.0", "scale-info", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "subxt-signer" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49888ae6ae90fe01b471193528eea5bd4ed52d8eecd2d13f4a2333b87388850" +checksum = "1e7a336d6a1f86f126100a4a717be58352de4c8214300c4f7807f974494efdb9" dependencies = [ + "base64 0.22.1", "bip32", "bip39", "cfg-if", + "crypto_secretbox", "hex", "hmac 0.12.1", "keccak-hash", "parity-scale-codec", "pbkdf2", + "polkadot-sdk 0.7.0", "regex", "schnorrkel 0.11.4", - "secp256k1", - "secrecy", + "scrypt", + "secp256k1 0.30.0", + "secrecy 0.10.3", + "serde", + "serde_json", "sha2 0.10.8", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subxt-core", "zeroize", ] +[[package]] +name = "subxt-utils-fetchmetadata" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082b17a86e3c3fe45d858d94d68f6b5247caace193dad6201688f24db8ba9bb" +dependencies = [ + "hex", + "parity-scale-codec", + "thiserror", +] + [[package]] name = "sval" version = "2.6.1" @@ -24570,9 +29153,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.82" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", @@ -24588,14 +29171,35 @@ dependencies = [ "paste", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", +] + +[[package]] +name = "syn-solidity" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219389c1ebe89f8333df8bdfb871f6631c552ff399c23cac02480b6088aad8f0" +dependencies = [ + "paste", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -24617,7 +29221,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -24688,7 +29292,7 @@ dependencies = [ "cfg-if", "fastrand 2.1.0", "redox_syscall 0.4.1", - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -24718,7 +29322,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -24747,7 +29351,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -24756,9 +29360,9 @@ version = "1.0.0" dependencies = [ "dlmalloc", "parity-scale-codec", - "polkadot-parachain-primitives", + "polkadot-parachain-primitives 6.0.0", "sp-io 30.0.0", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", "tiny-keccak", ] @@ -24775,14 +29379,14 @@ dependencies = [ "polkadot-node-core-pvf", "polkadot-node-primitives", "polkadot-node-subsystem", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-service", "polkadot-test-service", "sc-cli", "sc-service", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "substrate-test-utils", "test-parachain-adder", "tokio", @@ -24793,7 +29397,7 @@ name = "test-parachain-halt" version = "1.0.0" dependencies = [ "rustversion", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -24803,9 +29407,9 @@ dependencies = [ "dlmalloc", "log", "parity-scale-codec", - "polkadot-parachain-primitives", + "polkadot-parachain-primitives 6.0.0", "sp-io 30.0.0", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", "tiny-keccak", ] @@ -24822,14 +29426,14 @@ dependencies = [ "polkadot-node-core-pvf", "polkadot-node-primitives", "polkadot-node-subsystem", - "polkadot-parachain-primitives", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-service", "polkadot-test-service", "sc-cli", "sc-service", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "substrate-test-utils", "test-parachain-undying", "tokio", @@ -24850,8 +29454,8 @@ dependencies = [ name = "test-runtime-constants" version = "1.0.0" dependencies = [ - "frame-support", - "polkadot-primitives", + "frame-support 28.0.0", + "polkadot-primitives 7.0.0", "smallvec", "sp-runtime 31.0.1", ] @@ -24860,14 +29464,30 @@ dependencies = [ name = "testnet-parachains-constants" version = "1.0.0" dependencies = [ - "cumulus-primitives-core", - "frame-support", - "polkadot-core-primitives", - "rococo-runtime-constants", + "cumulus-primitives-core 0.7.0", + "frame-support 28.0.0", + "polkadot-core-primitives 7.0.0", + "rococo-runtime-constants 7.0.0", "smallvec", "sp-runtime 31.0.1", - "staging-xcm", - "westend-runtime-constants", + "staging-xcm 7.0.0", + "westend-runtime-constants 7.0.0", +] + +[[package]] +name = "testnet-parachains-constants" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bceae6f7c89d47daff6c7e05f712551a01379f61b07d494661941144878589" +dependencies = [ + "cumulus-primitives-core 0.16.0", + "frame-support 38.0.0", + "polkadot-core-primitives 15.0.0", + "rococo-runtime-constants 17.0.0", + "smallvec", + "sp-runtime 39.0.2", + "staging-xcm 14.2.0", + "westend-runtime-constants 17.0.0", ] [[package]] @@ -24922,7 +29542,7 @@ checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -25084,7 +29704,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -25118,24 +29738,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" -dependencies = [ - "rustls 0.22.4", - "rustls-pki-types", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.14", + "rustls 0.23.18", "rustls-pki-types", "tokio", ] @@ -25182,9 +29791,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -25243,7 +29852,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -25256,7 +29865,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.7.0", "toml_datetime", "winnow 0.5.15", ] @@ -25267,7 +29876,7 @@ version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -25360,7 +29969,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -25388,7 +29997,7 @@ name = "tracing-gum" version = "7.0.0" dependencies = [ "coarsetime", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "tracing", "tracing-gum-proc-macro", ] @@ -25402,7 +30011,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -25491,24 +30100,11 @@ dependencies = [ "keccak-hasher", "memory-db", "parity-scale-codec", - "trie-db 0.29.1", + "trie-db", "trie-root", "trie-standardmap", ] -[[package]] -name = "trie-db" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff28e0f815c2fea41ebddf148e008b077d2faddb026c9555b29696114d602642" -dependencies = [ - "hash-db", - "hashbrown 0.13.2", - "log", - "rustc-hex", - "smallvec", -] - [[package]] name = "trie-db" version = "0.29.1" @@ -25540,78 +30136,6 @@ dependencies = [ "keccak-hasher", ] -[[package]] -name = "trust-dns-proto" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner 0.5.1", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "rand", - "smallvec", - "socket2 0.4.9", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "trust-dns-proto" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner 0.6.0", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.4.0", - "ipnet", - "once_cell", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot 0.12.3", - "rand", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto 0.23.2", -] - [[package]] name = "try-lock" version = "0.2.4" @@ -25821,7 +30345,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" dependencies = [ - "asynchronous-codec", + "asynchronous-codec 0.6.2", "bytes", "futures-io", "futures-util", @@ -25859,7 +30383,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.14", + "rustls 0.23.18", "rustls-pki-types", "serde", "serde_json", @@ -26032,9 +30556,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -26045,24 +30569,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -26072,9 +30596,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote 1.0.37", "wasm-bindgen-macro-support", @@ -26082,22 +30606,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-bindgen-test" @@ -26217,7 +30741,7 @@ dependencies = [ "sp-runtime 37.0.0", "sp-state-machine 0.41.0", "sp-version 35.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "substrate-runtime-proposal-hash", "thiserror", "wasm-loader", @@ -26554,13 +31078,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -26584,19 +31118,19 @@ name = "westend-emulated-chain" version = "0.0.0" dependencies = [ "emulated-integration-tests-common", - "pallet-staking", - "parachains-common", - "polkadot-primitives", + "pallet-staking 28.0.0", + "parachains-common 7.0.0", + "polkadot-primitives 7.0.0", "sc-consensus-grandpa", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", + "sp-authority-discovery 26.0.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", "sp-core 28.0.0", "sp-runtime 31.0.1", - "staging-xcm", + "staging-xcm 7.0.0", "westend-runtime", - "westend-runtime-constants", - "xcm-runtime-apis", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -26604,77 +31138,77 @@ name = "westend-runtime" version = "7.0.0" dependencies = [ "approx", - "binary-merkle-tree", + "binary-merkle-tree 13.0.0", "bitvec", - "frame-benchmarking", - "frame-election-provider-support", - "frame-executive", - "frame-metadata-hash-extension", + "frame-benchmarking 28.0.0", + "frame-election-provider-support 28.0.0", + "frame-executive 28.0.0", + "frame-metadata-hash-extension 0.1.0", "frame-remote-externalities", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-system-benchmarking 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", "hex-literal", "log", - "pallet-asset-rate", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-bags-list", - "pallet-balances", - "pallet-beefy", - "pallet-beefy-mmr", - "pallet-collective", - "pallet-conviction-voting", - "pallet-delegated-staking", - "pallet-democracy", - "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", - "pallet-fast-unstake", - "pallet-grandpa", - "pallet-identity", - "pallet-indices", - "pallet-membership", - "pallet-message-queue", - "pallet-migrations", - "pallet-mmr", - "pallet-multisig", - "pallet-nomination-pools", - "pallet-nomination-pools-benchmarking", - "pallet-nomination-pools-runtime-api", - "pallet-offences", - "pallet-offences-benchmarking", - "pallet-parameters", - "pallet-preimage", - "pallet-proxy", - "pallet-recovery", - "pallet-referenda", - "pallet-root-testing", - "pallet-scheduler", - "pallet-session", - "pallet-session-benchmarking", - "pallet-society", - "pallet-staking", - "pallet-staking-runtime-api", - "pallet-state-trie-migration", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-treasury", - "pallet-utility", - "pallet-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-runtime-parachains", + "pallet-asset-rate 7.0.0", + "pallet-authority-discovery 28.0.0", + "pallet-authorship 28.0.0", + "pallet-babe 28.0.0", + "pallet-bags-list 27.0.0", + "pallet-balances 28.0.0", + "pallet-beefy 28.0.0", + "pallet-beefy-mmr 28.0.0", + "pallet-collective 28.0.0", + "pallet-conviction-voting 28.0.0", + "pallet-delegated-staking 1.0.0", + "pallet-democracy 28.0.0", + "pallet-election-provider-multi-phase 27.0.0", + "pallet-election-provider-support-benchmarking 27.0.0", + "pallet-elections-phragmen 29.0.0", + "pallet-fast-unstake 27.0.0", + "pallet-grandpa 28.0.0", + "pallet-identity 29.0.0", + "pallet-indices 28.0.0", + "pallet-membership 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-migrations 1.0.0", + "pallet-mmr 27.0.0", + "pallet-multisig 28.0.0", + "pallet-nomination-pools 25.0.0", + "pallet-nomination-pools-benchmarking 26.0.0", + "pallet-nomination-pools-runtime-api 23.0.0", + "pallet-offences 27.0.0", + "pallet-offences-benchmarking 28.0.0", + "pallet-parameters 0.1.0", + "pallet-preimage 28.0.0", + "pallet-proxy 28.0.0", + "pallet-recovery 28.0.0", + "pallet-referenda 28.0.0", + "pallet-root-testing 4.0.0", + "pallet-scheduler 29.0.0", + "pallet-session 28.0.0", + "pallet-session-benchmarking 28.0.0", + "pallet-society 28.0.0", + "pallet-staking 28.0.0", + "pallet-staking-runtime-api 14.0.0", + "pallet-state-trie-migration 29.0.0", + "pallet-sudo 28.0.0", + "pallet-timestamp 27.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "pallet-treasury 27.0.0", + "pallet-utility 28.0.0", + "pallet-vesting 28.0.0", + "pallet-whitelist 27.0.0", + "pallet-xcm 7.0.0", + "pallet-xcm-benchmarks 7.0.0", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "serde", "serde_derive", @@ -26683,49 +31217,66 @@ dependencies = [ "sp-api 26.0.0", "sp-application-crypto 30.0.0", "sp-arithmetic 23.0.0", - "sp-authority-discovery", - "sp-block-builder", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-consensus-grandpa", - "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", + "sp-authority-discovery 26.0.0", + "sp-block-builder 26.0.0", + "sp-consensus-babe 0.32.0", + "sp-consensus-beefy 13.0.0", + "sp-consensus-grandpa 13.0.0", + "sp-core 28.0.0", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "sp-keyring", - "sp-mmr-primitives", - "sp-npos-elections", - "sp-offchain", + "sp-keyring 31.0.0", + "sp-mmr-primitives 26.0.0", + "sp-npos-elections 26.0.0", + "sp-offchain 26.0.0", "sp-runtime 31.0.1", - "sp-session", - "sp-staking", + "sp-session 27.0.0", + "sp-staking 26.0.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", - "sp-transaction-pool", + "sp-transaction-pool 26.0.0", "sp-version 29.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "substrate-wasm-builder 17.0.0", "tiny-keccak", "tokio", - "westend-runtime-constants", - "xcm-runtime-apis", + "westend-runtime-constants 7.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] name = "westend-runtime-constants" version = "7.0.0" dependencies = [ - "frame-support", - "polkadot-primitives", - "polkadot-runtime-common", + "frame-support 28.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-common 7.0.0", "smallvec", "sp-core 28.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", - "staging-xcm", - "staging-xcm-builder", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", +] + +[[package]] +name = "westend-runtime-constants" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06861bf945aadac59f4be23b44c85573029520ea9bd3d6c9ab21c8b306e81cdc" +dependencies = [ + "frame-support 38.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-common 17.0.0", + "smallvec", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -26836,6 +31387,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -27078,16 +31659,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wyz" version = "0.5.1" @@ -27109,35 +31680,18 @@ dependencies = [ "zeroize", ] -[[package]] -name = "x509-parser" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" -dependencies = [ - "asn1-rs 0.5.2", - "data-encoding", - "der-parser 8.2.0", - "lazy_static", - "nom", - "oid-registry 0.6.1", - "rusticata-macros", - "thiserror", - "time", -] - [[package]] name = "x509-parser" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs", "data-encoding", - "der-parser 9.0.0", + "der-parser", "lazy_static", "nom", - "oid-registry 0.7.0", + "oid-registry", "rusticata-macros", "thiserror", "time", @@ -27157,24 +31711,24 @@ name = "xcm-docs" version = "0.1.0" dependencies = [ "docify", - "pallet-balances", - "pallet-message-queue", - "pallet-xcm", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", - "polkadot-sdk-frame", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", + "polkadot-sdk-frame 0.1.0", "scale-info", "simple-mermaid 0.1.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", "test-log", - "xcm-simulator", + "xcm-simulator 7.0.0", ] [[package]] @@ -27182,23 +31736,23 @@ name = "xcm-emulator" version = "0.5.0" dependencies = [ "array-bytes", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-test-relay-sproof-builder", - "frame-support", - "frame-system", + "cumulus-pallet-parachain-system 0.7.0", + "cumulus-pallet-xcmp-queue 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-primitives-parachain-inherent 0.7.0", + "cumulus-test-relay-sproof-builder 0.7.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "log", - "pallet-balances", - "pallet-message-queue", - "parachains-common", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "parachains-common 7.0.0", "parity-scale-codec", "paste", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", @@ -27206,30 +31760,33 @@ dependencies = [ "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", ] [[package]] name = "xcm-executor-integration-tests" version = "1.0.0" dependencies = [ - "frame-support", + "frame-support 28.0.0", + "frame-system 28.0.0", "futures", - "pallet-transaction-payment", - "pallet-xcm", + "pallet-sudo 28.0.0", + "pallet-transaction-payment 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", + "polkadot-runtime-parachains 7.0.0", "polkadot-test-client", "polkadot-test-runtime", "polkadot-test-service", "sp-consensus", "sp-core 28.0.0", - "sp-keyring", + "sp-keyring 31.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", ] [[package]] @@ -27237,82 +31794,133 @@ name = "xcm-procedural" version = "7.0.0" dependencies = [ "Inflector", + "frame-support 28.0.0", "proc-macro2 1.0.86", "quote 1.0.37", - "staging-xcm", - "syn 2.0.82", + "staging-xcm 7.0.0", + "syn 2.0.87", "trybuild", ] +[[package]] +name = "xcm-procedural" +version = "10.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fb4f14094d65c500a59bcf540cf42b99ee82c706edd6226a92e769ad60563e" +dependencies = [ + "Inflector", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "xcm-runtime-apis" version = "0.1.0" dependencies = [ - "frame-executive", - "frame-support", - "frame-system", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "hex-literal", "log", - "pallet-assets", - "pallet-balances", - "pallet-xcm", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", "scale-info", "sp-api 26.0.0", "sp-io 30.0.0", "sp-tracing 16.0.0", "sp-weights 27.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "xcm-runtime-apis" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d4473a5d157e4d437d9ebcb1b99f9693a64983877ee57d97005f0167869935" +dependencies = [ + "frame-support 38.0.0", + "parity-scale-codec", + "scale-info", + "sp-api 34.0.0", + "sp-weights 31.0.0", + "staging-xcm 14.2.0", + "staging-xcm-executor 17.0.0", ] [[package]] name = "xcm-simulator" version = "7.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "parity-scale-codec", "paste", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-parachains", + "polkadot-core-primitives 7.0.0", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", +] + +[[package]] +name = "xcm-simulator" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058e21bfc3e1180bbd83cad3690d0e63f34f43ab309e338afe988160aa776fcf" +dependencies = [ + "frame-support 38.0.0", + "frame-system 38.0.0", + "parity-scale-codec", + "paste", + "polkadot-core-primitives 15.0.0", + "polkadot-parachain-primitives 14.0.0", + "polkadot-primitives 16.0.0", + "polkadot-runtime-parachains 17.0.1", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "staging-xcm 14.2.0", + "staging-xcm-builder 17.0.1", + "staging-xcm-executor 17.0.0", ] [[package]] name = "xcm-simulator-example" version = "7.0.0" dependencies = [ - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", - "pallet-balances", - "pallet-message-queue", - "pallet-uniques", - "pallet-xcm", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-uniques 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", + "polkadot-core-primitives 7.0.0", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "xcm-simulator", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "xcm-simulator 7.0.0", ] [[package]] @@ -27320,27 +31928,27 @@ name = "xcm-simulator-fuzzer" version = "1.0.0" dependencies = [ "arbitrary", - "frame-executive", - "frame-support", - "frame-system", - "frame-try-runtime", + "frame-executive 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "frame-try-runtime 0.34.0", "honggfuzz", - "pallet-balances", - "pallet-message-queue", - "pallet-xcm", + "pallet-balances 28.0.0", + "pallet-message-queue 31.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-runtime-parachains", + "polkadot-core-primitives 7.0.0", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-parachains 7.0.0", "scale-info", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "xcm-simulator", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "xcm-simulator 7.0.0", ] [[package]] @@ -27373,6 +31981,22 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "yamux" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot 0.12.3", + "pin-project", + "rand", + "static_assertions", + "web-time", +] + [[package]] name = "yansi" version = "0.5.1" @@ -27411,7 +32035,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -27431,7 +32055,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.87", ] [[package]] @@ -27440,7 +32064,7 @@ version = "1.0.0" dependencies = [ "futures-util", "parity-scale-codec", - "reqwest 0.11.20", + "reqwest 0.12.9", "serde", "serde_json", "thiserror", @@ -27452,15 +32076,15 @@ dependencies = [ [[package]] name = "zombienet-configuration" -version = "0.2.13" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbfc98adb25076777967f7aad078e74029e129b102eb0812c425432f8c2be7b" +checksum = "d716b3ff8112d98ced15f53b0c72454f8cde533fe2b68bb04379228961efbd80" dependencies = [ "anyhow", "lazy_static", "multiaddr 0.18.1", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -27472,21 +32096,21 @@ dependencies = [ [[package]] name = "zombienet-orchestrator" -version = "0.2.13" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b17f4d1d05b3aedf02818eb0f4d5a76664da0e07bb2f7e7d02613e0ef0f316a" +checksum = "4098a7d33b729b59e32c41a87aa4d484bd1b8771a059bbd4edfb4d430b3b2d74" dependencies = [ "anyhow", "async-trait", "futures", "glob-match", "hex", - "libp2p", + "libp2p 0.52.4", "libsecp256k1", "multiaddr 0.18.1", "rand", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "sha2 0.10.8", @@ -27505,9 +32129,9 @@ dependencies = [ [[package]] name = "zombienet-prom-metrics-parser" -version = "0.2.13" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7203390ab88919240da3a3eb06b625b6e300e94f98e04ba5141e9138dc663b7d" +checksum = "961e30be45b34f6ebeabf29ee2f47b0cd191ea62e40c064752572207509a6f5c" dependencies = [ "pest", "pest_derive", @@ -27516,9 +32140,9 @@ dependencies = [ [[package]] name = "zombienet-provider" -version = "0.2.13" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee02ee957ec39b698798fa6dc2a0d5ba4524198471c37d57755e9685b67fb50c" +checksum = "ab0f7f01780b7c99a6c40539d195d979f234305f32808d547438b50829d44262" dependencies = [ "anyhow", "async-trait", @@ -27529,7 +32153,7 @@ dependencies = [ "kube", "nix 0.27.1", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "serde_yaml", @@ -27547,14 +32171,15 @@ dependencies = [ [[package]] name = "zombienet-sdk" -version = "0.2.13" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f594e67922182277a3da0926f21b693eb5a0c38b32ca7fd6ef16167809fe5064" +checksum = "99a3c5f2d657235b3ab7dc384677e63cde21983029e99106766ecd49e9f8d7f3" dependencies = [ "async-trait", "futures", "lazy_static", "subxt", + "subxt-signer", "tokio", "zombienet-configuration", "zombienet-orchestrator", @@ -27564,9 +32189,9 @@ dependencies = [ [[package]] name = "zombienet-support" -version = "0.2.13" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d3144537df7c8939bbb355cc5245a6dc0078446a6cdaf9272268bd1043c788" +checksum = "296f887ea88e07edd771f8e1d0dec5297a58b422f4b884a6292a21ebe03277cb" dependencies = [ "anyhow", "async-trait", @@ -27574,7 +32199,7 @@ dependencies = [ "nix 0.27.1", "rand", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "thiserror", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index f3042a8a3bdf..64a11a340d10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -293,6 +293,7 @@ members = [ "substrate/client/rpc-api", "substrate/client/rpc-servers", "substrate/client/rpc-spec-v2", + "substrate/client/runtime-utilities", "substrate/client/service", "substrate/client/service/test", "substrate/client/state-db", @@ -594,8 +595,7 @@ zero-prefixed-literal = { level = "allow", priority = 2 } # 00_1000_0 Inflector = { version = "0.11.4" } aes-gcm = { version = "0.10" } ahash = { version = "0.8.2" } -alloy-primitives = { version = "0.4.2", default-features = false } -alloy-sol-types = { version = "0.4.2", default-features = false } +alloy-core = { version = "0.8.15", default-features = false } always-assert = { version = "0.1" } anyhow = { version = "1.0.81", default-features = false } approx = { version = "0.5.1" } @@ -637,7 +637,7 @@ bitvec = { version = "1.0.1", default-features = false } blake2 = { version = "0.10.4", default-features = false } blake2b_simd = { version = "1.0.2", default-features = false } blake3 = { version = "1.5" } -bounded-collections = { version = "0.2.0", default-features = false } +bounded-collections = { version = "0.2.2", default-features = false } bounded-vec = { version = "0.7" } bp-asset-hub-rococo = { path = "bridges/chains/chain-asset-hub-rococo", default-features = false } bp-asset-hub-westend = { path = "bridges/chains/chain-asset-hub-westend", default-features = false } @@ -754,7 +754,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" } +ethabi = { version = "2.0.0", default-features = false, package = "ethabi-decode" } ethbloom = { version = "0.14.1", default-features = false } ethereum-types = { version = "0.15.1", default-features = false } exit-future = { version = "0.2.0" } @@ -779,7 +779,7 @@ frame-benchmarking-pallet-pov = { default-features = false, path = "substrate/fr frame-election-provider-solution-type = { path = "substrate/frame/election-provider-support/solution-type", default-features = false } frame-election-provider-support = { path = "substrate/frame/election-provider-support", default-features = false } frame-executive = { path = "substrate/frame/executive", default-features = false } -frame-metadata = { version = "16.0.0", default-features = false } +frame-metadata = { version = "18.0.0", default-features = false } frame-metadata-hash-extension = { path = "substrate/frame/metadata-hash-extension", default-features = false } frame-support = { path = "substrate/frame/support", default-features = false } frame-support-procedural = { path = "substrate/frame/support/procedural", default-features = false } @@ -792,7 +792,7 @@ frame-system-rpc-runtime-api = { path = "substrate/frame/system/rpc/runtime-api" frame-try-runtime = { path = "substrate/frame/try-runtime", default-features = false } fs4 = { version = "0.7.0" } fs_extra = { version = "1.3.0" } -futures = { version = "0.3.30" } +futures = { version = "0.3.31" } futures-channel = { version = "0.3.23" } futures-timer = { version = "3.0.2" } futures-util = { version = "0.3.30", default-features = false } @@ -841,20 +841,20 @@ kvdb-shared-tests = { version = "0.11.0" } landlock = { version = "0.3.0" } libc = { version = "0.2.155" } libfuzzer-sys = { version = "0.4" } -libp2p = { version = "0.52.4" } +libp2p = { version = "0.54.1" } libp2p-identity = { version = "0.2.9" } libsecp256k1 = { version = "0.7.0", default-features = false } linked-hash-map = { version = "0.5.4" } linked_hash_set = { version = "0.1.4" } linregress = { version = "0.5.1" } lite-json = { version = "0.2.0", default-features = false } -litep2p = { version = "0.7.0", features = ["websocket"] } +litep2p = { version = "0.8.4", features = ["websocket"] } log = { version = "0.4.22", default-features = false } macro_magic = { version = "0.5.1" } maplit = { version = "1.0.2" } memmap2 = { version = "0.9.3" } memory-db = { version = "0.32.0", default-features = false } -merkleized-metadata = { version = "0.1.0" } +merkleized-metadata = { version = "0.2.0" } merlin = { version = "3.0", default-features = false } messages-relay = { path = "bridges/relays/messages" } metered = { version = "0.6.1", default-features = false, package = "prioritized-metered-channel" } @@ -871,7 +871,7 @@ multihash = { version = "0.19.1", default-features = false } multihash-codetable = { version = "0.1.1" } multistream-select = { version = "0.13.0" } names = { version = "0.14.0", default-features = false } -nix = { version = "0.28.0" } +nix = { version = "0.29.0" } node-cli = { path = "substrate/bin/node/cli", package = "staging-node-cli" } node-inspect = { path = "substrate/bin/node/inspect", default-features = false, package = "staging-node-inspect" } node-primitives = { path = "substrate/bin/node/primitives", default-features = false } @@ -1089,9 +1089,9 @@ polkadot-subsystem-bench = { path = "polkadot/node/subsystem-bench" } polkadot-test-client = { path = "polkadot/node/test/client" } polkadot-test-runtime = { path = "polkadot/runtime/test-runtime" } polkadot-test-service = { path = "polkadot/node/test/service" } -polkavm = { version = "0.9.3", default-features = false } -polkavm-derive = "0.9.1" -polkavm-linker = "0.9.2" +polkavm = { version = "0.18.0", default-features = false } +polkavm-derive = "0.18.0" +polkavm-linker = "0.18.0" portpicker = { version = "0.1.1" } pretty_assertions = { version = "1.3.0" } primitive-types = { version = "0.13.1", default-features = false, features = [ @@ -1123,7 +1123,7 @@ regex = { version = "1.10.2" } relay-substrate-client = { path = "bridges/relays/client-substrate" } relay-utils = { path = "bridges/relays/utils" } remote-externalities = { path = "substrate/utils/frame/remote-externalities", default-features = false, package = "frame-remote-externalities" } -reqwest = { version = "0.11", default-features = false } +reqwest = { version = "0.12.9", default-features = false } rlp = { version = "0.6.1", default-features = false } rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/rococo" } rococo-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/rococo-parachain" } @@ -1136,7 +1136,7 @@ rstest = { version = "0.18.2" } rustc-hash = { version = "1.1.0" } rustc-hex = { version = "2.1.0", default-features = false } rustix = { version = "0.36.7", default-features = false } -rustls = { version = "0.23.14", default-features = false, features = ["logging", "ring", "std", "tls12"] } +rustls = { version = "0.23.18", default-features = false, features = ["logging", "ring", "std", "tls12"] } rustversion = { version = "1.0.17" } rusty-fork = { version = "0.3.0", default-features = false } safe-mix = { version = "1.0", default-features = false } @@ -1184,6 +1184,7 @@ sc-rpc-api = { path = "substrate/client/rpc-api", default-features = false } sc-rpc-server = { path = "substrate/client/rpc-servers", default-features = false } sc-rpc-spec-v2 = { path = "substrate/client/rpc-spec-v2", default-features = false } sc-runtime-test = { path = "substrate/client/executor/runtime-test" } +sc-runtime-utilities = { path = "substrate/client/runtime-utilities", default-features = true } sc-service = { path = "substrate/client/service", default-features = false } sc-service-test = { path = "substrate/client/service/test" } sc-state-db = { path = "substrate/client/state-db", default-features = false } @@ -1197,7 +1198,7 @@ sc-tracing-proc-macro = { path = "substrate/client/tracing/proc-macro", default- sc-transaction-pool = { path = "substrate/client/transaction-pool", default-features = false } sc-transaction-pool-api = { path = "substrate/client/transaction-pool/api", default-features = false } sc-utils = { path = "substrate/client/utils", default-features = false } -scale-info = { version = "2.11.1", default-features = false } +scale-info = { version = "2.11.6", default-features = false } schemars = { version = "0.8.13", default-features = false } schnellru = { version = "0.2.3" } schnorrkel = { version = "0.11.4", default-features = false } @@ -1205,12 +1206,11 @@ seccompiler = { version = "0.4.0" } secp256k1 = { version = "0.28.0", default-features = false } secrecy = { version = "0.8.0", default-features = false } separator = { version = "0.4.1" } -serde = { version = "1.0.210", default-features = false } +serde = { version = "1.0.214", default-features = false } serde-big-array = { version = "0.3.2" } serde_derive = { version = "1.0.117" } serde_json = { version = "1.0.132", default-features = false } serde_yaml = { version = "0.9" } -serial_test = { version = "2.0.0" } sha1 = { version = "0.10.6" } sha2 = { version = "0.10.7", default-features = false } sha3 = { version = "0.10.0", default-features = false } @@ -1317,9 +1317,10 @@ 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 } -subxt = { version = "0.37", default-features = false } -subxt-signer = { version = "0.37" } -syn = { version = "2.0.82" } +subxt = { version = "0.38", default-features = false } +subxt-metadata = { version = "0.38.0", default-features = false } +subxt-signer = { version = "0.38" } +syn = { version = "2.0.87" } sysinfo = { version = "0.30" } tar = { version = "0.4" } tempfile = { version = "3.8.1" } @@ -1388,7 +1389,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" } +zombienet-sdk = { version = "0.2.19" } zstd = { version = "0.12.4", default-features = false } [profile.release] diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 37b56140c289..49cd086fd3eb 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -99,6 +99,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-trie", + "xcm/runtime-benchmarks", ] integrity-test = ["static_assertions"] test-helpers = ["bp-runtime/test-helpers", "sp-trie"] diff --git a/bridges/bin/runtime-common/src/extensions.rs b/bridges/bin/runtime-common/src/extensions.rs index 19d1554c668b..44e6b40b7e0c 100644 --- a/bridges/bin/runtime-common/src/extensions.rs +++ b/bridges/bin/runtime-common/src/extensions.rs @@ -299,6 +299,7 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl codec::Encode, + _source: sp_runtime::transaction_validity::TransactionSource, ) -> Result< ( sp_runtime::transaction_validity::ValidTransaction, @@ -390,7 +391,9 @@ mod tests { parameter_types, AsSystemOriginSigner, AsTransactionAuthorizedOrigin, ConstU64, DispatchTransaction, Header as _, TransactionExtension, }, - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + transaction_validity::{ + InvalidTransaction, TransactionSource::External, TransactionValidity, ValidTransaction, + }, DispatchError, }; @@ -610,7 +613,9 @@ mod tests { 42u64.into(), &MockCall { data: 1 }, &(), - 0 + 0, + External, + 0, ), InvalidTransaction::Custom(1) ); @@ -619,7 +624,8 @@ mod tests { 42u64.into(), &MockCall { data: 1 }, &(), - 0 + 0, + 0, ), InvalidTransaction::Custom(1) ); @@ -629,7 +635,9 @@ mod tests { 42u64.into(), &MockCall { data: 2 }, &(), - 0 + 0, + External, + 0, ), InvalidTransaction::Custom(2) ); @@ -638,21 +646,22 @@ mod tests { 42u64.into(), &MockCall { data: 2 }, &(), - 0 + 0, + 0, ), InvalidTransaction::Custom(2) ); assert_eq!( BridgeRejectObsoleteHeadersAndMessages - .validate_only(42u64.into(), &MockCall { data: 3 }, &(), 0) + .validate_only(42u64.into(), &MockCall { data: 3 }, &(), 0, External, 0) .unwrap() .0, ValidTransaction { priority: 3, ..Default::default() }, ); assert_eq!( BridgeRejectObsoleteHeadersAndMessages - .validate_and_prepare(42u64.into(), &MockCall { data: 3 }, &(), 0) + .validate_and_prepare(42u64.into(), &MockCall { data: 3 }, &(), 0, 0) .unwrap() .0 .unwrap(), diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index 2ff6c4c9165a..535f1a26e5e8 100644 --- a/bridges/bin/runtime-common/src/integrity.rs +++ b/bridges/bin/runtime-common/src/integrity.rs @@ -89,13 +89,11 @@ macro_rules! assert_bridge_messages_pallet_types( /// Macro that combines four other macro calls - `assert_chain_types`, `assert_bridge_types`, /// and `assert_bridge_messages_pallet_types`. It may be used -/// at the chain that is implementing complete standard messages bridge (i.e. with bridge GRANDPA -/// and messages pallets deployed). +/// at the chain that is implementing standard messages bridge with messages pallets deployed. #[macro_export] macro_rules! assert_complete_bridge_types( ( runtime: $r:path, - with_bridged_chain_grandpa_instance: $gi:path, with_bridged_chain_messages_instance: $mi:path, this_chain: $this:path, bridged_chain: $bridged:path, @@ -186,34 +184,55 @@ where ); } -/// Parameters for asserting bridge pallet names. +/// Parameters for asserting bridge GRANDPA pallet names. #[derive(Debug)] -pub struct AssertBridgePalletNames<'a> { +struct AssertBridgeGrandpaPalletNames<'a> { /// Name of the GRANDPA pallet, deployed at this chain and used to bridge with the bridged /// chain. pub with_bridged_chain_grandpa_pallet_name: &'a str, - /// Name of the messages pallet, deployed at this chain and used to bridge with the bridged - /// chain. - pub with_bridged_chain_messages_pallet_name: &'a str, } /// Tests that bridge pallet names used in `construct_runtime!()` macro call are matching constants /// from chain primitives crates. -fn assert_bridge_pallet_names(params: AssertBridgePalletNames) +fn assert_bridge_grandpa_pallet_names(params: AssertBridgeGrandpaPalletNames) where - R: pallet_bridge_grandpa::Config + pallet_bridge_messages::Config, + R: pallet_bridge_grandpa::Config, GI: 'static, - MI: 'static, { // check that the bridge GRANDPA pallet has required name assert_eq!( - pallet_bridge_grandpa::PalletOwner::::storage_value_final_key().to_vec(), + pallet_bridge_grandpa::PalletOwner::::storage_value_final_key().to_vec(), + bp_runtime::storage_value_key( + params.with_bridged_chain_grandpa_pallet_name, + "PalletOwner", + ) + .0, + ); + assert_eq!( + pallet_bridge_grandpa::PalletOperatingMode::::storage_value_final_key().to_vec(), bp_runtime::storage_value_key( params.with_bridged_chain_grandpa_pallet_name, - "PalletOwner", - ).0, + "PalletOperatingMode", + ) + .0, ); +} +/// Parameters for asserting bridge messages pallet names. +#[derive(Debug)] +struct AssertBridgeMessagesPalletNames<'a> { + /// Name of the messages pallet, deployed at this chain and used to bridge with the bridged + /// chain. + pub with_bridged_chain_messages_pallet_name: &'a str, +} + +/// Tests that bridge pallet names used in `construct_runtime!()` macro call are matching constants +/// from chain primitives crates. +fn assert_bridge_messages_pallet_names(params: AssertBridgeMessagesPalletNames) +where + R: pallet_bridge_messages::Config, + MI: 'static, +{ // check that the bridge messages pallet has required name assert_eq!( pallet_bridge_messages::PalletOwner::::storage_value_final_key().to_vec(), @@ -223,6 +242,14 @@ where ) .0, ); + assert_eq!( + pallet_bridge_messages::PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_runtime::storage_value_key( + params.with_bridged_chain_messages_pallet_name, + "PalletOperatingMode", + ) + .0, + ); } /// Parameters for asserting complete standard messages bridge. @@ -246,9 +273,11 @@ pub fn assert_complete_with_relay_chain_bridge_constants( assert_chain_constants::(params.this_chain_constants); assert_bridge_grandpa_pallet_constants::(); assert_bridge_messages_pallet_constants::(); - assert_bridge_pallet_names::(AssertBridgePalletNames { + assert_bridge_grandpa_pallet_names::(AssertBridgeGrandpaPalletNames { with_bridged_chain_grandpa_pallet_name: >::BridgedChain::WITH_CHAIN_GRANDPA_PALLET_NAME, + }); + assert_bridge_messages_pallet_names::(AssertBridgeMessagesPalletNames { with_bridged_chain_messages_pallet_name: >::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME, }); @@ -256,21 +285,43 @@ pub fn assert_complete_with_relay_chain_bridge_constants( /// All bridge-related constants tests for the complete standard parachain messages bridge /// (i.e. with bridge GRANDPA, parachains and messages pallets deployed). -pub fn assert_complete_with_parachain_bridge_constants( +pub fn assert_complete_with_parachain_bridge_constants( params: AssertCompleteBridgeConstants, ) where R: frame_system::Config - + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + pallet_bridge_messages::Config, - GI: 'static, + >::BridgedRelayChain: ChainWithGrandpa, + PI: 'static, + MI: 'static, +{ + assert_chain_constants::(params.this_chain_constants); + assert_bridge_grandpa_pallet_constants::(); + assert_bridge_messages_pallet_constants::(); + assert_bridge_grandpa_pallet_names::( + AssertBridgeGrandpaPalletNames { + with_bridged_chain_grandpa_pallet_name: + <>::BridgedRelayChain>::WITH_CHAIN_GRANDPA_PALLET_NAME, + }, + ); + assert_bridge_messages_pallet_names::(AssertBridgeMessagesPalletNames { + with_bridged_chain_messages_pallet_name: + >::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + }); +} + +/// All bridge-related constants tests for the standalone messages bridge deployment (only with +/// messages pallets deployed). +pub fn assert_standalone_messages_bridge_constants(params: AssertCompleteBridgeConstants) +where + R: frame_system::Config + pallet_bridge_messages::Config, MI: 'static, - RelayChain: ChainWithGrandpa, { assert_chain_constants::(params.this_chain_constants); - assert_bridge_grandpa_pallet_constants::(); assert_bridge_messages_pallet_constants::(); - assert_bridge_pallet_names::(AssertBridgePalletNames { - with_bridged_chain_grandpa_pallet_name: RelayChain::WITH_CHAIN_GRANDPA_PALLET_NAME, + assert_bridge_messages_pallet_names::(AssertBridgeMessagesPalletNames { with_bridged_chain_messages_pallet_name: >::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME, }); diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 6cf04b452da7..88037d9deff5 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -196,6 +196,7 @@ impl pallet_bridge_messages::Config for TestRuntime { type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, (), + (), ConstU64<100_000>, >; type OnMessagesDelivered = (); diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index 363a869048aa..4eb93ab52bc9 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -19,10 +19,14 @@ scale-info = { features = ["derive"], workspace = true } # Substrate Dependencies frame-support = { workspace = true } +sp-core = { workspace = true } # Bridge Dependencies bp-xcm-bridge-hub-router = { workspace = true } +# Polkadot dependencies +xcm = { workspace = true } + [features] default = ["std"] std = [ @@ -30,4 +34,6 @@ std = [ "codec/std", "frame-support/std", "scale-info/std", + "sp-core/std", + "xcm/std", ] diff --git a/bridges/chains/chain-asset-hub-rococo/src/lib.rs b/bridges/chains/chain-asset-hub-rococo/src/lib.rs index de2e9ae856d1..4ff7b391acd0 100644 --- a/bridges/chains/chain-asset-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-asset-hub-rococo/src/lib.rs @@ -18,10 +18,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use codec::{Decode, Encode}; use scale_info::TypeInfo; pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; +use xcm::latest::prelude::*; /// `AssetHubRococo` Runtime `Call` enum. /// @@ -44,5 +47,27 @@ frame_support::parameter_types! { pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); } +/// Builds an (un)congestion XCM program with the `report_bridge_status` call for +/// `ToWestendXcmRouter`. +pub fn build_congestion_message( + bridge_id: sp_core::H256, + is_congested: bool, +) -> alloc::vec::Vec> { + alloc::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + fallback_max_weight: Some(XcmBridgeHubRouterTransactCallMaxWeight::get()), + call: Call::ToWestendXcmRouter(XcmBridgeHubRouterCall::report_bridge_status { + bridge_id, + is_congested, + }) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] +} + /// Identifier of AssetHubRococo in the Rococo relay chain. pub const ASSET_HUB_ROCOCO_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 430d9b6116cf..22071399f4d1 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -19,10 +19,14 @@ scale-info = { features = ["derive"], workspace = true } # Substrate Dependencies frame-support = { workspace = true } +sp-core = { workspace = true } # Bridge Dependencies bp-xcm-bridge-hub-router = { workspace = true } +# Polkadot dependencies +xcm = { workspace = true } + [features] default = ["std"] std = [ @@ -30,4 +34,6 @@ std = [ "codec/std", "frame-support/std", "scale-info/std", + "sp-core/std", + "xcm/std", ] diff --git a/bridges/chains/chain-asset-hub-westend/src/lib.rs b/bridges/chains/chain-asset-hub-westend/src/lib.rs index 9de1c8809894..9d245e08f7cc 100644 --- a/bridges/chains/chain-asset-hub-westend/src/lib.rs +++ b/bridges/chains/chain-asset-hub-westend/src/lib.rs @@ -18,10 +18,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use codec::{Decode, Encode}; use scale_info::TypeInfo; pub use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; +use xcm::latest::prelude::*; /// `AssetHubWestend` Runtime `Call` enum. /// @@ -44,5 +47,27 @@ frame_support::parameter_types! { pub const XcmBridgeHubRouterTransactCallMaxWeight: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(200_000_000, 6144); } +/// Builds an (un)congestion XCM program with the `report_bridge_status` call for +/// `ToRococoXcmRouter`. +pub fn build_congestion_message( + bridge_id: sp_core::H256, + is_congested: bool, +) -> alloc::vec::Vec> { + alloc::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + fallback_max_weight: Some(XcmBridgeHubRouterTransactCallMaxWeight::get()), + call: Call::ToRococoXcmRouter(XcmBridgeHubRouterCall::report_bridge_status { + bridge_id, + is_congested, + }) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] +} + /// Identifier of AssetHubWestend in the Westend relay chain. pub const ASSET_HUB_WESTEND_PARACHAIN_ID: u32 = 1000; diff --git a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml index 99ba721991ee..b9eb1d2d69c1 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml @@ -16,14 +16,14 @@ workspace = true [dependencies] # Bridge Dependencies -bp-polkadot-core = { workspace = true } bp-messages = { workspace = true } +bp-polkadot-core = { workspace = true } bp-runtime = { workspace = true } # Substrate Based Dependencies -frame-system = { workspace = true } frame-support = { workspace = true } +frame-system = { workspace = true } sp-api = { workspace = true } sp-std = { workspace = true } diff --git a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml index 39f7b44daa55..136832d0199d 100644 --- a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml @@ -17,8 +17,8 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { workspace = true } bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies diff --git a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index 3b0ac96e7cd3..04ce144b7906 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml @@ -18,8 +18,8 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { workspace = true } bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Based Dependencies diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 23fbd9a2742f..08a704add2b7 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -18,8 +18,8 @@ codec = { features = ["derive"], workspace = true } # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { workspace = true } bp-messages = { workspace = true } +bp-runtime = { workspace = true } bp-xcm-bridge-hub = { workspace = true } # Substrate Based Dependencies diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index 61357e6aa6c8..35932371d0a9 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -18,8 +18,8 @@ codec = { features = ["derive"], workspace = true } # Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } -bp-runtime = { workspace = true } bp-messages = { workspace = true } +bp-runtime = { workspace = true } bp-xcm-bridge-hub = { workspace = true } # Substrate Based Dependencies diff --git a/bridges/chains/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index c5c18beb2cad..070bc7b0ba3d 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -225,4 +225,4 @@ impl ChainWithMessages for PolkadotBulletin { } decl_bridge_finality_runtime_apis!(polkadot_bulletin, grandpa); -decl_bridge_messages_runtime_apis!(polkadot_bulletin, bp_messages::HashedLaneId); +decl_bridge_messages_runtime_apis!(polkadot_bulletin, bp_messages::LegacyLaneId); diff --git a/bridges/modules/beefy/Cargo.toml b/bridges/modules/beefy/Cargo.toml index cffc62d29082..adbf79e28b5a 100644 --- a/bridges/modules/beefy/Cargo.toml +++ b/bridges/modules/beefy/Cargo.toml @@ -31,13 +31,13 @@ sp-runtime = { workspace = true } sp-std = { workspace = true } [dev-dependencies] -sp-consensus-beefy = { workspace = true, default-features = true } +bp-test-utils = { workspace = true, default-features = true } mmr-lib = { workspace = true } pallet-beefy-mmr = { workspace = true, default-features = true } pallet-mmr = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -bp-test-utils = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 6d1419ae5b03..fdca48ac6f07 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -19,8 +19,8 @@ scale-info = { features = ["derive"], workspace = true } # Bridge Dependencies -bp-runtime = { workspace = true } bp-header-chain = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 9df318587e38..6248c9e65e16 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -33,8 +33,8 @@ bp-runtime = { features = ["test-helpers"], workspace = true } bp-test-utils = { workspace = true } pallet-balances = { workspace = true } pallet-bridge-grandpa = { workspace = true } -sp-io = { workspace = true } sp-core = { workspace = true } +sp-io = { workspace = true } [features] default = ["std"] diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 04e7b52ed86c..97ed61a9004e 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -34,15 +34,15 @@ sp-runtime = { workspace = true } sp-std = { workspace = true } [dev-dependencies] -bp-runtime = { workspace = true } -pallet-balances = { workspace = true, default-features = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } bp-parachains = { workspace = true } bp-polkadot-core = { workspace = true } +bp-runtime = { workspace = true } bp-test-utils = { workspace = true } +pallet-balances = { workspace = true, default-features = true } pallet-utility = { workspace = true } sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index 710533c223a0..d562ed9bcd0e 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -33,6 +33,7 @@ use bp_runtime::{Chain, RangeInclusiveExt, StaticStrProvider}; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, PostDispatchInfo}, + pallet_prelude::TransactionSource, weights::Weight, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -128,7 +129,7 @@ pub struct BridgeRelayersTransactionExtension( impl BridgeRelayersTransactionExtension where Self: 'static + Send + Sync, - R: RelayersConfig + R: RelayersConfig + BridgeMessagesConfig + TransactionPaymentConfig, C: ExtensionConfig, @@ -249,7 +250,7 @@ where // let's also replace the weight of slashing relayer with the weight of rewarding relayer if call_info.is_receive_messages_proof_call() { post_info_weight = post_info_weight.saturating_sub( - ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), + >::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), ); } @@ -277,7 +278,7 @@ impl TransactionExtension for BridgeRelayersTransactionExtension where Self: 'static + Send + Sync, - R: RelayersConfig + R: RelayersConfig + BridgeMessagesConfig + TransactionPaymentConfig, C: ExtensionConfig, @@ -304,6 +305,7 @@ where _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { // Prepare relevant data for `prepare` let parsed_call = match C::parse_and_check_for_obsolete_call(call)? { @@ -324,7 +326,9 @@ where }; // we only boost priority if relayer has staked required balance - if !RelayersPallet::::is_registration_active(&data.relayer) { + if !RelayersPallet::::is_registration_active( + &data.relayer, + ) { return Ok((Default::default(), Some(data), origin)) } @@ -380,7 +384,11 @@ where match call_result { RelayerAccountAction::None => (), RelayerAccountAction::Reward(relayer, reward_account, reward) => { - RelayersPallet::::register_relayer_reward(reward_account, &relayer, reward); + RelayersPallet::::register_relayer_reward( + reward_account, + &relayer, + reward, + ); log::trace!( target: LOG_TARGET, @@ -392,7 +400,7 @@ where ); }, RelayerAccountAction::Slash(relayer, slash_account) => - RelayersPallet::::slash_and_deregister( + RelayersPallet::::slash_and_deregister( &relayer, ExplicitOrAccountParams::Params(slash_account), ), @@ -463,7 +471,9 @@ mod tests { use pallet_utility::Call as UtilityCall; use sp_runtime::{ traits::{ConstU64, DispatchTransaction, Header as HeaderT}, - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + transaction_validity::{ + InvalidTransaction, TransactionSource::External, TransactionValidity, ValidTransaction, + }, DispatchError, }; @@ -1076,6 +1086,8 @@ mod tests { &call, &DispatchInfo::default(), 0, + External, + 0, ) .map(|t| t.0) } @@ -1088,6 +1100,8 @@ mod tests { &call, &DispatchInfo::default(), 0, + External, + 0, ) .map(|t| t.0) } @@ -1100,6 +1114,8 @@ mod tests { &call, &DispatchInfo::default(), 0, + External, + 0, ) .map(|t| t.0) } @@ -1125,6 +1141,7 @@ mod tests { &call, &DispatchInfo::default(), 0, + 0, ) .map(|(pre, _)| pre) } @@ -1142,6 +1159,7 @@ mod tests { &call, &DispatchInfo::default(), 0, + 0, ) .map(|(pre, _)| pre) } @@ -1159,6 +1177,7 @@ mod tests { &call, &DispatchInfo::default(), 0, + 0, ) .map(|(pre, _)| pre) } diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index f06c2e16ac24..d1c71b6d3051 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -22,8 +22,9 @@ use bp_relayers::{ ExplicitOrAccountParams, PaymentProcedure, Registration, RelayerRewardsKeyProvider, - RewardsAccountParams, StakeAndSlash, + StakeAndSlash, }; +pub use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::StorageDoubleMapKeyProvider; use frame_support::fail; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; @@ -31,7 +32,7 @@ use sp_runtime::{traits::CheckedSub, Saturating}; use sp_std::marker::PhantomData; pub use pallet::*; -pub use payment_adapter::DeliveryConfirmationPaymentsAdapter; +pub use payment_adapter::{DeliveryConfirmationPaymentsAdapter, PayRewardFromAccount}; pub use stake_adapter::StakeAndSlashNamed; pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index d186e968e648..7dc213249379 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -171,14 +171,14 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< frame_support::construct_runtime! { pub enum TestRuntime { - System: frame_system::{Pallet, Call, Config, Storage, Event}, + System: frame_system, Utility: pallet_utility, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, - BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, - BridgeGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, - BridgeParachains: pallet_bridge_parachains::{Pallet, Call, Storage, Event}, - BridgeMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + BridgeRelayers: pallet_bridge_relayers, + BridgeGrandpa: pallet_bridge_grandpa, + BridgeParachains: pallet_bridge_parachains, + BridgeMessages: pallet_bridge_messages, } } @@ -267,6 +267,7 @@ impl pallet_bridge_messages::Config for TestRuntime { type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, (), + (), ConstU64<100_000>, >; type OnMessagesDelivered = (); diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index 5383cba5ecbd..5af0d8f9dfbf 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -22,6 +22,7 @@ use bp_messages::{ source_chain::{DeliveryConfirmationPayments, RelayersRewards}, MessageNonce, }; +pub use bp_relayers::PayRewardFromAccount; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::Chain; use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; @@ -31,15 +32,16 @@ use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeIn /// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism /// for the messages pallet. -pub struct DeliveryConfirmationPaymentsAdapter( - PhantomData<(T, MI, DeliveryReward)>, +pub struct DeliveryConfirmationPaymentsAdapter( + PhantomData<(T, MI, RI, DeliveryReward)>, ); -impl DeliveryConfirmationPayments> - for DeliveryConfirmationPaymentsAdapter +impl DeliveryConfirmationPayments> + for DeliveryConfirmationPaymentsAdapter where - T: Config + pallet_bridge_messages::Config::LaneId>, + T: Config + pallet_bridge_messages::Config>::LaneId>, MI: 'static, + RI: 'static, DeliveryReward: Get, { type Error = &'static str; @@ -54,7 +56,7 @@ where bp_messages::calc_relayers_rewards::(messages_relayers, received_range); let rewarded_relayers = relayers_rewards.len(); - register_relayers_rewards::( + register_relayers_rewards::( confirmation_relayer, relayers_rewards, RewardsAccountParams::new( @@ -70,7 +72,7 @@ where } // Update rewards to given relayers, optionally rewarding confirmation relayer. -fn register_relayers_rewards( +fn register_relayers_rewards, I: 'static>( confirmation_relayer: &T::AccountId, relayers_rewards: RelayersRewards, lane_id: RewardsAccountParams, @@ -84,7 +86,7 @@ fn register_relayers_rewards( let relayer_reward = T::Reward::saturated_from(messages).saturating_mul(delivery_fee); if relayer != *confirmation_relayer { - Pallet::::register_relayer_reward(lane_id, &relayer, relayer_reward); + Pallet::::register_relayer_reward(lane_id, &relayer, relayer_reward); } else { confirmation_relayer_reward = confirmation_relayer_reward.saturating_add(relayer_reward); @@ -92,7 +94,7 @@ fn register_relayers_rewards( } // finally - pay reward to confirmation relayer - Pallet::::register_relayer_reward( + Pallet::::register_relayer_reward( lane_id, confirmation_relayer, confirmation_relayer_reward, @@ -115,7 +117,7 @@ mod tests { #[test] fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() { run_test(|| { - register_relayers_rewards::( + register_relayers_rewards::( &RELAYER_2, relayers_rewards(), test_reward_account_param(), @@ -136,7 +138,7 @@ mod tests { #[test] fn confirmation_relayer_is_not_rewarded_if_it_has_not_delivered_any_messages() { run_test(|| { - register_relayers_rewards::( + register_relayers_rewards::( &RELAYER_3, relayers_rewards(), test_reward_account_param(), diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 55824f6a7fe7..b0286938f36d 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -56,6 +56,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index 3c4a10f82e7d..ff06a1e3c8c5 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -18,9 +18,9 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{DeliveryFeeFactor, MINIMAL_DELIVERY_FEE_FACTOR}; +use crate::{Bridge, BridgeState, Call, MINIMAL_DELIVERY_FEE_FACTOR}; use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; -use frame_support::traits::{Get, Hooks}; +use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; use sp_runtime::traits::Zero; use xcm::prelude::*; @@ -45,16 +45,35 @@ pub trait Config: crate::Config { benchmarks_instance_pallet! { on_initialize_when_non_congested { - DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); + Bridge::::put(BridgeState { + is_congested: false, + delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, + }); }: { crate::Pallet::::on_initialize(Zero::zero()) } on_initialize_when_congested { - DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); + Bridge::::put(BridgeState { + is_congested: false, + delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, + }); let _ = T::ensure_bridged_target_destination()?; T::make_congested(); }: { crate::Pallet::::on_initialize(Zero::zero()) } + + report_bridge_status { + Bridge::::put(BridgeState::default()); + + let origin: T::RuntimeOrigin = T::BridgeHubOrigin::try_successful_origin().expect("expected valid BridgeHubOrigin"); + let bridge_id = Default::default(); + let is_congested = true; + + let call = Call::::report_bridge_status { bridge_id, is_congested }; + }: { call.dispatch_bypass_filter(origin)? } + verify { + assert!(Bridge::::get().is_congested); + } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index fe8f5a2efdfb..7361696faba7 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -30,9 +30,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -pub use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; +pub use bp_xcm_bridge_hub_router::{BridgeState, XcmChannelStatusProvider}; use codec::Encode; use frame_support::traits::Get; +use sp_core::H256; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; use sp_std::vec::Vec; use xcm::prelude::*; @@ -98,6 +99,8 @@ pub mod pallet { /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; + /// Origin of the sibling bridge hub that is allowed to report bridge status. + type BridgeHubOrigin: EnsureOrigin; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. type ToBridgeHubSender: SendXcm; /// Local XCM channel manager. @@ -120,95 +123,112 @@ pub mod pallet { return T::WeightInfo::on_initialize_when_congested() } + // if bridge has reported congestion, we don't change anything + let mut bridge = Self::bridge(); + if bridge.is_congested { + return T::WeightInfo::on_initialize_when_congested() + } + // if we can't decrease the delivery fee factor anymore, we don't change anything - let mut delivery_fee_factor = Self::delivery_fee_factor(); - if delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { + if bridge.delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { return T::WeightInfo::on_initialize_when_congested() } - let previous_factor = delivery_fee_factor; - delivery_fee_factor = - MINIMAL_DELIVERY_FEE_FACTOR.max(delivery_fee_factor / EXPONENTIAL_FEE_BASE); + let previous_factor = bridge.delivery_fee_factor; + bridge.delivery_fee_factor = + MINIMAL_DELIVERY_FEE_FACTOR.max(bridge.delivery_fee_factor / EXPONENTIAL_FEE_BASE); + log::info!( target: LOG_TARGET, "Bridge channel is uncongested. Decreased fee factor from {} to {}", previous_factor, - delivery_fee_factor, + bridge.delivery_fee_factor, ); Self::deposit_event(Event::DeliveryFeeFactorDecreased { - new_value: delivery_fee_factor, + new_value: bridge.delivery_fee_factor, }); - DeliveryFeeFactor::::put(delivery_fee_factor); + Bridge::::put(bridge); T::WeightInfo::on_initialize_when_non_congested() } } - /// Initialization value for the delivery fee factor. - #[pallet::type_value] - pub fn InitialFactor() -> FixedU128 { - MINIMAL_DELIVERY_FEE_FACTOR + #[pallet::call] + impl, I: 'static> Pallet { + /// Notification about congested bridge queue. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::report_bridge_status())] + pub fn report_bridge_status( + origin: OriginFor, + // this argument is not currently used, but to ease future migration, we'll keep it + // here + bridge_id: H256, + is_congested: bool, + ) -> DispatchResult { + let _ = T::BridgeHubOrigin::ensure_origin(origin)?; + + log::info!( + target: LOG_TARGET, + "Received bridge status from {:?}: congested = {}", + bridge_id, + is_congested, + ); + + Bridge::::mutate(|bridge| { + bridge.is_congested = is_congested; + }); + Ok(()) + } } - /// The number to multiply the base delivery fee by. + /// Bridge that we are using. /// - /// This factor is shared by all bridges, served by this pallet. For example, if this - /// chain (`Config::UniversalLocation`) opens two bridges ( - /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(1000))` and - /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(2000))`), then they - /// both will be sharing the same fee factor. This is because both bridges are sharing - /// the same local XCM channel with the child/sibling bridge hub, which we are using - /// to detect congestion: - /// - /// ```nocompile - /// ThisChain --- Local XCM channel --> Sibling Bridge Hub ------ - /// | | - /// | | - /// | | - /// Lane1 Lane2 - /// | | - /// | | - /// | | - /// \ / | - /// Parachain1 <-- Local XCM channel --- Remote Bridge Hub <------ - /// | - /// | - /// Parachain1 <-- Local XCM channel --------- - /// ``` - /// - /// If at least one of other channels is congested, the local XCM channel with sibling - /// bridge hub eventually becomes congested too. And we have no means to detect - which - /// bridge exactly causes the congestion. So the best solution here is not to make - /// any differences between all bridges, started by this chain. + /// **bridges-v1** assumptions: all outbound messages through this router are using single lane + /// and to single remote consensus. If there is some other remote consensus that uses the same + /// bridge hub, the separate pallet instance shall be used, In `v2` we'll have all required + /// primitives (lane-id aka bridge-id, derived from XCM locations) to support multiple bridges + /// by the same pallet instance. #[pallet::storage] - #[pallet::getter(fn delivery_fee_factor)] - pub type DeliveryFeeFactor, I: 'static = ()> = - StorageValue<_, FixedU128, ValueQuery, InitialFactor>; + #[pallet::getter(fn bridge)] + pub type Bridge, I: 'static = ()> = StorageValue<_, BridgeState, ValueQuery>; impl, I: 'static> Pallet { /// Called when new message is sent (queued to local outbound XCM queue) over the bridge. pub(crate) fn on_message_sent_to_bridge(message_size: u32) { - // if outbound channel is not congested, do nothing - if !T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { - return - } + log::trace!( + target: LOG_TARGET, + "on_message_sent_to_bridge - message_size: {message_size:?}", + ); + let _ = Bridge::::try_mutate(|bridge| { + let is_channel_with_bridge_hub_congested = + T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()); + let is_bridge_congested = bridge.is_congested; + + // if outbound queue is not congested AND bridge has not reported congestion, do + // nothing + if !is_channel_with_bridge_hub_congested && !is_bridge_congested { + return Err(()) + } + + // ok - we need to increase the fee factor, let's do that + let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) + .saturating_mul(MESSAGE_SIZE_FEE_BASE); + let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); + let previous_factor = bridge.delivery_fee_factor; + bridge.delivery_fee_factor = + bridge.delivery_fee_factor.saturating_mul(total_factor); - // ok - we need to increase the fee factor, let's do that - let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) - .saturating_mul(MESSAGE_SIZE_FEE_BASE); - let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); - DeliveryFeeFactor::::mutate(|f| { - let previous_factor = *f; - *f = f.saturating_mul(total_factor); log::info!( target: LOG_TARGET, "Bridge channel is congested. Increased fee factor from {} to {}", previous_factor, - f, + bridge.delivery_fee_factor, ); - Self::deposit_event(Event::DeliveryFeeFactorIncreased { new_value: *f }); - *f + Self::deposit_event(Event::DeliveryFeeFactorIncreased { + new_value: bridge.delivery_fee_factor, + }); + Ok(()) }); } } @@ -310,9 +330,9 @@ impl, I: 'static> ExporterFor for Pallet { let message_size = message.encoded_size(); let message_fee = (message_size as u128).saturating_mul(T::ByteFee::get()); let fee_sum = base_fee.saturating_add(message_fee); - - let fee_factor = Self::delivery_fee_factor(); + let fee_factor = Self::bridge().delivery_fee_factor; let fee = fee_factor.saturating_mul_int(fee_sum); + let fee = if fee > 0 { Some((T::FeeAsset::get(), fee).into()) } else { None }; log::info!( @@ -427,24 +447,47 @@ mod tests { use frame_system::{EventRecord, Phase}; use sp_runtime::traits::One; + fn congested_bridge(delivery_fee_factor: FixedU128) -> BridgeState { + BridgeState { is_congested: true, delivery_fee_factor } + } + + fn uncongested_bridge(delivery_fee_factor: FixedU128) -> BridgeState { + BridgeState { is_congested: false, delivery_fee_factor } + } + #[test] fn initial_fee_factor_is_one() { run_test(|| { - assert_eq!(DeliveryFeeFactor::::get(), MINIMAL_DELIVERY_FEE_FACTOR); + assert_eq!( + Bridge::::get(), + uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR), + ); }) } #[test] fn fee_factor_is_not_decreased_from_on_initialize_when_xcm_channel_is_congested() { run_test(|| { - DeliveryFeeFactor::::put(FixedU128::from_rational(125, 100)); + Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); // it should not decrease, because queue is congested - let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); + let old_delivery = XcmBridgeHubRouter::bridge(); XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), old_delivery_fee_factor); + assert_eq!(XcmBridgeHubRouter::bridge(), old_delivery); + assert_eq!(System::events(), vec![]); + }) + } + + #[test] + fn fee_factor_is_not_decreased_from_on_initialize_when_bridge_has_reported_congestion() { + run_test(|| { + Bridge::::put(congested_bridge(FixedU128::from_rational(125, 100))); + // it should not decrease, because bridge congested + let old_bridge = XcmBridgeHubRouter::bridge(); + XcmBridgeHubRouter::on_initialize(One::one()); + assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); assert_eq!(System::events(), vec![]); }) } @@ -453,16 +496,19 @@ mod tests { fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() { run_test(|| { let initial_fee_factor = FixedU128::from_rational(125, 100); - DeliveryFeeFactor::::put(initial_fee_factor); + Bridge::::put(uncongested_bridge(initial_fee_factor)); - // it shold eventually decreased to one - while XcmBridgeHubRouter::delivery_fee_factor() > MINIMAL_DELIVERY_FEE_FACTOR { + // it should eventually decrease to one + while XcmBridgeHubRouter::bridge().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR { XcmBridgeHubRouter::on_initialize(One::one()); } - // verify that it doesn't decreases anymore + // verify that it doesn't decrease anymore XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), MINIMAL_DELIVERY_FEE_FACTOR); + assert_eq!( + XcmBridgeHubRouter::bridge(), + uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR) + ); // check emitted event let first_system_event = System::events().first().cloned(); @@ -582,7 +628,7 @@ mod tests { // but when factor is larger than one, it increases the fee, so it becomes: // `(BASE_FEE + BYTE_FEE * msg_size) * F + HRMP_FEE` let factor = FixedU128::from_rational(125, 100); - DeliveryFeeFactor::::put(factor); + Bridge::::put(uncongested_bridge(factor)); let expected_fee = (FixedU128::saturating_from_integer(BASE_FEE + BYTE_FEE * (msg_size as u128)) * factor) @@ -598,7 +644,7 @@ mod tests { #[test] fn sent_message_doesnt_increase_factor_if_queue_is_uncongested() { run_test(|| { - let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); + let old_bridge = XcmBridgeHubRouter::bridge(); assert_eq!( send_xcm::( Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), @@ -609,7 +655,7 @@ mod tests { ); assert!(TestToBridgeHubSender::is_message_sent()); - assert_eq!(old_delivery_fee_factor, XcmBridgeHubRouter::delivery_fee_factor()); + assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); assert_eq!(System::events(), vec![]); }); @@ -620,7 +666,39 @@ mod tests { run_test(|| { TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); - let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); + let old_bridge = XcmBridgeHubRouter::bridge(); + assert_ok!(send_xcm::( + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), + vec![ClearOrigin].into(), + ) + .map(drop)); + + assert!(TestToBridgeHubSender::is_message_sent()); + assert!( + old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor + ); + + // check emitted event + let first_system_event = System::events().first().cloned(); + assert!(matches!( + first_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter( + Event::DeliveryFeeFactorIncreased { .. } + ), + .. + }) + )); + }); + } + + #[test] + fn sent_message_increases_factor_if_bridge_has_reported_congestion() { + run_test(|| { + Bridge::::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)); + + let old_bridge = XcmBridgeHubRouter::bridge(); assert_ok!(send_xcm::( Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), vec![ClearOrigin].into(), @@ -628,7 +706,9 @@ mod tests { .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); - assert!(old_delivery_fee_factor < XcmBridgeHubRouter::delivery_fee_factor()); + assert!( + old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor + ); // check emitted event let first_system_event = System::events().first().cloned(); diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index bb265e1925a2..ac642e108c2a 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -80,6 +80,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type DestinationVersion = LatestOrNoneForLocationVersionChecker>; + type BridgeHubOrigin = frame_system::EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; type LocalXcmChannelManager = TestLocalXcmChannelManager; @@ -141,8 +142,8 @@ impl InspectMessageQueues for TestToBridgeHubSender { .iter() .map(|(location, message)| { ( - VersionedLocation::V4(location.clone()), - vec![VersionedXcm::V4(message.clone())], + VersionedLocation::from(location.clone()), + vec![VersionedXcm::from(message.clone())], ) }) .collect() diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index d9a0426fecaf..8f5012c9de26 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -52,6 +52,7 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn on_initialize_when_non_congested() -> Weight; fn on_initialize_when_congested() -> Weight; + fn report_bridge_status() -> Weight; } /// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets. @@ -85,6 +86,19 @@ impl WeightInfo for BridgeWeight { // Minimum execution time: 4_239 nanoseconds. Weight::from_parts(4_383_000, 3547).saturating_add(T::DbWeight::get().reads(1_u64)) } + /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) + /// + /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: + /// 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `53` + // Estimated: `1502` + // Minimum execution time: 10_427 nanoseconds. + Weight::from_parts(10_682_000, 1502) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -120,4 +134,17 @@ impl WeightInfo for () { // Minimum execution time: 4_239 nanoseconds. Weight::from_parts(4_383_000, 3547).saturating_add(RocksDbWeight::get().reads(1_u64)) } + /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) + /// + /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: + /// 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `53` + // Estimated: `1502` + // Minimum execution time: 10_427 nanoseconds. + Weight::from_parts(10_682_000, 1502) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index fe58b910a94e..b5e365874443 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -34,12 +34,13 @@ xcm-builder = { workspace = true } xcm-executor = { workspace = true } [dev-dependencies] -pallet-balances = { workspace = true } -sp-io = { workspace = true } -bp-runtime = { workspace = true } bp-header-chain = { workspace = true } +bp-runtime = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +pallet-balances = { workspace = true } pallet-xcm-bridge-hub-router = { workspace = true } polkadot-parachain-primitives = { workspace = true } +sp-io = { workspace = true } [features] default = ["std"] @@ -47,6 +48,7 @@ std = [ "bp-header-chain/std", "bp-messages/std", "bp-runtime/std", + "bp-xcm-bridge-hub-router/std", "bp-xcm-bridge-hub/std", "codec/std", "frame-support/std", @@ -75,6 +77,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 5afb9f36bc94..93b6093b42af 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -364,7 +364,7 @@ mod tests { use bp_runtime::RangeInclusiveExt; use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; - use frame_support::assert_ok; + use frame_support::{assert_ok, traits::EnsureOrigin}; use pallet_bridge_messages::InboundLaneStorage; use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; use xcm_executor::traits::{export_xcm, ConvertLocation}; @@ -381,9 +381,8 @@ mod tests { BridgedUniversalDestination::get() } - fn open_lane() -> (BridgeLocations, TestLaneIdType) { + fn open_lane(origin: RuntimeOrigin) -> (BridgeLocations, TestLaneIdType) { // open expected outbound lane - let origin = OpenBridgeOrigin::sibling_parachain_origin(); let with = bridged_asset_hub_universal_location(); let locations = XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); @@ -439,7 +438,7 @@ mod tests { } fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) { - let (locations, lane_id) = open_lane(); + let (locations, lane_id) = open_lane(OpenBridgeOrigin::sibling_parachain_origin()); // now let's try to enqueue message using our `ExportXcm` implementation export_xcm::( @@ -473,7 +472,7 @@ mod tests { fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() { run_test(|| { let (bridge_id, _) = open_lane_and_send_regular_message(); - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -490,7 +489,7 @@ mod tests { } open_lane_and_send_regular_message(); - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); }); } @@ -502,11 +501,11 @@ mod tests { open_lane_and_send_regular_message(); } - assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); open_lane_and_send_regular_message(); - assert!(TestLocalXcmChannelManager::is_bridge_suspened()); + assert!(TestLocalXcmChannelManager::is_bridge_suspended(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); }); } @@ -523,7 +522,7 @@ mod tests { OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, ); - assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); }); } @@ -537,7 +536,7 @@ mod tests { OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); - assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -554,7 +553,7 @@ mod tests { OUTBOUND_LANE_UNCONGESTED_THRESHOLD, ); - assert!(TestLocalXcmChannelManager::is_bridge_resumed()); + assert!(TestLocalXcmChannelManager::is_bridge_resumed(&bridge_id)); assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -648,7 +647,10 @@ mod tests { let dest = Location::new(2, BridgedUniversalDestination::get()); // open bridge - let (_, expected_lane_id) = open_lane(); + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let origin_as_location = + OpenBridgeOriginOf::::try_origin(origin.clone()).unwrap(); + let (_, expected_lane_id) = open_lane(origin); // check before - no messages assert_eq!( @@ -662,18 +664,24 @@ mod tests { ); // send `ExportMessage(message)` by `UnpaidRemoteExporter`. - TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location); assert_ok!(send_xcm::< UnpaidRemoteExporter< NetworkExportTable, - TestExportXcmWithXcmOverBridge, + ExecuteXcmOverSendXcm, UniversalLocation, >, >(dest.clone(), Xcm::<()>::default())); + // we need to set `UniversalLocation` for `sibling_parachain_origin` for + // `XcmOverBridgeWrappedWithExportMessageRouterInstance`. + ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get())); // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. - TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); - assert_ok!(send_xcm::(dest.clone(), Xcm::<()>::default())); + ExecuteXcmOverSendXcm::set_origin_for_execute(SiblingLocation::get()); + assert_ok!(send_xcm::( + dest.clone(), + Xcm::<()>::default() + )); // check after - a message ready to be relayed assert_eq!( @@ -765,7 +773,7 @@ mod tests { ); // ok - let _ = open_lane(); + let _ = open_lane(OpenBridgeOrigin::sibling_parachain_origin()); let mut dest_wrapper = Some(bridged_relative_destination()); assert_ok!(XcmOverBridge::validate( BridgedRelayNetwork::get(), @@ -780,4 +788,77 @@ mod tests { assert_eq!(None, dest_wrapper); }); } + + #[test] + fn congestion_with_pallet_xcm_bridge_hub_router_works() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + + fn router_bridge_state() -> pallet_xcm_bridge_hub_router::BridgeState { + pallet_xcm_bridge_hub_router::Bridge::< + TestRuntime, + XcmOverBridgeWrappedWithExportMessageRouterInstance, + >::get() + } + + // open two bridges + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let origin_as_location = + OpenBridgeOriginOf::::try_origin(origin.clone()).unwrap(); + let (bridge_1, expected_lane_id_1) = open_lane(origin); + + // we need to set `UniversalLocation` for `sibling_parachain_origin` for + // `XcmOverBridgeWrappedWithExportMessageRouterInstance`. + ExportMessageOriginUniversalLocation::set(Some(SiblingUniversalLocation::get())); + + // check before + // bridges are opened + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Opened + ); + + // the router is uncongested + assert!(!router_bridge_state().is_congested); + assert!(!TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + + // make bridges congested with sending too much messages + for _ in 1..(OUTBOUND_LANE_CONGESTED_THRESHOLD + 2) { + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. + ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone()); + assert_ok!(send_xcm::( + dest.clone(), + Xcm::<()>::default() + )); + } + + // checks after + // bridges are suspended + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Suspended, + ); + // the router is congested + assert!(router_bridge_state().is_congested); + assert!(TestLocalXcmChannelManager::is_bridge_suspended(bridge_1.bridge_id())); + assert!(!TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + + // make bridges uncongested to trigger resume signal + XcmOverBridge::on_bridge_messages_delivered( + expected_lane_id_1, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + // bridge is again opened + assert_eq!( + XcmOverBridge::bridge(bridge_1.bridge_id()).unwrap().state, + BridgeState::Opened + ); + // the router is uncongested + assert!(!router_bridge_state().is_congested); + assert!(TestLocalXcmChannelManager::is_bridge_resumed(bridge_1.bridge_id())); + }) + } } diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 1b2536598a20..682db811efa7 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -145,8 +145,8 @@ 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}; +pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState, LocalXcmChannelManager}; +use bp_xcm_bridge_hub::{BridgeLocations, BridgeLocationsError}; use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; use frame_system::Config as SystemConfig; use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 6511b9fc5b04..d186507dab17 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -24,10 +24,10 @@ use bp_messages::{ }; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; -use codec::Encode; +use codec::{Decode, Encode}; use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{EnsureOrigin, Equals, Everything, OriginTrait}, + traits::{EnsureOrigin, Equals, Everything, Get, OriginTrait}, weights::RuntimeDbWeight, }; use polkadot_parachain_primitives::primitives::Sibling; @@ -38,13 +38,13 @@ use sp_runtime::{ AccountId32, BuildStorage, StateVersion, }; use sp_std::cell::RefCell; -use xcm::prelude::*; +use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*}; use xcm_builder::{ AllowUnpaidExecutionFrom, DispatchBlob, DispatchBlobError, FixedWeightBounds, InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, SiblingParachainConvertsVia, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{traits::ConvertOrigin, XcmExecutor}; pub type AccountId = AccountId32; pub type Balance = u64; @@ -63,7 +63,7 @@ frame_support::construct_runtime! { Balances: pallet_balances::{Pallet, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, HoldReason, Event}, - XcmOverBridgeRouter: pallet_xcm_bridge_hub_router, + XcmOverBridgeWrappedWithExportMessageRouter: pallet_xcm_bridge_hub_router = 57, } } @@ -160,7 +160,7 @@ parameter_types! { 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(); - pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; + pub const NonBridgedRelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub const BridgeDeposit: Balance = 100_000; @@ -208,17 +208,27 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type BlobDispatcher = TestBlobDispatcher; } -impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { +/// A router instance simulates a scenario where the router is deployed on a different chain than +/// the `MessageExporter`. This means that the router sends an `ExportMessage`. +pub type XcmOverBridgeWrappedWithExportMessageRouterInstance = (); +impl pallet_xcm_bridge_hub_router::Config + for TestRuntime +{ type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - type UniversalLocation = UniversalLocation; + type UniversalLocation = ExportMessageOriginUniversalLocation; type SiblingBridgeHubLocation = BridgeHubLocation; type BridgedNetworkId = BridgedRelayNetwork; type Bridges = NetworkExportTable; type DestinationVersion = AlwaysLatest; - type ToBridgeHubSender = TestExportXcmWithXcmOverBridge; + // We convert to root `here` location with `BridgeHubLocationXcmOriginAsRoot` + type BridgeHubOrigin = frame_system::EnsureRoot; + // **Note**: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which + // calls the `ExportXcm` implementation of `pallet_xcm_bridge_hub` as the + // `MessageExporter`. + type ToBridgeHubSender = ExecuteXcmOverSendXcm; type LocalXcmChannelManager = TestLocalXcmChannelManager; type ByteFee = ConstU128<0>; @@ -230,7 +240,7 @@ impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); type AssetTransactor = (); - type OriginConverter = (); + type OriginConverter = BridgeHubLocationXcmOriginAsRoot; type IsReserve = (); type IsTeleporter = (); type UniversalLocation = UniversalLocation; @@ -270,8 +280,8 @@ thread_local! { /// /// Note: The crucial part is that `ExportMessage` is processed by `XcmExecutor`, which calls the /// `ExportXcm` implementation of `pallet_xcm_bridge_hub` as `MessageExporter`. -pub struct TestExportXcmWithXcmOverBridge; -impl SendXcm for TestExportXcmWithXcmOverBridge { +pub struct ExecuteXcmOverSendXcm; +impl SendXcm for ExecuteXcmOverSendXcm { type Ticket = Xcm<()>; fn validate( @@ -298,7 +308,7 @@ impl SendXcm for TestExportXcmWithXcmOverBridge { Ok(hash) } } -impl InspectMessageQueues for TestExportXcmWithXcmOverBridge { +impl InspectMessageQueues for ExecuteXcmOverSendXcm { fn clear_messages() { todo!() } @@ -307,12 +317,51 @@ impl InspectMessageQueues for TestExportXcmWithXcmOverBridge { todo!() } } -impl TestExportXcmWithXcmOverBridge { +impl ExecuteXcmOverSendXcm { pub fn set_origin_for_execute(origin: Location) { EXECUTE_XCM_ORIGIN.with(|o| *o.borrow_mut() = Some(origin)); } } +/// A dynamic way to set different universal location for the origin which sends `ExportMessage`. +pub struct ExportMessageOriginUniversalLocation; +impl ExportMessageOriginUniversalLocation { + pub(crate) fn set(universal_location: Option) { + EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION.with(|o| *o.borrow_mut() = universal_location); + } +} +impl Get for ExportMessageOriginUniversalLocation { + fn get() -> InteriorLocation { + EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION.with(|o| { + o.borrow() + .clone() + .expect("`EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION` is not set!") + }) + } +} +thread_local! { + pub static EXPORT_MESSAGE_ORIGIN_UNIVERSAL_LOCATION: RefCell> = RefCell::new(None); +} + +pub struct BridgeHubLocationXcmOriginAsRoot( + sp_std::marker::PhantomData, +); +impl ConvertOrigin + for BridgeHubLocationXcmOriginAsRoot +{ + fn convert_origin( + origin: impl Into, + kind: OriginKind, + ) -> Result { + let origin = origin.into(); + if kind == OriginKind::Xcm && origin.eq(&BridgeHubLocation::get()) { + Ok(RuntimeOrigin::root()) + } else { + Err(origin) + } + } +} + /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used /// when determining ownership of accounts for asset transacting and when attempting to use XCM /// `Transact` in order to determine the dispatch Origin. @@ -396,6 +445,9 @@ impl EnsureOrigin for OpenBridgeOrigin { } } +pub(crate) type OpenBridgeOriginOf = + >::OpenBridgeOrigin; + pub struct TestLocalXcmChannelManager; impl TestLocalXcmChannelManager { @@ -403,30 +455,82 @@ impl TestLocalXcmChannelManager { frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Congested", &true); } - pub fn is_bridge_suspened() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Suspended") + fn suspended_key(bridge: &BridgeId) -> Vec { + [b"TestLocalXcmChannelManager.Suspended", bridge.encode().as_slice()].concat() + } + fn resumed_key(bridge: &BridgeId) -> Vec { + [b"TestLocalXcmChannelManager.Resumed", bridge.encode().as_slice()].concat() + } + + pub fn is_bridge_suspended(bridge: &BridgeId) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::suspended_key(bridge)) } - pub fn is_bridge_resumed() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Resumed") + pub fn is_bridge_resumed(bridge: &BridgeId) -> bool { + frame_support::storage::unhashed::get_or_default(&Self::resumed_key(bridge)) + } + + fn build_congestion_message(bridge: &BridgeId, is_congested: bool) -> Vec> { + use bp_xcm_bridge_hub_router::XcmBridgeHubRouterCall; + #[allow(clippy::large_enum_variant)] + #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, scale_info::TypeInfo)] + enum Call { + #[codec(index = 57)] + XcmOverBridgeWrappedWithExportMessageRouter(XcmBridgeHubRouterCall), + } + + sp_std::vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::Xcm, + fallback_max_weight: None, + call: Call::XcmOverBridgeWrappedWithExportMessageRouter( + XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: bridge.inner(), + is_congested, + } + ) + .encode() + .into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ] + } + + fn report_bridge_status( + local_origin: &Location, + bridge: &BridgeId, + is_congested: bool, + key: Vec, + ) -> Result<(), SendError> { + // send as BridgeHub would send to sibling chain + ExecuteXcmOverSendXcm::set_origin_for_execute(BridgeHubLocation::get()); + let result = send_xcm::( + local_origin.clone(), + Self::build_congestion_message(&bridge, is_congested).into(), + ); + + if result.is_ok() { + frame_support::storage::unhashed::put(&key, &true); + } + + result.map(|_| ()) } } impl LocalXcmChannelManager for TestLocalXcmChannelManager { - type Error = (); + type Error = SendError; fn is_congested(_with: &Location) -> bool { frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Congested") } - fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Suspended", &true); - Ok(()) + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + Self::report_bridge_status(local_origin, &bridge, true, Self::suspended_key(&bridge)) } - fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { - frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Resumed", &true); - Ok(()) + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + Self::report_bridge_status(local_origin, &bridge, false, Self::resumed_key(&bridge)) } } diff --git a/bridges/primitives/beefy/Cargo.toml b/bridges/primitives/beefy/Cargo.toml index 404acaff30af..b32cf1e407eb 100644 --- a/bridges/primitives/beefy/Cargo.toml +++ b/bridges/primitives/beefy/Cargo.toml @@ -23,10 +23,10 @@ bp-runtime = { workspace = true } # Substrate Dependencies binary-merkle-tree = { workspace = true } -sp-consensus-beefy = { workspace = true } frame-support = { workspace = true } pallet-beefy-mmr = { workspace = true } pallet-mmr = { workspace = true } +sp-consensus-beefy = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index 081bda479495..b17dcb2f7491 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -23,8 +23,8 @@ bp-runtime = { workspace = true } # Substrate Dependencies frame-support = { workspace = true } -sp-core = { features = ["serde"], workspace = true } sp-consensus-grandpa = { features = ["serde"], workspace = true } +sp-core = { features = ["serde"], workspace = true } sp-runtime = { features = ["serde"], workspace = true } sp-std = { workspace = true } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 87c8cbe88180..dd1bd083371f 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -16,19 +16,19 @@ scale-info = { features = ["bit-vec", "derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies -bp-runtime = { workspace = true } bp-header-chain = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies frame-support = { workspace = true } sp-core = { workspace = true } -sp-std = { workspace = true } sp-io = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] +bp-runtime = { workspace = true } hex = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } -bp-runtime = { workspace = true } [features] default = ["std"] diff --git a/bridges/primitives/messages/src/lane.rs b/bridges/primitives/messages/src/lane.rs index 0f14ce93e114..75237a44d538 100644 --- a/bridges/primitives/messages/src/lane.rs +++ b/bridges/primitives/messages/src/lane.rs @@ -108,8 +108,8 @@ impl TypeId for LegacyLaneId { /// concatenation (separated by some binary data). I.e.: /// /// ```nocompile -/// let endpoint1 = X2(GlobalConsensus(NetworkId::Rococo), Parachain(42)); -/// let endpoint2 = X2(GlobalConsensus(NetworkId::Wococo), Parachain(777)); +/// let endpoint1 = X2(GlobalConsensus(NetworkId::Polkadot), Parachain(42)); +/// let endpoint2 = X2(GlobalConsensus(NetworkId::Kusama), Parachain(777)); /// /// let final_lane_key = if endpoint1 < endpoint2 { /// (endpoint1, VALUES_SEPARATOR, endpoint2) diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 34be38bed4ac..9219bae1e131 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -21,8 +21,8 @@ bp-parachains = { workspace = true } bp-runtime = { workspace = true } # Substrate Dependencies -frame-system = { workspace = true } frame-support = { workspace = true } +frame-system = { workspace = true } pallet-utility = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index ba0c51152bd2..b8a21ec35024 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -15,8 +15,8 @@ codec = { features = ["bit-vec", "derive"], workspace = true } scale-info = { features = ["bit-vec", "derive"], workspace = true } # Substrate Dependencies -sp-runtime = { workspace = true } sp-core = { workspace = true } +sp-runtime = { workspace = true } # Polkadot Dependencies xcm = { workspace = true } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 79201a8756f9..800e2a3da3a3 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -20,10 +20,10 @@ bp-messages = { workspace = true } bp-runtime = { workspace = true } # Substrate Dependencies -sp-std = { workspace = true } -sp-io = { workspace = true } -sp-core = { workspace = true } frame-support = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-std = { workspace = true } # Polkadot Dependencies xcm = { workspace = true } diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 061e7a275063..471cf402c34f 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -87,6 +87,11 @@ impl BridgeId { .into(), ) } + + /// Access the inner representation. + pub fn inner(&self) -> H256 { + self.0 + } } impl core::fmt::Debug for BridgeId { @@ -359,10 +364,11 @@ impl BridgeLocations { #[cfg(test)] mod tests { use super::*; + use xcm::latest::ROCOCO_GENESIS_HASH; const LOCAL_NETWORK: NetworkId = Kusama; const REMOTE_NETWORK: NetworkId = Polkadot; - const UNREACHABLE_NETWORK: NetworkId = Rococo; + const UNREACHABLE_NETWORK: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); const SIBLING_PARACHAIN: u32 = 1000; const LOCAL_BRIDGE_HUB: u32 = 1001; const REMOTE_PARACHAIN: u32 = 2000; diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml index 6065c23773e3..6a59688b2d8c 100644 --- a/bridges/relays/client-substrate/Cargo.toml +++ b/bridges/relays/client-substrate/Cargo.toml @@ -18,16 +18,16 @@ futures = { workspace = true } jsonrpsee = { features = ["macros", "ws-client"], workspace = true } log = { workspace = true } num-traits = { workspace = true, default-features = true } +quick_cache = { workspace = true } rand = { workspace = true, default-features = true } -serde_json = { workspace = true } scale-info = { features = [ "derive", ], workspace = true, default-features = true } +serde_json = { workspace = true } +thiserror = { workspace = true } tokio = { features = [ "rt-multi-thread", ], workspace = true, default-features = true } -thiserror = { workspace = true } -quick_cache = { workspace = true } # Bridge dependencies diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index b0f93e5b5485..b418a2a3abb8 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -32,29 +32,29 @@ bp-relayers = { workspace = true, default-features = true } equivocation-detector = { workspace = true } finality-relay = { workspace = true } -parachains-relay = { workspace = true } -relay-utils = { workspace = true } messages-relay = { workspace = true } +parachains-relay = { workspace = true } relay-substrate-client = { workspace = true } +relay-utils = { workspace = true } pallet-bridge-grandpa = { workspace = true, default-features = true } pallet-bridge-messages = { workspace = true, default-features = true } pallet-bridge-parachains = { workspace = true, default-features = true } -bp-runtime = { workspace = true, default-features = true } bp-messages = { workspace = true, default-features = true } +bp-runtime = { workspace = true, default-features = true } # Substrate Dependencies frame-support = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-grandpa = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-trie = { workspace = true } [dev-dependencies] -scale-info = { features = ["derive"], workspace = true } pallet-transaction-payment = { workspace = true, default-features = true } relay-substrate-client = { features = ["test-helpers"], workspace = true } +scale-info = { features = ["derive"], workspace = true } diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index 4c25566607dc..8592ca780eaa 100644 --- a/bridges/relays/utils/Cargo.toml +++ b/bridges/relays/utils/Cargo.toml @@ -16,18 +16,18 @@ async-std = { workspace = true } async-trait = { workspace = true } backoff = { workspace = true } console = { workspace = true } -isahc = { workspace = true } -sp-tracing = { workspace = true, default-features = true } futures = { workspace = true } +isahc = { workspace = true } jsonpath_lib = { workspace = true } log = { workspace = true } num-traits = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } sysinfo = { workspace = true } +thiserror = { workspace = true } time = { features = ["formatting", "local-offset", "std"], workspace = true } tokio = { features = ["rt"], workspace = true, default-features = true } -thiserror = { workspace = true } # Bridge dependencies @@ -35,5 +35,5 @@ bp-runtime = { workspace = true, default-features = true } # Substrate dependencies -sp-runtime = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/bridges/relays/utils/src/initialize.rs b/bridges/relays/utils/src/initialize.rs index 564ed1f0e5cc..deb9b9d059d5 100644 --- a/bridges/relays/utils/src/initialize.rs +++ b/bridges/relays/utils/src/initialize.rs @@ -52,9 +52,10 @@ pub fn initialize_logger(with_timestamp: bool) { format, ); - let env_filter = EnvFilter::from_default_env() - .add_directive(Level::WARN.into()) - .add_directive("bridge=info".parse().expect("static filter string is valid")); + let env_filter = EnvFilter::builder() + .with_default_directive(Level::WARN.into()) + .with_default_directive("bridge=info".parse().expect("static filter string is valid")) + .from_env_lossy(); let builder = SubscriberBuilder::default().with_env_filter(env_filter); diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index 262d9a7f380d..ebd8a1c6ed11 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -15,37 +15,37 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { optional = true, workspace = true, default-features = true } -serde_json = { optional = true, workspace = true, default-features = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } +serde_json = { optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } sp-core = { workspace = true } -sp-std = { workspace = true } -sp-runtime = { workspace = true } sp-io = { optional = true, workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +pallet-timestamp = { optional = true, workspace = true } +snowbridge-beacon-primitives = { workspace = true } snowbridge-core = { workspace = true } snowbridge-ethereum = { workspace = true } snowbridge-pallet-ethereum-client-fixtures = { optional = true, workspace = true } -snowbridge-beacon-primitives = { workspace = true } static_assertions = { workspace = true } -pallet-timestamp = { optional = true, workspace = true } [dev-dependencies] -rand = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } pallet-timestamp = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } snowbridge-pallet-ethereum-client-fixtures = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -serde = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml index 87f0cf9a5513..74bfe580ec36 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] hex-literal = { workspace = true, default-features = true } +snowbridge-beacon-primitives = { workspace = true } +snowbridge-core = { workspace = true } sp-core = { workspace = true } sp-std = { workspace = true } -snowbridge-core = { workspace = true } -snowbridge-beacon-primitives = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml index 1b08bb39b434..5d4e8ad67662 100644 --- a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml @@ -15,42 +15,40 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { optional = true, workspace = true, default-features = true } +alloy-core = { workspace = true, features = ["sol-types"] } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } -alloy-primitives = { features = ["rlp"], workspace = true } -alloy-sol-types = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-balances = { workspace = true } sp-core = { workspace = true } -sp-std = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } xcm = { workspace = true } xcm-executor = { workspace = true } -snowbridge-core = { workspace = true } -snowbridge-router-primitives = { workspace = true } snowbridge-beacon-primitives = { workspace = true } +snowbridge-core = { workspace = true } snowbridge-pallet-inbound-queue-fixtures = { optional = true, workspace = true } +snowbridge-router-primitives = { workspace = true } [dev-dependencies] frame-benchmarking = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -snowbridge-pallet-ethereum-client = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } +snowbridge-pallet-ethereum-client = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } [features] default = ["std"] std = [ - "alloy-primitives/std", - "alloy-sol-types/std", + "alloy-core/std", "codec/std", "frame-benchmarking/std", "frame-support/std", @@ -83,6 +81,7 @@ runtime-benchmarks = [ "snowbridge-router-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml index 6162a17728b6..c698dbbf1003 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] hex-literal = { workspace = true, default-features = true } +snowbridge-beacon-primitives = { workspace = true } +snowbridge-core = { workspace = true } sp-core = { workspace = true } sp-std = { workspace = true } -snowbridge-core = { workspace = true } -snowbridge-beacon-primitives = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs b/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs index 31a8992442d8..d213c8aad648 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs @@ -5,8 +5,7 @@ use snowbridge_core::{inbound::Log, ChannelId}; use sp_core::{RuntimeDebug, H160, H256}; use sp_std::prelude::*; -use alloy_primitives::B256; -use alloy_sol_types::{sol, SolEvent}; +use alloy_core::{primitives::B256, sol, sol_types::SolEvent}; sol! { event OutboundMessageAccepted(bytes32 indexed channel_id, uint64 nonce, bytes32 indexed message_id, bytes payload); @@ -36,7 +35,7 @@ impl TryFrom<&Log> for Envelope { fn try_from(log: &Log) -> Result { let topics: Vec = log.topics.iter().map(|x| B256::from_slice(x.as_ref())).collect(); - let event = OutboundMessageAccepted::decode_log(topics, &log.data, true) + let event = OutboundMessageAccepted::decode_raw_log(topics, &log.data, true) .map_err(|_| EnvelopeDecodeError)?; Ok(Self { @@ -44,7 +43,7 @@ impl TryFrom<&Log> for Envelope { channel_id: ChannelId::from(event.channel_id.as_ref()), nonce: event.nonce, message_id: H256::from(event.message_id.as_ref()), - payload: event.payload, + payload: event.payload.into(), }) } } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 3e67d5ab738b..eed0656e9ca7 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -19,7 +19,10 @@ use sp_runtime::{ BuildStorage, FixedU128, MultiSignature, }; use sp_std::{convert::From, default::Default}; -use xcm::{latest::SendXcm, prelude::*}; +use xcm::{ + latest::{SendXcm, WESTEND_GENESIS_HASH}, + prelude::*, +}; use xcm_executor::AssetsInHolding; use crate::{self as inbound_queue}; @@ -113,8 +116,8 @@ parameter_types! { pub const InitialFund: u128 = 1_000_000_000_000; pub const InboundQueuePalletInstance: u8 = 80; pub UniversalLocation: InteriorLocation = - [GlobalConsensus(Westend), Parachain(1002)].into(); - pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(Westend),Parachain(1000)]); + [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1002)].into(); + pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)),Parachain(1000)]); } #[cfg(feature = "runtime-benchmarks")] @@ -245,20 +248,6 @@ impl inbound_queue::Config for Test { type AssetTransactor = SuccessfulTransactor; } -pub fn last_events(n: usize) -> Vec { - frame_system::Pallet::::events() - .into_iter() - .rev() - .take(n) - .rev() - .map(|e| e.event) - .collect() -} - -pub fn expect_events(e: Vec) { - assert_eq!(last_events(e.len()), e); -} - pub fn setup() { System::set_block_number(1); Balances::mint_into( diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 41c38460aabf..aa99d63b4bf9 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -5,11 +5,11 @@ use super::*; use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; use snowbridge_core::{inbound::Proof, ChannelId}; -use sp_keyring::AccountKeyring as Keyring; +use sp_keyring::Sr25519Keyring as Keyring; use sp_runtime::DispatchError; use sp_std::convert::From; -use crate::{Error, Event as InboundQueueEvent}; +use crate::Error; use crate::mock::*; @@ -35,17 +35,16 @@ fn test_submit_happy_path() { assert_eq!(Balances::balance(&channel_sovereign), initial_fund); assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); - expect_events(vec![InboundQueueEvent::MessageReceived { - channel_id: hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539") - .into(), - nonce: 1, - message_id: [ - 255, 125, 48, 71, 174, 185, 100, 26, 159, 43, 108, 6, 116, 218, 55, 155, 223, 143, - 141, 22, 124, 110, 241, 18, 122, 217, 130, 29, 139, 76, 97, 201, - ], - fee_burned: 110000000000, - } - .into()]); + + let events = frame_system::Pallet::::events(); + assert!( + events.iter().any(|event| matches!( + event.event, + RuntimeEvent::InboundQueue(Event::MessageReceived { nonce, ..}) + if nonce == 1 + )), + "no event emit." + ); let delivery_cost = InboundQueue::calculate_delivery_cost(message.encode().len() as u32); assert!( diff --git a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml index 78546e258daa..f4910e6e6457 100644 --- a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml @@ -15,24 +15,24 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { features = ["alloc", "derive"], workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +serde = { features = ["alloc", "derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } -sp-std = { workspace = true } -sp-runtime = { workspace = true } sp-io = { workspace = true } -sp-arithmetic = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } bridge-hub-common = { workspace = true } +ethabi = { workspace = true } snowbridge-core = { features = ["serde"], workspace = true } snowbridge-outbound-queue-merkle-tree = { workspace = true } -ethabi = { workspace = true } [dev-dependencies] pallet-message-queue = { workspace = true } diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 16241428df80..2a0616b4f954 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -22,9 +22,9 @@ sp-core = { workspace = true } sp-runtime = { workspace = true } [dev-dependencies] -hex-literal = { workspace = true, default-features = true } -hex = { workspace = true, default-features = true } array-bytes = { workspace = true, default-features = true } +hex = { workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } diff --git a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml index d35bdde5a81e..18f7dde22c93 100644 --- a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml @@ -16,11 +16,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -sp-std = { workspace = true } -sp-api = { workspace = true } frame-support = { workspace = true } -snowbridge-outbound-queue-merkle-tree = { workspace = true } snowbridge-core = { workspace = true } +snowbridge-outbound-queue-merkle-tree = { workspace = true } +sp-api = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/system/Cargo.toml b/bridges/snowbridge/pallets/system/Cargo.toml index f1e749afb997..3544925956b4 100644 --- a/bridges/snowbridge/pallets/system/Cargo.toml +++ b/bridges/snowbridge/pallets/system/Cargo.toml @@ -18,16 +18,16 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } -sp-std = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } xcm = { workspace = true } xcm-executor = { workspace = true } @@ -38,10 +38,10 @@ snowbridge-core = { workspace = true } hex = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } pallet-message-queue = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } snowbridge-pallet-outbound-queue = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } [features] default = ["std"] @@ -71,6 +71,7 @@ runtime-benchmarks = [ "snowbridge-pallet-outbound-queue/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml index 7c524dd2edad..fc377b460d33 100644 --- a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -sp-std = { workspace = true } +snowbridge-core = { workspace = true } sp-api = { workspace = true } +sp-std = { workspace = true } xcm = { workspace = true } -snowbridge-core = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/pallets/system/src/benchmarking.rs b/bridges/snowbridge/pallets/system/src/benchmarking.rs index 20798b7c3493..939de9d40d13 100644 --- a/bridges/snowbridge/pallets/system/src/benchmarking.rs +++ b/bridges/snowbridge/pallets/system/src/benchmarking.rs @@ -169,7 +169,7 @@ mod benchmarks { T::Token::mint_into(&caller, amount)?; let relay_token_asset_id: Location = Location::parent(); - let asset = Box::new(VersionedLocation::V4(relay_token_asset_id)); + let asset = Box::new(VersionedLocation::from(relay_token_asset_id)); let asset_metadata = AssetMetadata { name: "wnd".as_bytes().to_vec().try_into().unwrap(), symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs index 1e8a788b7a5a..eb3da095fe85 100644 --- a/bridges/snowbridge/pallets/system/src/lib.rs +++ b/bridges/snowbridge/pallets/system/src/lib.rs @@ -269,12 +269,12 @@ pub mod pallet { /// Lookup table for foreign token ID to native location relative to ethereum #[pallet::storage] pub type ForeignToNativeId = - StorageMap<_, Blake2_128Concat, TokenId, xcm::v4::Location, OptionQuery>; + StorageMap<_, Blake2_128Concat, TokenId, xcm::v5::Location, OptionQuery>; /// Lookup table for native location relative to ethereum to foreign token ID #[pallet::storage] pub type NativeToForeignId = - StorageMap<_, Blake2_128Concat, xcm::v4::Location, TokenId, OptionQuery>; + StorageMap<_, Blake2_128Concat, xcm::v5::Location, TokenId, OptionQuery>; #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] diff --git a/bridges/snowbridge/primitives/beacon/Cargo.toml b/bridges/snowbridge/primitives/beacon/Cargo.toml index 9ced99fbf3fd..bf5d6838f7bb 100644 --- a/bridges/snowbridge/primitives/beacon/Cargo.toml +++ b/bridges/snowbridge/primitives/beacon/Cargo.toml @@ -12,24 +12,24 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { optional = true, features = ["derive"], workspace = true, default-features = true } -hex = { workspace = true } codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } +hex = { workspace = true } rlp = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } frame-support = { workspace = true } -sp-runtime = { workspace = true } sp-core = { workspace = true } -sp-std = { workspace = true } sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +byte-slice-cast = { workspace = true } ssz_rs = { workspace = true } ssz_rs_derive = { workspace = true } -byte-slice-cast = { workspace = true } -snowbridge-ethereum = { workspace = true } milagro-bls = { workspace = true } +snowbridge-ethereum = { workspace = true } [dev-dependencies] hex-literal = { workspace = true, default-features = true } diff --git a/bridges/snowbridge/primitives/core/Cargo.toml b/bridges/snowbridge/primitives/core/Cargo.toml index fa37c795b2d1..514579400aca 100644 --- a/bridges/snowbridge/primitives/core/Cargo.toml +++ b/bridges/snowbridge/primitives/core/Cargo.toml @@ -12,10 +12,10 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { optional = true, features = ["alloc", "derive"], workspace = true } codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } hex-literal = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, features = ["alloc", "derive"], workspace = true } polkadot-parachain-primitives = { workspace = true } xcm = { workspace = true } @@ -23,11 +23,11 @@ xcm-builder = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-arithmetic = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -sp-io = { workspace = true } -sp-core = { workspace = true } -sp-arithmetic = { workspace = true } snowbridge-beacon-primitives = { workspace = true } @@ -64,4 +64,5 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/bridges/snowbridge/primitives/core/src/location.rs b/bridges/snowbridge/primitives/core/src/location.rs index aad1c9ece05c..f49a245c4126 100644 --- a/bridges/snowbridge/primitives/core/src/location.rs +++ b/bridges/snowbridge/primitives/core/src/location.rs @@ -97,9 +97,12 @@ impl DescribeLocation for DescribeTokenTerminal { #[cfg(test)] mod tests { use crate::TokenIdOf; - use xcm::prelude::{ - GeneralIndex, GeneralKey, GlobalConsensus, Junction::*, Location, NetworkId::*, - PalletInstance, Parachain, + use xcm::{ + latest::WESTEND_GENESIS_HASH, + prelude::{ + GeneralIndex, GeneralKey, GlobalConsensus, Junction::*, Location, NetworkId::ByGenesis, + PalletInstance, Parachain, + }, }; use xcm_executor::traits::ConvertLocation; @@ -108,17 +111,24 @@ mod tests { let token_locations = [ // Relay Chain cases // Relay Chain relative to Ethereum - Location::new(1, [GlobalConsensus(Westend)]), + Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]), // Parachain cases // Parachain relative to Ethereum - Location::new(1, [GlobalConsensus(Westend), Parachain(2000)]), + Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000)]), // Parachain general index - Location::new(1, [GlobalConsensus(Westend), Parachain(2000), GeneralIndex(1)]), + Location::new( + 1, + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(2000), + GeneralIndex(1), + ], + ), // Parachain general key Location::new( 1, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000), GeneralKey { length: 32, data: [0; 32] }, ], @@ -127,7 +137,7 @@ mod tests { Location::new( 1, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000), AccountKey20 { network: None, key: [0; 20] }, ], @@ -136,24 +146,36 @@ mod tests { Location::new( 1, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000), AccountId32 { network: None, id: [0; 32] }, ], ), // Parchain Pallet instance cases // Parachain pallet instance - Location::new(1, [GlobalConsensus(Westend), Parachain(2000), PalletInstance(8)]), + Location::new( + 1, + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(2000), + PalletInstance(8), + ], + ), // Parachain Pallet general index Location::new( 1, - [GlobalConsensus(Westend), Parachain(2000), PalletInstance(8), GeneralIndex(1)], + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(2000), + PalletInstance(8), + GeneralIndex(1), + ], ), // Parachain Pallet general key Location::new( 1, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000), PalletInstance(8), GeneralKey { length: 32, data: [0; 32] }, @@ -163,7 +185,7 @@ mod tests { Location::new( 1, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000), PalletInstance(8), AccountKey20 { network: None, key: [0; 20] }, @@ -173,7 +195,7 @@ mod tests { Location::new( 1, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2000), PalletInstance(8), AccountId32 { network: None, id: [0; 32] }, diff --git a/bridges/snowbridge/primitives/ethereum/Cargo.toml b/bridges/snowbridge/primitives/ethereum/Cargo.toml index 764ce90b8139..44ea2d0d222b 100644 --- a/bridges/snowbridge/primitives/ethereum/Cargo.toml +++ b/bridges/snowbridge/primitives/ethereum/Cargo.toml @@ -12,26 +12,26 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -serde = { optional = true, features = ["derive"], workspace = true, default-features = true } -serde-big-array = { optional = true, features = ["const-generics"], workspace = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } ethbloom = { workspace = true } ethereum-types = { features = ["codec", "rlp", "serialize"], workspace = true } hex-literal = { workspace = true } parity-bytes = { workspace = true } rlp = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde-big-array = { optional = true, features = ["const-generics"], workspace = true } sp-io = { workspace = true } -sp-std = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } ethabi = { workspace = true } [dev-dependencies] -wasm-bindgen-test = { workspace = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +wasm-bindgen-test = { workspace = true } [features] default = ["std"] diff --git a/bridges/snowbridge/primitives/router/Cargo.toml b/bridges/snowbridge/primitives/router/Cargo.toml index ee8d481cec12..e44cca077ef3 100644 --- a/bridges/snowbridge/primitives/router/Cargo.toml +++ b/bridges/snowbridge/primitives/router/Cargo.toml @@ -13,8 +13,8 @@ workspace = true [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } sp-core = { workspace = true } @@ -51,4 +51,5 @@ runtime-benchmarks = [ "snowbridge-core/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index a9324ac42470..bc5d401cd4f7 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs @@ -7,7 +7,7 @@ mod tests; use codec::{Decode, Encode}; use core::marker::PhantomData; -use frame_support::{traits::tokens::Balance as BalanceT, weights::Weight, PalletError}; +use frame_support::{traits::tokens::Balance as BalanceT, PalletError}; use scale_info::TypeInfo; use snowbridge_core::TokenId; use sp_core::{Get, RuntimeDebug, H160, H256}; @@ -253,7 +253,7 @@ where let bridge_location = Location::new(2, GlobalConsensus(network)); - let owner = GlobalConsensusEthereumConvertsFor::<[u8; 32]>::from_chain_id(&chain_id); + let owner = EthereumLocationsConverterFor::<[u8; 32]>::from_chain_id(&chain_id); let asset_id = Self::convert_token_address(network, token); let create_call_index: [u8; 2] = CreateAssetCall::get(); let inbound_queue_pallet_index = InboundQueuePalletInstance::get(); @@ -279,7 +279,7 @@ where // Call create_asset on foreign assets pallet. Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(400_000_000, 8_000), + fallback_max_weight: Some(Weight::from_parts(400_000_000, 8_000)), call: ( create_call_index, asset_id, @@ -358,7 +358,9 @@ where }])), // Perform a deposit reserve to send to destination chain. DepositReserveAsset { - assets: Definite(vec![dest_para_fee_asset.clone(), asset].into()), + // Send over assets and unspent fees, XCM delivery fee will be charged from + // here. + assets: Wild(AllCounted(2)), dest: Location::new(1, [Parachain(dest_para_id)]), xcm: vec![ // Buy execution on target. @@ -454,22 +456,27 @@ where } } -pub struct GlobalConsensusEthereumConvertsFor(PhantomData); -impl ConvertLocation for GlobalConsensusEthereumConvertsFor +pub struct EthereumLocationsConverterFor(PhantomData); +impl ConvertLocation for EthereumLocationsConverterFor where AccountId: From<[u8; 32]> + Clone, { fn convert_location(location: &Location) -> Option { match location.unpack() { - (_, [GlobalConsensus(Ethereum { chain_id })]) => + (2, [GlobalConsensus(Ethereum { chain_id })]) => Some(Self::from_chain_id(chain_id).into()), + (2, [GlobalConsensus(Ethereum { chain_id }), AccountKey20 { network: _, key }]) => + Some(Self::from_chain_id_with_key(chain_id, *key).into()), _ => None, } } } -impl GlobalConsensusEthereumConvertsFor { +impl EthereumLocationsConverterFor { pub fn from_chain_id(chain_id: &u64) -> [u8; 32] { (b"ethereum-chain", chain_id).using_encoded(blake2_256) } + pub fn from_chain_id_with_key(chain_id: &u64, key: [u8; 20]) -> [u8; 32] { + (b"ethereum-chain", chain_id, key).using_encoded(blake2_256) + } } diff --git a/bridges/snowbridge/primitives/router/src/inbound/tests.rs b/bridges/snowbridge/primitives/router/src/inbound/tests.rs index e0e90e516be1..786aa594f653 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/tests.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/tests.rs @@ -1,4 +1,4 @@ -use super::GlobalConsensusEthereumConvertsFor; +use super::EthereumLocationsConverterFor; use crate::inbound::CallIndex; use frame_support::{assert_ok, parameter_types}; use hex_literal::hex; @@ -17,14 +17,28 @@ parameter_types! { } #[test] -fn test_contract_location_with_network_converts_successfully() { +fn test_ethereum_network_converts_successfully() { let expected_account: [u8; 32] = hex!("ce796ae65569a670d0c1cc1ac12515a3ce21b5fbf729d63d7b289baad070139d"); let contract_location = Location::new(2, [GlobalConsensus(NETWORK)]); let account = - GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(&contract_location) - .unwrap(); + EthereumLocationsConverterFor::<[u8; 32]>::convert_location(&contract_location).unwrap(); + + assert_eq!(account, expected_account); +} + +#[test] +fn test_contract_location_with_network_converts_successfully() { + let expected_account: [u8; 32] = + hex!("9038d35aba0e78e072d29b2d65be9df5bb4d7d94b4609c9cf98ea8e66e544052"); + let contract_location = Location::new( + 2, + [GlobalConsensus(NETWORK), AccountKey20 { network: None, key: [123u8; 20] }], + ); + + let account = + EthereumLocationsConverterFor::<[u8; 32]>::convert_location(&contract_location).unwrap(); assert_eq!(account, expected_account); } @@ -34,7 +48,7 @@ fn test_contract_location_with_incorrect_location_fails_convert() { let contract_location = Location::new(2, [GlobalConsensus(Polkadot), Parachain(1000)]); assert_eq!( - GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(&contract_location), + EthereumLocationsConverterFor::<[u8; 32]>::convert_location(&contract_location), None, ); } diff --git a/bridges/snowbridge/primitives/router/src/outbound/tests.rs b/bridges/snowbridge/primitives/router/src/outbound/tests.rs index 8bd3fa24df5b..44f81ce31b3a 100644 --- a/bridges/snowbridge/primitives/router/src/outbound/tests.rs +++ b/bridges/snowbridge/primitives/router/src/outbound/tests.rs @@ -5,7 +5,10 @@ use snowbridge_core::{ AgentIdOf, }; use sp_std::default::Default; -use xcm::prelude::SendError as XcmSendError; +use xcm::{ + latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, + prelude::SendError as XcmSendError, +}; use super::*; @@ -61,7 +64,7 @@ impl SendMessageFeeProvider for MockErrOutboundQueue { pub struct MockTokenIdConvert; impl MaybeEquivalence for MockTokenIdConvert { fn convert(_id: &TokenId) -> Option { - Some(Location::new(1, [GlobalConsensus(Westend)])) + Some(Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))])) } fn convert_back(_loc: &Location) -> Option { None @@ -1109,7 +1112,7 @@ fn xcm_converter_transfer_native_token_success() { let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); let amount = 1000000; - let asset_location = Location::new(1, [GlobalConsensus(Westend)]); + let asset_location = Location::new(1, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]); let token_id = TokenIdOf::convert_location(&asset_location).unwrap(); let assets: Assets = vec![Asset { id: AssetId(asset_location), fun: Fungible(amount) }].into(); @@ -1142,7 +1145,8 @@ fn xcm_converter_transfer_native_token_with_invalid_location_will_fail() { let amount = 1000000; // Invalid asset location from a different consensus - let asset_location = Location { parents: 2, interior: [GlobalConsensus(Rococo)].into() }; + let asset_location = + Location { parents: 2, interior: [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))].into() }; let assets: Assets = vec![Asset { id: AssetId(asset_location), fun: Fungible(amount) }].into(); let filter: AssetFilter = assets.clone().into(); @@ -1221,7 +1225,8 @@ fn exporter_validate_with_invalid_universal_source_does_not_alter_universal_sour let network = BridgedNetwork::get(); let destination: InteriorLocation = Here.into(); - let universal_source: InteriorLocation = [GlobalConsensus(Westend), Parachain(1000)].into(); + let universal_source: InteriorLocation = + [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000)].into(); let token_address: [u8; 20] = hex!("1000000000000000000000000000000000000000"); let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); diff --git a/bridges/snowbridge/runtime/runtime-common/Cargo.toml b/bridges/snowbridge/runtime/runtime-common/Cargo.toml index d47cb3cb7101..23cd0adf1226 100644 --- a/bridges/snowbridge/runtime/runtime-common/Cargo.toml +++ b/bridges/snowbridge/runtime/runtime-common/Cargo.toml @@ -12,11 +12,11 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -log = { workspace = true } codec = { workspace = true } frame-support = { workspace = true } -sp-std = { workspace = true } +log = { workspace = true } sp-arithmetic = { workspace = true } +sp-std = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } @@ -43,4 +43,5 @@ runtime-benchmarks = [ "snowbridge-core/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index 6f8e586bf5ff..184a0ff2329f 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -6,6 +6,8 @@ authors = ["Snowfork "] edition.workspace = true license = "Apache-2.0" categories = ["cryptography::cryptocurrencies"] +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,8 +19,8 @@ codec = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-balances = { workspace = true } -pallet-session = { workspace = true } pallet-message-queue = { workspace = true } +pallet-session = { workspace = true } pallet-timestamp = { workspace = true } pallet-utility = { workspace = true } sp-core = { workspace = true } @@ -90,5 +92,6 @@ runtime-benchmarks = [ "snowbridge-pallet-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] fast-runtime = [] diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index b157ad4356bd..5441dd822cac 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -13,12 +13,9 @@ use parachains_runtimes_test_utils::{ use snowbridge_core::{ChannelId, ParaId}; use snowbridge_pallet_ethereum_client_fixtures::*; use sp_core::{Get, H160, U256}; -use sp_keyring::AccountKeyring::*; +use sp_keyring::Sr25519Keyring::*; use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating}; -use xcm::{ - latest::prelude::*, - v3::Error::{self, Barrier}, -}; +use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; type RuntimeHelper = @@ -374,7 +371,7 @@ pub fn send_unpaid_transfer_token_message( Weight::zero(), ); // check error is barrier - assert_err!(outcome.ensure_complete(), Barrier); + assert_err!(outcome.ensure_complete(), XcmError::Barrier); }); } @@ -388,7 +385,7 @@ pub fn send_transfer_token_message_failure( weth_contract_address: H160, destination_address: H160, fee_amount: u128, - expected_error: Error, + expected_error: XcmError, ) where Runtime: frame_system::Config + pallet_balances::Config @@ -434,7 +431,7 @@ pub fn ethereum_extrinsic( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, ) where @@ -570,7 +567,7 @@ pub fn ethereum_to_polkadot_message_extrinsics_work( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, ) where diff --git a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh index e7848fe7163c..321f4d9f26d0 100755 --- a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -7,47 +7,52 @@ source "$FRAMEWORK_PATH/utils/bridges.sh" # # Generated by: # -# #[test] -# fn generate_sovereign_accounts() { -# use sp_core::crypto::Ss58Codec; -# use polkadot_parachain_primitives::primitives::Sibling; +##[test] +#fn generate_sovereign_accounts() { +# use polkadot_parachain_primitives::primitives::Sibling; +# use sp_core::crypto::Ss58Codec; +# use staging_xcm_builder::{GlobalConsensusConvertsFor, SiblingParachainConvertsVia}; +# use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}; +# use xcm_executor::traits::ConvertLocation; # -# parameter_types! { -# pub UniversalLocationAHR: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(1000)); -# pub UniversalLocationAHW: InteriorMultiLocation = X2(GlobalConsensus(Westend), Parachain(1000)); -# } +# const Rococo: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); +# const Westend: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH); +# frame_support::parameter_types! { +# pub UniversalLocationAHR: InteriorLocation = [GlobalConsensus(Rococo), Parachain(1000)].into(); +# pub UniversalLocationAHW: InteriorLocation = [GlobalConsensus(Westend), Parachain(1000)].into(); +# } # -# // SS58=42 -# println!("GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusConvertsFor::::convert_location( -# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); -# println!("ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# SiblingParachainConvertsVia::::convert_location( -# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); +# // SS58=42 +# println!("GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &Location { parents: 2, interior: GlobalConsensus(Rococo).into() }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &Location { parents: 1, interior: Parachain(1000).into() }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); # -# // SS58=42 -# println!("GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusConvertsFor::::convert_location( -# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Westend)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); -# println!("ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# SiblingParachainConvertsVia::::convert_location( -# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); -# } -GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT="5GxRGwT8bU1JeBPTUXc7LEjZMxNrK8MyL2NJnkWFQJTQ4sii" +# // SS58=42 +# println!("GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &Location { parents: 2, interior: GlobalConsensus(Westend).into() }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &Location { parents: 1, interior: Parachain(1000).into() }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +#} +GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT="5HmYPhRNAenHN6xnDLQDLZq71d4BgzPrdJ2sNZo8o1KXi9wr" ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" -GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT="5He2Qdztyxxa4GoagY6q1jaiLMmKy1gXS7PdZkhfj8ZG9hk5" +GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT="5CtHyjQE8fbPaQeBrwaGph6qsSEtnMFBAZcAkxwnEfQkkYAq" ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" # Expected sovereign accounts for rewards on BridgeHubs. @@ -115,7 +120,11 @@ ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXa ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5Tnt3VGpEvc6jSgYwVToDGxLRMuYoZ8coo6GHyWbR" LANE_ID="00000002" -XCM_VERSION=3 +XCM_VERSION=5 +# 6408de7737c59c238890533af25896a2c20608d8b380bb01029acb392781063e +ROCOCO_GENESIS_HASH=[100,8,222,119,55,197,156,35,136,144,83,58,242,88,150,162,194,6,8,216,179,128,187,1,2,154,203,57,39,129,6,62] +# e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e +WESTEND_GENESIS_HASH=[225,67,242,56,3,172,80,232,246,248,230,38,149,209,206,158,78,29,104,170,54,193,205,44,253,21,52,2,19,243,66,62] function init_ro_wnd() { local relayer_path=$(ensure_relayer) @@ -270,7 +279,7 @@ case "$1" in "//Alice" \ 1000 \ "ws://127.0.0.1:9910" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X1": [{ "GlobalConsensus": "Westend" }] } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": [{ "GlobalConsensus": { ByGenesis: '$WESTEND_GENESIS_HASH' } }] } }')" \ "$GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT" \ 10000000000 \ true @@ -289,7 +298,7 @@ case "$1" in "//Alice" \ 1000 \ "ws://127.0.0.1:9910" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$WESTEND_GENESIS_HASH' } }, { "Parachain": 1000 } ] } }')" \ $XCM_VERSION ;; init-bridge-hub-rococo-local) @@ -318,7 +327,7 @@ case "$1" in "//Alice" \ 1013 \ "ws://127.0.0.1:8943" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1002 } ] } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$WESTEND_GENESIS_HASH' } }, { "Parachain": 1002 } ] } }')" \ $XCM_VERSION ;; init-asset-hub-westend-local) @@ -329,7 +338,7 @@ case "$1" in "//Alice" \ 1000 \ "ws://127.0.0.1:9010" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X1": [{ "GlobalConsensus": "Rococo" }] } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": [{ "GlobalConsensus": { ByGenesis: '$ROCOCO_GENESIS_HASH' } }] } }')" \ "$GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT" \ 10000000000 \ true @@ -348,7 +357,7 @@ case "$1" in "//Alice" \ 1000 \ "ws://127.0.0.1:9010" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$ROCOCO_GENESIS_HASH' } }, { "Parachain": 1000 } ] } }')" \ $XCM_VERSION ;; init-bridge-hub-westend-local) @@ -376,7 +385,7 @@ case "$1" in "//Alice" \ 1002 \ "ws://127.0.0.1:8945" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1013 } ] } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$ROCOCO_GENESIS_HASH' } }, { "Parachain": 1013 } ] } }')" \ $XCM_VERSION ;; reserve-transfer-assets-from-asset-hub-rococo-local) @@ -386,9 +395,9 @@ case "$1" in limited_reserve_transfer_assets \ "ws://127.0.0.1:9910" \ "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ + "$(jq --null-input '{ "V5": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$WESTEND_GENESIS_HASH' } }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V5": { "parents": 0, "interior": { "X1": [{ "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } }] } } }')" \ + "$(jq --null-input '{ "V5": [ { "id": { "parents": 1, "interior": "Here" }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; @@ -399,9 +408,9 @@ case "$1" in limited_reserve_transfer_assets \ "ws://127.0.0.1:9910" \ "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ + "$(jq --null-input '{ "V5": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$WESTEND_GENESIS_HASH' } }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V5": { "parents": 0, "interior": { "X1": [{ "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } }] } } }')" \ + "$(jq --null-input '{ "V5": [ { "id": { "parents": 2, "interior": { "X1": [{ "GlobalConsensus": { ByGenesis: '$WESTEND_GENESIS_HASH' } }] } }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; @@ -412,9 +421,9 @@ case "$1" in limited_reserve_transfer_assets \ "ws://127.0.0.1:9010" \ "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ + "$(jq --null-input '{ "V5": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$ROCOCO_GENESIS_HASH' } }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V5": { "parents": 0, "interior": { "X1": [{ "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } }] } } }')" \ + "$(jq --null-input '{ "V5": [ { "id": { "parents": 1, "interior": "Here" }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; @@ -425,9 +434,9 @@ case "$1" in limited_reserve_transfer_assets \ "ws://127.0.0.1:9010" \ "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ + "$(jq --null-input '{ "V5": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": { ByGenesis: '$ROCOCO_GENESIS_HASH' } }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V5": { "parents": 0, "interior": { "X1": [{ "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } }] } } }')" \ + "$(jq --null-input '{ "V5": [ { "id": { "parents": 2, "interior": { "X1": [{ "GlobalConsensus": { ByGenesis: '$ROCOCO_GENESIS_HASH' } }] } }, "fun": { "Fungible": '$amount' } } ] }')" \ 0 \ "Unlimited" ;; diff --git a/bridges/testing/framework/js-helpers/wrapped-assets-balance.js b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js index 7b343ed97a88..837b3a3b1dbc 100644 --- a/bridges/testing/framework/js-helpers/wrapped-assets-balance.js +++ b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js @@ -3,17 +3,15 @@ async function run(nodeName, networkInfo, args) { const api = await zombie.connect(wsUri, userDefinedTypes); // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later - const accountAddress = args[0]; - const expectedForeignAssetBalance = BigInt(args[1]); - const bridgedNetworkName = args[2]; + const accountAddress = args.accountAddress; + const expectedAssetId = args.expectedAssetId; + const expectedAssetBalance = BigInt(args.expectedAssetBalance); + while (true) { - const foreignAssetAccount = await api.query.foreignAssets.account( - { parents: 2, interior: { X1: [{ GlobalConsensus: bridgedNetworkName }] } }, - accountAddress - ); + const foreignAssetAccount = await api.query.foreignAssets.account(expectedAssetId, accountAddress); if (foreignAssetAccount.isSome) { const foreignAssetAccountBalance = foreignAssetAccount.unwrap().balance.toBigInt(); - if (foreignAssetAccountBalance > expectedForeignAssetBalance) { + if (foreignAssetAccountBalance > expectedAssetBalance) { return foreignAssetAccountBalance; } } diff --git a/bridges/testing/framework/utils/bridges.sh b/bridges/testing/framework/utils/bridges.sh index 07d9e4cd50b1..3d7b37b4ffc2 100755 --- a/bridges/testing/framework/utils/bridges.sh +++ b/bridges/testing/framework/utils/bridges.sh @@ -114,7 +114,7 @@ function send_governance_transact() { local dest=$(jq --null-input \ --arg para_id "$para_id" \ - '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $para_id } } } }') + '{ "V4": { "parents": 0, "interior": { "X1": [{ "Parachain": $para_id }] } } }') local message=$(jq --null-input \ --argjson hex_encoded_data $hex_encoded_data \ @@ -122,7 +122,7 @@ function send_governance_transact() { --arg require_weight_at_most_proof_size "$require_weight_at_most_proof_size" \ ' { - "V3": [ + "V4": [ { "UnpaidExecution": { "weight_limit": "Unlimited" diff --git a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl index 6e26632fd9f9..b3cafc993e54 100644 --- a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl @@ -6,7 +6,7 @@ Creds: config asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "auto-log reserve-transfer-assets-from-asset-hub-rococo-local 5000000000000" within 120 seconds # check that //Alice received at least 4.8 ROC on Westend AH -asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Rococo" within 600 seconds +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with '{ "accountAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "expectedAssetBalance": 4800000000000, "expectedAssetId": { "parents": 2, "interior": { "X1": [{ "GlobalConsensus": { "ByGenesis": [100,8,222,119,55,197,156,35,136,144,83,58,242,88,150,162,194,6,8,216,179,128,187,1,2,154,203,57,39,129,6,62] } }] }}}' within 600 seconds # relayer //Ferdie is rewarded for delivering messages from Rococo BH bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw,0x00000002,0x6268726F,ThisChain,0" within 300 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl index 5a8d6dabc20e..eacac98982ab 100644 --- a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl @@ -6,7 +6,7 @@ Creds: config asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "auto-log reserve-transfer-assets-from-asset-hub-westend-local 5000000000000" within 120 seconds # check that //Alice received at least 4.8 WND on Rococo AH -asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Westend" within 600 seconds +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with '{ "accountAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "expectedAssetBalance": 4800000000000, "expectedAssetId": { "parents": 2, "interior": { "X1": [{ "GlobalConsensus": { "ByGenesis": [225,67,242,56,3,172,80,232,246,248,230,38,149,209,206,158,78,29,104,170,54,193,205,44,253,21,52,2,19,243,66,62] } }] }}}' within 600 seconds # relayer //Eve is rewarded for delivering messages from Westend BH bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL,0x00000002,0x62687764,ThisChain,0" within 300 seconds diff --git a/cumulus/README.md b/cumulus/README.md index 7e145ad7b4ab..400f9481c3fb 100644 --- a/cumulus/README.md +++ b/cumulus/README.md @@ -4,7 +4,7 @@ This repository contains both the Cumulus SDK and also specific chains implemented on top of this SDK. -If you only want to run a **Polkadot Parachain Node**, check out our [container section](./docs/contributor/container.md). +If you only want to run a **Polkadot Parachain Node**, check out our [container section](../docs/contributor/container.md). ## Cumulus SDK @@ -34,7 +34,7 @@ A Polkadot [collator](https://wiki.polkadot.network/docs/en/learn-collator) for `polkadot-parachain` binary (previously called `polkadot-collator`). You may run `polkadot-parachain` locally after building it or using one of the container option described -[here](./docs/contributor/container.md). +[here](../docs/contributor/container.md). ### Relay Chain Interaction To operate a parachain node, a connection to the corresponding relay chain is necessary. This can be achieved in one of @@ -60,7 +60,7 @@ polkadot-parachain \ ``` #### External Relay Chain Node -An external relay chain node is connected via WebsSocket RPC by using the `--relay-chain-rpc-urls` command line +An external relay chain node is connected via WebSocket RPC by using the `--relay-chain-rpc-urls` command line argument. This option accepts one or more space-separated WebSocket URLs to a full relay chain node. By default, only the first URL will be used, with the rest as a backup in case the connection to the first node is lost. diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml index 9be92960ad77..d7af29a6bcb2 100644 --- a/cumulus/bin/pov-validator/Cargo.toml +++ b/cumulus/bin/pov-validator/Cargo.toml @@ -9,18 +9,18 @@ homepage.workspace = true description = "A tool for validating PoVs locally" [dependencies] -codec.workspace = true +anyhow.workspace = true clap = { workspace = true, features = ["derive"] } -sc-executor.workspace = true -sp-io.workspace = true -sp-core.workspace = true -sp-maybe-compressed-blob.workspace = true +codec.workspace = true polkadot-node-primitives.workspace = true polkadot-parachain-primitives.workspace = true polkadot-primitives.workspace = true -anyhow.workspace = true -tracing.workspace = true +sc-executor.workspace = true +sp-core.workspace = true +sp-io.workspace = true +sp-maybe-compressed-blob.workspace = true tracing-subscriber.workspace = true +tracing.workspace = true [lints] workspace = true diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 9b6f6b73960b..bdc0236e368f 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Parachain node CLI utilities." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -15,10 +17,10 @@ codec = { workspace = true, default-features = true } url = { workspace = true } # Substrate +sc-chain-spec = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } -sc-chain-spec = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 6ebde0c2c653..ff591c2d6e3a 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -5,20 +5,22 @@ authors.workspace = true edition.workspace = true description = "Common node-side functionality and glue code to collate parachain blocks." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -parking_lot = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true, default-features = true } futures = { workspace = true } +parking_lot = { workspace = true, default-features = true } tracing = { workspace = true, default-features = true } # Substrate sc-client-api = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } @@ -46,5 +48,5 @@ polkadot-node-subsystem-test-helpers = { workspace = true } # Cumulus cumulus-test-client = { workspace = true } -cumulus-test-runtime = { workspace = true } cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } +cumulus-test-runtime = { workspace = true } diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 0bb2de6bb9b8..702230938645 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,18 +16,19 @@ async-trait = { workspace = true } codec = { features = ["derive"], workspace = true, default-features = true } futures = { workspace = true } parking_lot = { workspace = true } -tracing = { workspace = true, default-features = true } schnellru = { workspace = true } tokio = { workspace = true, features = ["macros"] } +tracing = { workspace = true, default-features = true } # Substrate +prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-consensus-aura = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } sc-consensus-slots = { workspace = true, default-features = true } -sc-utils = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } @@ -36,25 +39,25 @@ sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } # Cumulus +cumulus-client-collator = { workspace = true, default-features = true } cumulus-client-consensus-common = { workspace = true, default-features = true } -cumulus-relay-chain-interface = { workspace = true, default-features = true } cumulus-client-consensus-proposer = { workspace = true, default-features = true } cumulus-client-parachain-inherent = { workspace = true, default-features = true } cumulus-primitives-aura = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } -cumulus-client-collator = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { workspace = true, default-features = true } 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-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } [features] # Allows collator to use full PoV size for block building diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 8ac43fbd116e..2dbcf5eb58e9 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -36,17 +36,15 @@ use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterfa use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::{ - ClaimQueueOffset, CollectCollationInfo, PersistedValidationData, DEFAULT_CLAIM_QUEUE_OFFSET, -}; +use cumulus_primitives_core::{ClaimQueueOffset, CollectCollationInfo, PersistedValidationData}; use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_node_primitives::{PoV, SubmitCollationParams}; use polkadot_node_subsystem::messages::CollationGenerationMessage; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::{ - BlockNumber as RBlockNumber, CollatorPair, Hash as RHash, HeadData, Id as ParaId, - OccupiedCoreAssumption, + vstaging::DEFAULT_CLAIM_QUEUE_OFFSET, BlockNumber as RBlockNumber, CollatorPair, Hash as RHash, + HeadData, Id as ParaId, OccupiedCoreAssumption, }; use futures::prelude::*; diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs index e75b52aeebd3..41751f1db530 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs @@ -20,35 +20,35 @@ use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterfa use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::{ - GetCoreSelectorApi, PersistedValidationData, DEFAULT_CLAIM_QUEUE_OFFSET, -}; +use cumulus_primitives_core::{GetCoreSelectorApi, PersistedValidationData}; use cumulus_relay_chain_interface::RelayChainInterface; -use polkadot_primitives::{ - vstaging::{ClaimQueueOffset, CoreSelector}, - BlockId, CoreIndex, Hash as RelayHash, Header as RelayHeader, Id as ParaId, - OccupiedCoreAssumption, -}; +use polkadot_primitives::Id as ParaId; use futures::prelude::*; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf, UsageProvider}; use sc_consensus::BlockImport; -use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; use sp_consensus_aura::{AuraApi, Slot}; -use sp_core::{crypto::Pair, U256}; +use sp_core::crypto::Pair; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member, One}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member}; use sp_timestamp::Timestamp; -use std::{collections::BTreeSet, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use super::CollatorMessage; use crate::{ collator::{self as collator_util}, - collators::{check_validation_code_or_log, cores_scheduled_for_para}, + collators::{ + check_validation_code_or_log, + slot_based::{ + core_selector, + relay_chain_data_cache::{RelayChainData, RelayChainDataCache}, + }, + }, LOG_TARGET, }; @@ -220,7 +220,7 @@ where collator_util::Collator::::new(params) }; - let mut relay_chain_fetcher = RelayChainCachingFetcher::new(relay_client.clone(), para_id); + let mut relay_chain_data_cache = RelayChainDataCache::new(relay_client.clone(), para_id); loop { // We wait here until the next slot arrives. @@ -244,7 +244,7 @@ where // Retrieve the core selector. let (core_selector, claim_queue_offset) = - match core_selector(&*para_client, &parent).await { + match core_selector(&*para_client, parent.hash, *parent.header.number()) { Ok(core_selector) => core_selector, Err(err) => { tracing::trace!( @@ -261,7 +261,7 @@ where max_pov_size, scheduled_cores, claimed_cores, - }) = relay_chain_fetcher + }) = relay_chain_data_cache .get_mut_relay_chain_data(relay_parent, claim_queue_offset) .await else { @@ -421,119 +421,3 @@ where } } } - -/// Contains relay chain data necessary for parachain block building. -#[derive(Clone)] -struct RelayChainData { - /// Current relay chain parent header. - pub relay_parent_header: RelayHeader, - /// The cores on which the para is scheduled at the configured claim queue offset. - pub scheduled_cores: Vec, - /// Maximum configured PoV size on the relay chain. - pub max_pov_size: u32, - /// The claimed cores at a relay parent. - pub claimed_cores: BTreeSet, -} - -/// Simple helper to fetch relay chain data and cache it based on the current relay chain best block -/// hash. -struct RelayChainCachingFetcher { - relay_client: RI, - para_id: ParaId, - last_data: Option<(RelayHash, RelayChainData)>, -} - -impl RelayChainCachingFetcher -where - RI: RelayChainInterface + Clone + 'static, -{ - pub fn new(relay_client: RI, para_id: ParaId) -> Self { - Self { relay_client, para_id, last_data: None } - } - - /// Fetch required [`RelayChainData`] from the relay chain. - /// If this data has been fetched in the past for the incoming hash, it will reuse - /// cached data. - pub async fn get_mut_relay_chain_data( - &mut self, - relay_parent: RelayHash, - claim_queue_offset: ClaimQueueOffset, - ) -> Result<&mut RelayChainData, ()> { - match &self.last_data { - Some((last_seen_hash, _)) if *last_seen_hash == relay_parent => { - tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Using cached data for relay parent."); - Ok(&mut self.last_data.as_mut().expect("last_data is Some").1) - }, - _ => { - tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Relay chain best block changed, fetching new data from relay chain."); - let data = self.update_for_relay_parent(relay_parent, claim_queue_offset).await?; - self.last_data = Some((relay_parent, data)); - Ok(&mut self.last_data.as_mut().expect("last_data was just set above").1) - }, - } - } - - /// Fetch fresh data from the relay chain for the given relay parent hash. - async fn update_for_relay_parent( - &self, - relay_parent: RelayHash, - claim_queue_offset: ClaimQueueOffset, - ) -> Result { - let scheduled_cores = cores_scheduled_for_para( - relay_parent, - self.para_id, - &self.relay_client, - claim_queue_offset, - ) - .await; - - let Ok(Some(relay_parent_header)) = - self.relay_client.header(BlockId::Hash(relay_parent)).await - else { - tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block header."); - return Err(()) - }; - - let max_pov_size = match self - .relay_client - .persisted_validation_data(relay_parent, self.para_id, OccupiedCoreAssumption::Included) - .await - { - Ok(None) => return Err(()), - Ok(Some(pvd)) => pvd.max_pov_size, - Err(err) => { - tracing::error!(target: crate::LOG_TARGET, ?err, "Failed to gather information from relay-client"); - return Err(()) - }, - }; - - Ok(RelayChainData { - relay_parent_header, - scheduled_cores, - max_pov_size, - claimed_cores: BTreeSet::new(), - }) - } -} - -async fn core_selector( - para_client: &Client, - parent: &consensus_common::PotentialParent, -) -> Result<(CoreSelector, ClaimQueueOffset), sp_api::ApiError> -where - Client: ProvideRuntimeApi + Send + Sync, - Client::Api: GetCoreSelectorApi, -{ - let block_hash = parent.hash; - let runtime_api = para_client.runtime_api(); - - if runtime_api.has_api::>(block_hash)? { - Ok(runtime_api.core_selector(block_hash)?) - } else { - let next_block_number: U256 = (*parent.header.number() + One::one()).into(); - - // If the runtime API does not support the core selector API, fallback to some default - // values. - Ok((CoreSelector(next_block_number.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET))) - } -} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/block_import.rs b/cumulus/client/consensus/aura/src/collators/slot_based/block_import.rs new file mode 100644 index 000000000000..9c53da6a6b7d --- /dev/null +++ b/cumulus/client/consensus/aura/src/collators/slot_based/block_import.rs @@ -0,0 +1,144 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +use futures::{stream::FusedStream, StreamExt}; +use sc_consensus::{BlockImport, StateAction}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use sp_api::{ApiExt, CallApiAt, CallContext, Core, ProvideRuntimeApi, StorageProof}; +use sp_runtime::traits::{Block as BlockT, Header as _}; +use sp_trie::proof_size_extension::ProofSizeExt; +use std::sync::Arc; + +/// Handle for receiving the block and the storage proof from the [`SlotBasedBlockImport`]. +/// +/// This handle should be passed to [`Params`](super::Params) or can also be dropped if the node is +/// not running as collator. +pub struct SlotBasedBlockImportHandle { + receiver: TracingUnboundedReceiver<(Block, StorageProof)>, +} + +impl SlotBasedBlockImportHandle { + /// Returns the next item. + /// + /// The future will never return when the internal channel is closed. + pub async fn next(&mut self) -> (Block, StorageProof) { + loop { + if self.receiver.is_terminated() { + futures::pending!() + } else if let Some(res) = self.receiver.next().await { + return res + } + } + } +} + +/// Special block import for the slot based collator. +pub struct SlotBasedBlockImport { + inner: BI, + client: Arc, + sender: TracingUnboundedSender<(Block, StorageProof)>, +} + +impl SlotBasedBlockImport { + /// Create a new instance. + /// + /// The returned [`SlotBasedBlockImportHandle`] needs to be passed to the + /// [`Params`](super::Params), so that this block import instance can communicate with the + /// collation task. If the node is not running as a collator, just dropping the handle is fine. + pub fn new(inner: BI, client: Arc) -> (Self, SlotBasedBlockImportHandle) { + let (sender, receiver) = tracing_unbounded("SlotBasedBlockImportChannel", 1000); + + (Self { sender, client, inner }, SlotBasedBlockImportHandle { receiver }) + } +} + +impl Clone for SlotBasedBlockImport { + fn clone(&self) -> Self { + Self { inner: self.inner.clone(), client: self.client.clone(), sender: self.sender.clone() } + } +} + +#[async_trait::async_trait] +impl BlockImport for SlotBasedBlockImport +where + Block: BlockT, + BI: BlockImport + Send + Sync, + BI::Error: Into, + Client: ProvideRuntimeApi + CallApiAt + Send + Sync, + Client::StateBackend: Send, + Client::Api: Core, +{ + type Error = sp_consensus::Error; + + async fn check_block( + &self, + block: sc_consensus::BlockCheckParams, + ) -> Result { + self.inner.check_block(block).await.map_err(Into::into) + } + + async fn import_block( + &self, + mut params: sc_consensus::BlockImportParams, + ) -> Result { + // If the channel exists and it is required to execute the block, we will execute the block + // here. This is done to collect the storage proof and to prevent re-execution, we push + // downwards the state changes. `StateAction::ApplyChanges` is ignored, because it either + // means that the node produced the block itself or the block was imported via state sync. + if !self.sender.is_closed() && !matches!(params.state_action, StateAction::ApplyChanges(_)) + { + let mut runtime_api = self.client.runtime_api(); + + runtime_api.set_call_context(CallContext::Onchain); + + runtime_api.record_proof(); + let recorder = runtime_api + .proof_recorder() + .expect("Proof recording is enabled in the line above; qed."); + runtime_api.register_extension(ProofSizeExt::new(recorder)); + + let parent_hash = *params.header.parent_hash(); + + let block = Block::new(params.header.clone(), params.body.clone().unwrap_or_default()); + + runtime_api + .execute_block(parent_hash, block.clone()) + .map_err(|e| Box::new(e) as Box<_>)?; + + let storage_proof = + runtime_api.extract_proof().expect("Proof recording was enabled above; qed"); + + let state = self.client.state_at(parent_hash).map_err(|e| Box::new(e) as Box<_>)?; + let gen_storage_changes = runtime_api + .into_storage_changes(&state, parent_hash) + .map_err(sp_consensus::Error::ChainLookup)?; + + if params.header.state_root() != &gen_storage_changes.transaction_storage_root { + return Err(sp_consensus::Error::Other(Box::new( + sp_blockchain::Error::InvalidStateRoot, + ))) + } + + params.state_action = StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes( + gen_storage_changes, + )); + + let _ = self.sender.unbounded_send((block, storage_proof)); + } + + self.inner.import_block(params).await.map_err(Into::into) + } +} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs index 5b8151f6302c..abaeb8319a40 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/collation_task.rs @@ -47,6 +47,8 @@ pub struct Params { pub collator_service: CS, /// Receiver channel for communication with the block builder task. pub collator_receiver: TracingUnboundedReceiver>, + /// The handle from the special slot based block import. + pub block_import_handle: super::SlotBasedBlockImportHandle, } /// Asynchronously executes the collation task for a parachain. @@ -55,28 +57,49 @@ pub struct Params { /// collations to the relay chain. It listens for new best relay chain block notifications and /// handles collator messages. If our parachain is scheduled on a core and we have a candidate, /// the task will build a collation and send it to the relay chain. -pub async fn run_collation_task(mut params: Params) -where +pub async fn run_collation_task( + Params { + relay_client, + collator_key, + para_id, + reinitialize, + collator_service, + mut collator_receiver, + mut block_import_handle, + }: Params, +) where Block: BlockT, CS: CollatorServiceInterface + Send + Sync + 'static, RClient: RelayChainInterface + Clone + 'static, { - let Ok(mut overseer_handle) = params.relay_client.overseer_handle() else { + let Ok(mut overseer_handle) = relay_client.overseer_handle() else { tracing::error!(target: LOG_TARGET, "Failed to get overseer handle."); return }; cumulus_client_collator::initialize_collator_subsystems( &mut overseer_handle, - params.collator_key, - params.para_id, - params.reinitialize, + collator_key, + para_id, + reinitialize, ) .await; - let collator_service = params.collator_service; - while let Some(collator_message) = params.collator_receiver.next().await { - handle_collation_message(collator_message, &collator_service, &mut overseer_handle).await; + loop { + futures::select! { + collator_message = collator_receiver.next() => { + let Some(message) = collator_message else { + return; + }; + + handle_collation_message(message, &collator_service, &mut overseer_handle).await; + }, + block_import_msg = block_import_handle.next().fuse() => { + // TODO: Implement me. + // Issue: https://github.com/paritytech/polkadot-sdk/issues/6495 + let _ = block_import_msg; + } + } } } diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs b/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs index 7453d3c89d08..ab78b31fbd80 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs @@ -28,40 +28,42 @@ //! during the relay chain block. After the block is built, the block builder task sends it to //! the collation task which compresses it and submits it to the collation-generation subsystem. +use self::{block_builder_task::run_block_builder, collation_task::run_collation_task}; use codec::Codec; use consensus_common::ParachainCandidate; use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface; use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::GetCoreSelectorApi; +use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector, GetCoreSelectorApi}; use cumulus_relay_chain_interface::RelayChainInterface; +use futures::FutureExt; use polkadot_primitives::{ - CollatorPair, CoreIndex, Hash as RelayHash, Id as ParaId, ValidationCodeHash, + vstaging::DEFAULT_CLAIM_QUEUE_OFFSET, CollatorPair, CoreIndex, Hash as RelayHash, Id as ParaId, + ValidationCodeHash, }; - use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf, UsageProvider}; use sc_consensus::BlockImport; use sc_utils::mpsc::tracing_unbounded; - -use sp_api::ProvideRuntimeApi; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; use sp_consensus_aura::AuraApi; -use sp_core::crypto::Pair; +use sp_core::{crypto::Pair, traits::SpawnNamed, U256}; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::traits::{Block as BlockT, Member}; - +use sp_runtime::traits::{Block as BlockT, Member, NumberFor, One}; use std::{sync::Arc, time::Duration}; -use self::{block_builder_task::run_block_builder, collation_task::run_collation_task}; +pub use block_import::{SlotBasedBlockImport, SlotBasedBlockImportHandle}; mod block_builder_task; +mod block_import; mod collation_task; +mod relay_chain_data_cache; /// Parameters for [`run`]. -pub struct Params { +pub struct Params { /// Inherent data providers. Only non-consensus inherent data should be provided, i.e. /// the timestamp, slot, and paras inherents should be omitted, as they are set by this /// collator. @@ -93,13 +95,33 @@ pub struct Params { /// Drift slots by a fixed duration. This can be used to create more preferrable authoring /// timings. pub slot_drift: Duration, + /// The handle returned by [`SlotBasedBlockImport`]. + pub block_import_handle: SlotBasedBlockImportHandle, + /// Spawner for spawning futures. + pub spawner: Spawner, } /// Run aura-based block building and collation task. -pub fn run( - params: Params, -) -> (impl futures::Future, impl futures::Future) -where +pub fn run( + Params { + create_inherent_data_providers, + block_import, + para_client, + para_backend, + relay_client, + code_hash_provider, + keystore, + collator_key, + para_id, + proposer, + collator_service, + authoring_duration, + reinitialize, + slot_drift, + block_import_handle, + spawner, + }: Params, +) where Block: BlockT, Client: ProvideRuntimeApi + BlockOf @@ -123,39 +145,50 @@ where P: Pair + 'static, P::Public: AppPublic + Member + Codec, P::Signature: TryFrom> + Member + Codec, + Spawner: SpawnNamed, { let (tx, rx) = tracing_unbounded("mpsc_builder_to_collator", 100); let collator_task_params = collation_task::Params { - relay_client: params.relay_client.clone(), - collator_key: params.collator_key, - para_id: params.para_id, - reinitialize: params.reinitialize, - collator_service: params.collator_service.clone(), + relay_client: relay_client.clone(), + collator_key, + para_id, + reinitialize, + collator_service: collator_service.clone(), collator_receiver: rx, + block_import_handle, }; let collation_task_fut = run_collation_task::(collator_task_params); let block_builder_params = block_builder_task::BuilderTaskParams { - create_inherent_data_providers: params.create_inherent_data_providers, - block_import: params.block_import, - para_client: params.para_client, - para_backend: params.para_backend, - relay_client: params.relay_client, - code_hash_provider: params.code_hash_provider, - keystore: params.keystore, - para_id: params.para_id, - proposer: params.proposer, - collator_service: params.collator_service, - authoring_duration: params.authoring_duration, + create_inherent_data_providers, + block_import, + para_client, + para_backend, + relay_client, + code_hash_provider, + keystore, + para_id, + proposer, + collator_service, + authoring_duration, collator_sender: tx, - slot_drift: params.slot_drift, + slot_drift, }; let block_builder_fut = run_block_builder::(block_builder_params); - (collation_task_fut, block_builder_fut) + spawner.spawn_blocking( + "slot-based-block-builder", + Some("slot-based-collator"), + block_builder_fut.boxed(), + ); + spawner.spawn_blocking( + "slot-based-collation", + Some("slot-based-collator"), + collation_task_fut.boxed(), + ); } /// Message to be sent from the block builder to the collation task. @@ -173,3 +206,26 @@ struct CollatorMessage { /// Core index that this block should be submitted on pub core_index: CoreIndex, } + +/// Fetch the `CoreSelector` and `ClaimQueueOffset` for `parent_hash`. +fn core_selector( + para_client: &Client, + parent_hash: Block::Hash, + parent_number: NumberFor, +) -> Result<(CoreSelector, ClaimQueueOffset), sp_api::ApiError> +where + Client: ProvideRuntimeApi + Send + Sync, + Client::Api: GetCoreSelectorApi, +{ + let runtime_api = para_client.runtime_api(); + + if runtime_api.has_api::>(parent_hash)? { + Ok(runtime_api.core_selector(parent_hash)?) + } else { + let next_block_number: U256 = (parent_number + One::one()).into(); + + // If the runtime API does not support the core selector API, fallback to some default + // values. + Ok((CoreSelector(next_block_number.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET))) + } +} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/relay_chain_data_cache.rs b/cumulus/client/consensus/aura/src/collators/slot_based/relay_chain_data_cache.rs new file mode 100644 index 000000000000..be30ec2f747d --- /dev/null +++ b/cumulus/client/consensus/aura/src/collators/slot_based/relay_chain_data_cache.rs @@ -0,0 +1,127 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +//! Utility for caching [`RelayChainData`] for different relay blocks. + +use crate::collators::cores_scheduled_for_para; +use cumulus_primitives_core::ClaimQueueOffset; +use cumulus_relay_chain_interface::RelayChainInterface; +use polkadot_primitives::{ + CoreIndex, Hash as RelayHash, Header as RelayHeader, Id as ParaId, OccupiedCoreAssumption, +}; +use sp_runtime::generic::BlockId; +use std::collections::BTreeSet; + +/// Contains relay chain data necessary for parachain block building. +#[derive(Clone)] +pub struct RelayChainData { + /// Current relay chain parent header. + pub relay_parent_header: RelayHeader, + /// The cores on which the para is scheduled at the configured claim queue offset. + pub scheduled_cores: Vec, + /// Maximum configured PoV size on the relay chain. + pub max_pov_size: u32, + /// The claimed cores at a relay parent. + pub claimed_cores: BTreeSet, +} + +/// Simple helper to fetch relay chain data and cache it based on the current relay chain best block +/// hash. +pub struct RelayChainDataCache { + relay_client: RI, + para_id: ParaId, + cached_data: schnellru::LruMap, +} + +impl RelayChainDataCache +where + RI: RelayChainInterface + Clone + 'static, +{ + pub fn new(relay_client: RI, para_id: ParaId) -> Self { + Self { + relay_client, + para_id, + // 50 cached relay chain blocks should be more than enough. + cached_data: schnellru::LruMap::new(schnellru::ByLength::new(50)), + } + } + + /// Fetch required [`RelayChainData`] from the relay chain. + /// If this data has been fetched in the past for the incoming hash, it will reuse + /// cached data. + pub async fn get_mut_relay_chain_data( + &mut self, + relay_parent: RelayHash, + claim_queue_offset: ClaimQueueOffset, + ) -> Result<&mut RelayChainData, ()> { + let insert_data = if self.cached_data.peek(&relay_parent).is_some() { + tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Using cached data for relay parent."); + None + } else { + tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Relay chain best block changed, fetching new data from relay chain."); + Some(self.update_for_relay_parent(relay_parent, claim_queue_offset).await?) + }; + + Ok(self + .cached_data + .get_or_insert(relay_parent, || { + insert_data.expect("`insert_data` exists if not cached yet; qed") + }) + .expect("There is space for at least one element; qed")) + } + + /// Fetch fresh data from the relay chain for the given relay parent hash. + async fn update_for_relay_parent( + &self, + relay_parent: RelayHash, + claim_queue_offset: ClaimQueueOffset, + ) -> Result { + let scheduled_cores = cores_scheduled_for_para( + relay_parent, + self.para_id, + &self.relay_client, + claim_queue_offset, + ) + .await; + + let Ok(Some(relay_parent_header)) = + self.relay_client.header(BlockId::Hash(relay_parent)).await + else { + tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block header."); + return Err(()) + }; + + let max_pov_size = match self + .relay_client + .persisted_validation_data(relay_parent, self.para_id, OccupiedCoreAssumption::Included) + .await + { + Ok(None) => return Err(()), + Ok(Some(pvd)) => pvd.max_pov_size, + Err(err) => { + tracing::error!(target: crate::LOG_TARGET, ?err, "Failed to gather information from relay-client"); + return Err(()) + }, + }; + + Ok(RelayChainData { + relay_parent_header, + scheduled_cores, + max_pov_size, + claimed_cores: BTreeSet::new(), + }) + } +} diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 4bc2f1d1e600..5bc5160601e7 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -18,6 +20,7 @@ log = { workspace = true, default-features = true } tracing = { workspace = true, default-features = true } # Substrate +prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } @@ -29,15 +32,14 @@ sp-runtime = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } # Polkadot polkadot-primitives = { workspace = true, default-features = true } # Cumulus +cumulus-client-pov-recovery = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } cumulus-relay-chain-interface = { workspace = true, default-features = true } -cumulus-client-pov-recovery = { workspace = true, default-features = true } schnellru = { workspace = true } [dev-dependencies] diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index bb760ae03f4d..e391481bc445 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index f3ee6fc2f7d2..fdc343dc65de 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -16,6 +18,7 @@ parking_lot = { workspace = true, default-features = true } tracing = { workspace = true, default-features = true } # Substrate +prometheus-endpoint = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } @@ -24,7 +27,6 @@ sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } # Cumulus cumulus-client-consensus-common = { workspace = true, default-features = true } diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index bc67678eedeb..11025f8f62e6 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true description = "Cumulus-specific networking protocol" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -19,28 +21,28 @@ tracing = { workspace = true, default-features = true } # Substrate sc-client-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } # Polkadot polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } # Cumulus cumulus-relay-chain-interface = { workspace = true, default-features = true } [dev-dependencies] portpicker = { workspace = true } +rstest = { workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } url = { workspace = true } -rstest = { workspace = true } # Substrate sc-cli = { workspace = true, default-features = true } diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index 009f922008b1..cccb710bf18f 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -321,8 +321,8 @@ impl RelayChainInterface for DummyRelayChainInterface { .to_vec(); Ok(RuntimeVersion { - spec_name: sp_version::create_runtime_str!("test"), - impl_name: sp_version::create_runtime_str!("test"), + spec_name: Cow::Borrowed("test"), + impl_name: Cow::Borrowed("test"), authoring_version: 1, spec_version: 1, impl_version: 0, diff --git a/cumulus/client/parachain-inherent/Cargo.toml b/cumulus/client/parachain-inherent/Cargo.toml index 0d82cf648743..4f53e2bc1bc2 100644 --- a/cumulus/client/parachain-inherent/Cargo.toml +++ b/cumulus/client/parachain-inherent/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Inherent that needs to be present in every parachain block. Contains messages and a relay chain storage-proof." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [dependencies] async-trait = { workspace = true } diff --git a/cumulus/client/parachain-inherent/src/mock.rs b/cumulus/client/parachain-inherent/src/mock.rs index 950cba2aaa7d..e08aca932564 100644 --- a/cumulus/client/parachain-inherent/src/mock.rs +++ b/cumulus/client/parachain-inherent/src/mock.rs @@ -17,17 +17,17 @@ use crate::{ParachainInherentData, INHERENT_IDENTIFIER}; use codec::Decode; use cumulus_primitives_core::{ - relay_chain, InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData, + relay_chain, relay_chain::UpgradeGoAhead, InboundDownwardMessage, InboundHrmpMessage, ParaId, + PersistedValidationData, }; use cumulus_primitives_parachain_inherent::MessageQueueChain; +use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use sc_client_api::{Backend, StorageProvider}; use sp_crypto_hashing::twox_128; use sp_inherents::{InherentData, InherentDataProvider}; use sp_runtime::traits::Block; use std::collections::BTreeMap; -use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; - /// Relay chain slot duration, in milliseconds. pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; @@ -68,10 +68,12 @@ pub struct MockValidationDataInherentDataProvider { pub xcm_config: MockXcmConfig, /// Inbound downward XCM messages to be injected into the block. pub raw_downward_messages: Vec>, - // Inbound Horizontal messages sorted by channel. + /// Inbound Horizontal messages sorted by channel. pub raw_horizontal_messages: Vec<(ParaId, Vec)>, - // Additional key-value pairs that should be injected. + /// Additional key-value pairs that should be injected. pub additional_key_values: Option, Vec)>>, + /// Whether upgrade go ahead should be set. + pub upgrade_go_ahead: Option, } /// Something that can generate randomness. @@ -176,6 +178,7 @@ impl> InherentDataProvider sproof_builder.current_slot = ((relay_parent_number / RELAY_CHAIN_SLOT_DURATION_MILLIS) as u64).into(); + sproof_builder.upgrade_go_ahead = self.upgrade_go_ahead; // Process the downward messages and set up the correct head let mut downward_messages = Vec::new(); let mut dmq_mqc = MessageQueueChain::new(self.xcm_config.starting_dmq_mqc_head); diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 3127dd26fcaa..7e7da7244a86 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true description = "Parachain PoV recovery" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -19,10 +21,10 @@ tracing = { workspace = true, default-features = true } # Substrate sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-maybe-compressed-blob = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } # Polkadot @@ -32,19 +34,19 @@ polkadot-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } # Cumulus +async-trait = { workspace = true } cumulus-primitives-core = { workspace = true, default-features = true } cumulus-relay-chain-interface = { workspace = true, default-features = true } -async-trait = { workspace = true } [dev-dependencies] -rstest = { workspace = true } -tokio = { features = ["macros"], workspace = true, default-features = true } -portpicker = { workspace = true } -sp-blockchain = { workspace = true, default-features = true } +assert_matches = { workspace = true } cumulus-test-client = { workspace = true } +portpicker = { workspace = true } +rstest = { workspace = true } sc-utils = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -assert_matches = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } # Cumulus cumulus-test-service = { workspace = true } diff --git a/cumulus/client/pov-recovery/src/tests.rs b/cumulus/client/pov-recovery/src/tests.rs index d528a92a52a8..91b462e06bf8 100644 --- a/cumulus/client/pov-recovery/src/tests.rs +++ b/cumulus/client/pov-recovery/src/tests.rs @@ -322,8 +322,8 @@ impl RelayChainInterface for Relaychain { .to_vec(); Ok(RuntimeVersion { - spec_name: sp_version::create_runtime_str!("test"), - impl_name: sp_version::create_runtime_str!("test"), + spec_name: Cow::Borrowed("test"), + impl_name: Cow::Borrowed("test"), authoring_version: 1, spec_version: 1, impl_version: 0, diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 6f1b74191be7..2a590bbca562 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" edition.workspace = true description = "Implementation of the RelayChainInterface trait for Polkadot full-nodes." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,9 +19,9 @@ futures-timer = { workspace = true } # Substrate sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } -sc-sysinfo = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } @@ -40,9 +42,9 @@ cumulus-relay-chain-interface = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } # Polkadot +metered = { features = ["futures_channel"], workspace = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-test-client = { workspace = true } -metered = { features = ["futures_channel"], workspace = true } # Cumulus cumulus-test-service = { workspace = true } diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index a496fab050dd..659d3b0f5b27 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" edition.workspace = true description = "Common interface for different relay chain datasources." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,14 +16,14 @@ polkadot-overseer = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } sp-version = { workspace = true } -futures = { workspace = true } async-trait = { workspace = true } -thiserror = { workspace = true } -jsonrpsee-core = { workspace = true } codec = { workspace = true, default-features = true } +futures = { workspace = true } +jsonrpsee-core = { workspace = true } +thiserror = { workspace = true } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 95ecadc8bd06..5b1e30cea9ba 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -5,43 +5,45 @@ version = "0.7.0" edition.workspace = true description = "Minimal node implementation to be used in tandem with RPC or light-client mode." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] # polkadot deps -polkadot-primitives = { workspace = true, default-features = true } polkadot-core-primitives = { workspace = true, default-features = true } -polkadot-overseer = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-node-network-protocol = { 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-network-bridge = { workspace = true, default-features = true } polkadot-service = { workspace = true, default-features = true } # substrate deps +prometheus-endpoint = { workspace = true, default-features = true } sc-authority-discovery = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-consensus-babe = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } tokio = { features = ["macros"], workspace = true, default-features = true } # cumulus deps +cumulus-primitives-core = { workspace = true, default-features = true } cumulus-relay-chain-interface = { workspace = true, default-features = true } cumulus-relay-chain-rpc-interface = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } array-bytes = { workspace = true, default-features = true } -tracing = { workspace = true, default-features = true } async-trait = { workspace = true } futures = { workspace = true } +tracing = { workspace = true, default-features = true } diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index a3d858ea40c9..f70a73a5d5ce 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -224,7 +224,7 @@ async fn new_minimal_relay_chain( + let (network, sync_service) = build_collator_network::( &config, net_config, task_manager.spawn_handle(), @@ -262,8 +262,6 @@ async fn new_minimal_relay_chain>( genesis_hash: Hash, best_header: Header, notification_metrics: NotificationMetrics, -) -> Result< - (Arc, NetworkStarter, Arc), - Error, -> { +) -> Result<(Arc, Arc), Error> { let protocol_id = config.protocol_id(); let (block_announce_config, _notification_service) = get_block_announce_proto_config::( protocol_id.clone(), @@ -85,8 +82,6 @@ pub(crate) fn build_collator_network>( let network_worker = Network::new(network_params)?; let network_service = network_worker.network_service(); - let (network_start_tx, network_start_rx) = futures::channel::oneshot::channel(); - // The network worker is responsible for gathering all network messages and processing // them. This is quite a heavy task, and at the time of the writing of this comment it // frequently happens that this future takes several seconds or in some situations @@ -94,22 +89,9 @@ pub(crate) fn build_collator_network>( // issue, and ideally we would like to fix the network future to take as little time as // possible, but we also take the extra harm-prevention measure to execute the networking // future using `spawn_blocking`. - spawn_handle.spawn_blocking("network-worker", Some("networking"), async move { - if network_start_rx.await.is_err() { - tracing::warn!( - "The NetworkStart returned as part of `build_network` has been silently dropped" - ); - // This `return` might seem unnecessary, but we don't want to make it look like - // everything is working as normal even though the user is clearly misusing the API. - return - } - - network_worker.run().await; - }); - - let network_starter = NetworkStarter::new(network_start_tx); + spawn_handle.spawn_blocking("network-worker", Some("networking"), network_worker.run()); - Ok((network_service, network_starter, Arc::new(SyncOracle {}))) + Ok((network_service, Arc::new(SyncOracle {}))) } fn adjust_network_config_light_in_peers(config: &mut NetworkConfiguration) { diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index fb4cb4ceed4e..50b438e34237 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -5,6 +5,8 @@ version = "0.7.0" edition.workspace = true description = "Implementation of the RelayChainInterface trait that connects to a remote RPC-node." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -18,36 +20,36 @@ polkadot-overseer = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } cumulus-relay-chain-interface = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-consensus-babe = { workspace = true, default-features = true } sp-authority-discovery = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } sp-storage = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sc-rpc-api = { workspace = true, default-features = true } -sc-service = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } tokio = { features = ["sync"], workspace = true, default-features = true } tokio-util = { features = ["compat"], workspace = true } +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +either = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } -codec = { workspace = true, default-features = true } jsonrpsee = { features = ["ws-client"], workspace = true } -tracing = { workspace = true, default-features = true } -async-trait = { workspace = true } -url = { workspace = true } -serde_json = { workspace = true, default-features = true } -serde = { workspace = true, default-features = true } +pin-project = { workspace = true } +prometheus = { workspace = true } +rand = { workspace = true, default-features = true } schnellru = { workspace = true } +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } smoldot = { default_features = false, features = ["std"], workspace = true } smoldot-light = { default_features = false, features = ["std"], workspace = true } -either = { workspace = true, default-features = true } thiserror = { workspace = true } -rand = { workspace = true, default-features = true } -pin-project = { workspace = true } -prometheus = { workspace = true } +tracing = { workspace = true, default-features = true } +url = { workspace = true } diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index 8e9e41ca89dc..c88386b985a4 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -5,32 +5,35 @@ authors.workspace = true edition.workspace = true description = "Common functions used to assemble the components of a parachain node." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] futures = { workspace = true } +futures-timer = { workspace = true } # Substrate sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } -sc-transaction-pool = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-network-sync = { workspace = true, default-features = true } +sc-network-transactions = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } sc-sysinfo = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -sc-network-sync = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } -sc-network-transactions = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-transaction-pool = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } # Polkadot polkadot-primitives = { workspace = true, default-features = true } @@ -39,10 +42,10 @@ polkadot-primitives = { workspace = true, default-features = true } cumulus-client-cli = { workspace = true, default-features = true } cumulus-client-collator = { workspace = true, default-features = true } cumulus-client-consensus-common = { workspace = true, default-features = true } -cumulus-client-pov-recovery = { workspace = true, default-features = true } cumulus-client-network = { workspace = true, default-features = true } +cumulus-client-pov-recovery = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } -cumulus-relay-chain-interface = { workspace = true, default-features = true } cumulus-relay-chain-inprocess-interface = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } cumulus-relay-chain-minimal-node = { workspace = true, default-features = true } diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 25b8ee10a931..912109c2ad32 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -40,10 +40,7 @@ use sc_consensus::{ use sc_network::{config::SyncMode, service::traits::NetworkService, NetworkBackend}; use sc_network_sync::SyncingService; use sc_network_transactions::TransactionsHandlerController; -use sc_service::{ - build_polkadot_syncing_strategy, Configuration, NetworkStarter, SpawnTaskHandle, TaskManager, - WarpSyncConfig, -}; +use sc_service::{Configuration, SpawnTaskHandle, TaskManager, WarpSyncConfig}; use sc_telemetry::{log, TelemetryWorkerHandle}; use sc_utils::mpsc::TracingUnboundedSender; use sp_api::ProvideRuntimeApi; @@ -429,7 +426,7 @@ pub struct BuildNetworkParams< pub async fn build_network<'a, Block, Client, RCInterface, IQ, Network>( BuildNetworkParams { parachain_config, - mut net_config, + net_config, client, transaction_pool, para_id, @@ -442,7 +439,6 @@ pub async fn build_network<'a, Block, Client, RCInterface, IQ, Network>( Arc, TracingUnboundedSender>, TransactionsHandlerController, - NetworkStarter, Arc>, )> where @@ -500,16 +496,6 @@ where parachain_config.prometheus_config.as_ref().map(|config| &config.registry), ); - let syncing_strategy = build_polkadot_syncing_strategy( - parachain_config.protocol_id(), - parachain_config.chain_spec.fork_id(), - &mut net_config, - warp_sync_config, - client.clone(), - &spawn_handle, - parachain_config.prometheus_config.as_ref().map(|config| &config.registry), - )?; - sc_service::build_network(sc_service::BuildNetworkParams { config: parachain_config, net_config, @@ -518,7 +504,7 @@ where spawn_handle, import_queue, block_announce_validator_builder: Some(Box::new(move |_| block_announce_validator)), - syncing_strategy, + warp_sync_config, block_relay: None, metrics, }) diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index c08148928b7c..fcda79f1d5c1 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "AURA consensus extension pallet for parachains" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 8d67db3daf8b..651cceebbc6e 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -16,29 +16,29 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { workspace = true } codec = { features = ["derive"], workspace = true } +log = { workspace = true } rand = { features = ["std_rng"], workspace = true } scale-info = { features = ["derive"], workspace = true } -sp-runtime = { workspace = true } -sp-staking = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-session = { workspace = true } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } frame-benchmarking = { optional = true, workspace = true } [dev-dependencies] +pallet-aura = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } -sp-consensus-aura = { workspace = true, default-features = true } -pallet-aura = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 936526290d93..4f5bbc97bfc2 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -21,8 +21,8 @@ scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-runtime = { workspace = true } sp-io = { workspace = true } +sp-runtime = { workspace = true } # Polkadot xcm = { workspace = true } @@ -56,6 +56,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 3cb0394c4b95..6b6bc4fbcefe 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Base pallet for cumulus-based parachains" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -15,8 +17,8 @@ codec = { features = ["derive"], workspace = true } environmental = { workspace = true } impl-trait-for-tuples = { workspace = true } log = { workspace = true } -trie-db = { workspace = true } scale-info = { features = ["derive"], workspace = true } +trie-db = { workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -36,7 +38,6 @@ sp-version = { workspace = true } # Polkadot polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } polkadot-runtime-parachains = { workspace = true } -polkadot-runtime-common = { optional = true, workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } @@ -48,18 +49,18 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } +futures = { workspace = true } hex-literal = { workspace = true, default-features = true } -trie-standardmap = { workspace = true } rand = { workspace = true, default-features = true } -futures = { workspace = true } +trie-standardmap = { workspace = true } # Substrate sc-client-api = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } -sp-consensus-slots = { workspace = true, default-features = true } # Cumulus cumulus-test-client = { workspace = true } @@ -82,7 +83,6 @@ std = [ "log/std", "pallet-message-queue/std", "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", "polkadot-runtime-parachains/std", "scale-info/std", "sp-core/std", @@ -107,17 +107,16 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-message-queue/try-runtime", - "polkadot-runtime-common?/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index da6f0fd03efb..d4485a400cb8 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Proc macros provided by the parachain-system pallet" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -13,10 +15,10 @@ workspace = true proc-macro = true [dependencies] -syn = { workspace = true } +proc-macro-crate = { workspace = true } proc-macro2 = { workspace = true } quote = { workspace = true } -proc-macro-crate = { workspace = true } +syn = { workspace = true } [features] default = ["std"] diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 98989a852b8d..0fa759357f65 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -35,12 +35,12 @@ use core::{cmp, marker::PhantomData}; use cumulus_primitives_core::{ relay_chain::{ self, - vstaging::{ClaimQueueOffset, CoreSelector}, + vstaging::{ClaimQueueOffset, CoreSelector, DEFAULT_CLAIM_QUEUE_OFFSET}, }, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, ListChannelInfos, MessageSendError, OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, - XcmpMessageHandler, XcmpMessageSource, DEFAULT_CLAIM_QUEUE_OFFSET, + XcmpMessageHandler, XcmpMessageSource, }; use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use frame_support::{ @@ -1636,7 +1636,7 @@ impl InspectMessageQueues for Pallet { } #[cfg(feature = "runtime-benchmarks")] -impl polkadot_runtime_common::xcm_sender::EnsureForParachain for Pallet { +impl polkadot_runtime_parachains::EnsureForParachain for Pallet { fn ensure(para_id: ParaId) { if let ChannelStatus::Closed = Self::get_channel_status(para_id) { Self::open_outbound_hrmp_channel_for_benchmarks_or_tests(para_id) diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs index 1f5e4f4dbcf3..5b59be0482e7 100644 --- a/cumulus/pallets/parachain-system/src/mock.rs +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -57,8 +57,8 @@ frame_support::construct_runtime!( parameter_types! { pub Version: RuntimeVersion = RuntimeVersion { - spec_name: sp_version::create_runtime_str!("test"), - impl_name: sp_version::create_runtime_str!("system-test"), + spec_name: alloc::borrow::Cow::Borrowed("test"), + impl_name: alloc::borrow::Cow::Borrowed("system-test"), authoring_version: 1, spec_version: 1, impl_version: 1, diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs index 035541fb17b1..36efd3decf77 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs @@ -85,7 +85,10 @@ impl CacheProvider { } impl TrieCacheProvider for CacheProvider { - type Cache<'a> = TrieCache<'a, H> where H: 'a; + type Cache<'a> + = TrieCache<'a, H> + where + H: 'a; fn as_trie_db_cache(&self, storage_root: ::Out) -> Self::Cache<'_> { TrieCache { diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs index 4a478d047f1b..8dc2f20dd390 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs @@ -115,7 +115,10 @@ impl SizeOnlyRecorderProvider { } impl sp_trie::TrieRecorderProvider for SizeOnlyRecorderProvider { - type Recorder<'a> = SizeOnlyRecorder<'a, H> where H: 'a; + type Recorder<'a> + = SizeOnlyRecorder<'a, H> + where + H: 'a; fn drain_storage_proof(self) -> Option { None diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index 5af94434e0af..6d77e567c9b6 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -sp-runtime = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } pallet-session = { workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index 5fd1939e93a0..2088361bf11a 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Adds functionality to migrate from a Solo to a Parachain" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 35d7a083b061..25938763c956 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -5,6 +5,8 @@ name = "cumulus-pallet-xcm" version = "0.7.0" license = "Apache-2.0" description = "Pallet for stuff specific to parachains' usage of XCM" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -13,10 +15,10 @@ workspace = true codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } xcm = { workspace = true } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 9c7470eda6da..43dfae8927d2 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Pallet to queue outbound and inbound XCMP messages." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,24 +19,24 @@ scale-info = { features = ["derive"], workspace = true } # Substrate frame-support = { workspace = true } frame-system = { workspace = true } -sp-io = { workspace = true } +pallet-message-queue = { workspace = true } sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } -pallet-message-queue = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true } polkadot-runtime-parachains = { workspace = true } xcm = { workspace = true } -xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Cumulus cumulus-primitives-core = { workspace = true } # Optional import for benchmarking -frame-benchmarking = { optional = true, workspace = true } bounded-collections = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } # Bridges bp-xcm-bridge-hub-router = { optional = true, workspace = true } @@ -42,9 +44,9 @@ bp-xcm-bridge-hub-router = { optional = true, workspace = true } [dev-dependencies] # Substrate -sp-core = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } frame-support = { features = ["experimental"], workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } # Cumulus cumulus-pallet-parachain-system = { workspace = true, default-features = true } @@ -85,6 +87,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-parachain-system/try-runtime", diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 6bb7395f6553..91f71558b54a 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -1036,7 +1036,7 @@ impl InspectMessageQueues for Pallet { } ( - VersionedLocation::V4((Parent, Parachain(para_id.into())).into()), + VersionedLocation::from(Location::new(1, Parachain(para_id.into()))), decoded_messages, ) }) diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index 5b02baf2310a..bf042f15ccc0 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -456,7 +456,7 @@ fn send_xcm_nested_works() { XcmpQueue::take_outbound_messages(usize::MAX), vec![( HRMP_PARA_ID.into(), - (XcmpMessageFormat::ConcatenatedVersionedXcm, VersionedXcm::V4(good.clone())) + (XcmpMessageFormat::ConcatenatedVersionedXcm, VersionedXcm::from(good.clone())) .encode(), )] ); @@ -512,7 +512,7 @@ fn hrmp_signals_are_prioritized() { // Without a signal we get the messages in order: let mut expected_msg = XcmpMessageFormat::ConcatenatedVersionedXcm.encode(); for _ in 0..31 { - expected_msg.extend(VersionedXcm::V4(message.clone()).encode()); + expected_msg.extend(VersionedXcm::from(message.clone()).encode()); } hypothetically!({ @@ -539,6 +539,7 @@ fn maybe_double_encoded_versioned_xcm_works() { // pre conditions assert_eq!(VersionedXcm::<()>::V3(Default::default()).encode(), &[3, 0]); assert_eq!(VersionedXcm::<()>::V4(Default::default()).encode(), &[4, 0]); + assert_eq!(VersionedXcm::<()>::V5(Default::default()).encode(), &[5, 0]); } // Now also testing a page instead of just concat messages. @@ -597,7 +598,7 @@ fn take_first_concatenated_xcm_good_recursion_depth_works() { for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { good = Xcm(vec![SetAppendix(good)]); } - let good = VersionedXcm::V4(good); + let good = VersionedXcm::from(good); let page = good.encode(); assert_ok!(XcmpQueue::take_first_concatenated_xcm(&mut &page[..], &mut WeightMeter::new())); @@ -610,7 +611,7 @@ fn take_first_concatenated_xcm_good_bad_depth_errors() { for _ in 0..MAX_XCM_DECODE_DEPTH { bad = Xcm(vec![SetAppendix(bad)]); } - let bad = VersionedXcm::V4(bad); + let bad = VersionedXcm::from(bad); let page = bad.encode(); assert_err!( @@ -872,18 +873,18 @@ fn get_messages_works() { queued_messages, vec![ ( - VersionedLocation::V4(other_destination), + VersionedLocation::from(other_destination), vec![ - VersionedXcm::V4(Xcm(vec![ClearOrigin])), - VersionedXcm::V4(Xcm(vec![ClearOrigin])), + VersionedXcm::from(Xcm(vec![ClearOrigin])), + VersionedXcm::from(Xcm(vec![ClearOrigin])), ], ), ( - VersionedLocation::V4(destination), + VersionedLocation::from(destination), vec![ - VersionedXcm::V4(Xcm(vec![ClearOrigin])), - VersionedXcm::V4(Xcm(vec![ClearOrigin])), - VersionedXcm::V4(Xcm(vec![ClearOrigin])), + VersionedXcm::from(Xcm(vec![ClearOrigin])), + VersionedXcm::from(Xcm(vec![ClearOrigin])), + VersionedXcm::from(Xcm(vec![ClearOrigin])), ], ), ], diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 58b8ac019227..ae4409e4f44f 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -28,7 +28,8 @@ "/dns/mine14.rotko.net/tcp/35524/wss/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30511/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU", "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30513/wss/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU", - "/dns/boot-kusama-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWSwaeFs6FNgpgh54fdoxSDAA4nJNaPE3PAcse2GRrG7b3" + "/dns/boot-kusama-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWSwaeFs6FNgpgh54fdoxSDAA4nJNaPE3PAcse2GRrG7b3", + "/dns/asset-hub-kusama-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWNCg821LyWDVrAJ2mG6ScDeeBFuDPiJtLYc9jCGNCyMoq" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index 3e46501b0078..62efb924c171 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -28,7 +28,8 @@ "/dns/mint14.rotko.net/tcp/35514/wss/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30508/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R", "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30510/wss/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R", - "/dns/boot-polkadot-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWDR9M7CjV1xdjCRbRwkFn1E7sjMaL4oYxGyDWxuLrFc2J" + "/dns/boot-polkadot-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWDR9M7CjV1xdjCRbRwkFn1E7sjMaL4oYxGyDWxuLrFc2J", + "/dns/asset-hub-polkadot-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWJUhizuk3crSvpyKLGycHBtnP93rwjksVueveU6x6k6RY" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-westend.json b/cumulus/parachains/chain-specs/asset-hub-westend.json index 42717974a0b3..67a208c2787b 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -29,7 +29,8 @@ "/dns/wmint14.rotko.net/tcp/34534/ws/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", "/dns/wmint14.rotko.net/tcp/35534/wss/p2p/12D3KooWE4UDXqgtTcMCyUQ8S4uvaT8VMzzTBA6NWmKuYwTacWuN", "/dns/asset-hub-westend.bootnodes.polkadotters.com/tcp/30514/p2p/12D3KooWNFYysCqmojxqjjaTfD2VkWBNngfyUKWjcR4WFixfHNTk", - "/dns/asset-hub-westend.bootnodes.polkadotters.com/tcp/30516/wss/p2p/12D3KooWNFYysCqmojxqjjaTfD2VkWBNngfyUKWjcR4WFixfHNTk" + "/dns/asset-hub-westend.bootnodes.polkadotters.com/tcp/30516/wss/p2p/12D3KooWNFYysCqmojxqjjaTfD2VkWBNngfyUKWjcR4WFixfHNTk", + "/dns/asset-hub-westend-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWDUPyF2q8b6fVFEuwxBbRV3coAy1kzuCPU3D9TRiLnUfE" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 36558b325bbf..83910965584f 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -28,7 +28,8 @@ "/dns/kbr13.rotko.net/tcp/35553/wss/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30520/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV", "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30522/wss/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV", - "/dns/boot-kusama-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWQybw6AFmAvrFfwUQnNxUpS12RovapD6oorh2mAJr4xyd" + "/dns/boot-kusama-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWQybw6AFmAvrFfwUQnNxUpS12RovapD6oorh2mAJr4xyd", + "/dns/bridge-hub-kusama-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWBE1ZhrYqMC3ECFK6qbufS9kgKuF57XpvvZU6LKsPUSnF" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index eb22e09035f3..30585efaf4f1 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -28,7 +28,8 @@ "/dns/bridge-hub-polkadot.bootnodes.polkadotters.com/tcp/30519/wss/p2p/12D3KooWLUNE3LHPDa1WrrZaYT7ArK66CLM1bPv7kKz74UcLnQRB", "/dns/boot-polkadot-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWKf3mBXHjLbwtPqv1BdbQuwbFNcQQYxASS7iQ25264AXH", "/dns/bridge-hub-polkadot.bootnode.amforc.com/tcp/29999/wss/p2p/12D3KooWGT5E56rAHfT5dY1pMLTrpAgV72yfDtD1Y5tPCHaTsifp", - "/dns/bridge-hub-polkadot.bootnode.amforc.com/tcp/30010/p2p/12D3KooWGT5E56rAHfT5dY1pMLTrpAgV72yfDtD1Y5tPCHaTsifp" + "/dns/bridge-hub-polkadot.bootnode.amforc.com/tcp/30010/p2p/12D3KooWGT5E56rAHfT5dY1pMLTrpAgV72yfDtD1Y5tPCHaTsifp", + "/dns/bridge-hub-polkadot-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWSBpo6fYU8CUr4fwA14CKSDUSj5jSgZzQDBNL1B8Dnmaw" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-westend.json b/cumulus/parachains/chain-specs/bridge-hub-westend.json index 40c7c7460c23..05d679a3e23f 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -29,7 +29,8 @@ "/dns/bridge-hub-westend.bootnodes.polkadotters.com/tcp/30523/p2p/12D3KooWPkwgJofp4GeeRwNgXqkp2aFwdLkCWv3qodpBJLwK43Jj", "/dns/bridge-hub-westend.bootnodes.polkadotters.com/tcp/30525/wss/p2p/12D3KooWPkwgJofp4GeeRwNgXqkp2aFwdLkCWv3qodpBJLwK43Jj", "/dns/bridge-hub-westend.bootnode.amforc.com/tcp/29999/wss/p2p/12D3KooWDSWod2gMtHxunXot538oEMw9p42pnPrpRELdsfYyT8R6", - "/dns/bridge-hub-westend.bootnode.amforc.com/tcp/30007/p2p/12D3KooWDSWod2gMtHxunXot538oEMw9p42pnPrpRELdsfYyT8R6" + "/dns/bridge-hub-westend.bootnode.amforc.com/tcp/30007/p2p/12D3KooWDSWod2gMtHxunXot538oEMw9p42pnPrpRELdsfYyT8R6", + "/dns/bridge-hub-westend-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWJEfDZxrEKehoPbW2Mfg6rypttMXCMgMiybmapKqcByc1" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index 5ccccbec9053..458530baf336 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -27,7 +27,8 @@ "/dns/pch16.rotko.net/tcp/35576/wss/p2p/12D3KooWKrm3XmuGzJH17Wcn4HRDGsEjLZGDgN77q3ZhwnnQP7y1", "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30526/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff", "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30528/wss/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff", - "/dns/boot-polkadot-collectives.luckyfriday.io/tcp/443/wss/p2p/12D3KooWCzifnPooTt4kvTnXT7FTKTymVL7xn7DURQLsS2AKpf6w" + "/dns/boot-polkadot-collectives.luckyfriday.io/tcp/443/wss/p2p/12D3KooWCzifnPooTt4kvTnXT7FTKTymVL7xn7DURQLsS2AKpf6w", + "/dns/collectives-polkadot-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWNscpobBzjPEdjbbjjKRYh9j1whYJvagRJwb9UH68zCPC" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-westend.json b/cumulus/parachains/chain-specs/collectives-westend.json index f583eddcef1f..aa0204df1a06 100644 --- a/cumulus/parachains/chain-specs/collectives-westend.json +++ b/cumulus/parachains/chain-specs/collectives-westend.json @@ -29,7 +29,8 @@ "/dns/wch13.rotko.net/tcp/34593/ws/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", "/dns/wch13.rotko.net/tcp/35593/wss/p2p/12D3KooWPG85zhuSRoyptjLkFD4iJFistjiBmc15JgQ96B4fdXYr", "/dns/collectives-westend.bootnodes.polkadotters.com/tcp/30529/p2p/12D3KooWAFkXNSBfyPduZVgfS7pj5NuVpbU8Ee5gHeF8wvos7Yqn", - "/dns/collectives-westend.bootnodes.polkadotters.com/tcp/30531/wss/p2p/12D3KooWAFkXNSBfyPduZVgfS7pj5NuVpbU8Ee5gHeF8wvos7Yqn" + "/dns/collectives-westend.bootnodes.polkadotters.com/tcp/30531/wss/p2p/12D3KooWAFkXNSBfyPduZVgfS7pj5NuVpbU8Ee5gHeF8wvos7Yqn", + "/dns/collectives-westend-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWFH7UZnWESzuRSgrLvNSfALjtpr9PmG7QGyRNCizWEHcd" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/coretime-kusama.json b/cumulus/parachains/chain-specs/coretime-kusama.json index 3e4ffae403bd..8352588a1e4b 100644 --- a/cumulus/parachains/chain-specs/coretime-kusama.json +++ b/cumulus/parachains/chain-specs/coretime-kusama.json @@ -26,7 +26,8 @@ "/dns/coretime-kusama-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWFzW9AgxNfkVNCepVByS7URDCRDAA5p3XzBLVptqZvWoL", "/dns/coretime-kusama-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWFzW9AgxNfkVNCepVByS7URDCRDAA5p3XzBLVptqZvWoL", "/dns/coretime-kusama.bootnode.amforc.com/tcp/29999/wss/p2p/12D3KooWPrgxrrumrANp6Bp2SMEwMQHPHDbPzA1HbcrakZrbFi5P", - "/dns/coretime-kusama.bootnode.amforc.com/tcp/30013/p2p/12D3KooWPrgxrrumrANp6Bp2SMEwMQHPHDbPzA1HbcrakZrbFi5P" + "/dns/coretime-kusama.bootnode.amforc.com/tcp/30013/p2p/12D3KooWPrgxrrumrANp6Bp2SMEwMQHPHDbPzA1HbcrakZrbFi5P", + "/dns/coretime-kusama-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWMPc6jEjzFLRCK7QgbcNh3gvxCzGvDKhU4F66QWf2kZmq" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/coretime-polkadot.json b/cumulus/parachains/chain-specs/coretime-polkadot.json index e4f947d2afc9..7c12ee155b41 100644 --- a/cumulus/parachains/chain-specs/coretime-polkadot.json +++ b/cumulus/parachains/chain-specs/coretime-polkadot.json @@ -12,7 +12,8 @@ "/dns/coretime-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWGpmytHjdthrkKgkXDZyKm9ABtJ2PtGk9NStJDG4pChy9", "/dns/coretime-polkadot-boot-ng.dwellir.com/tcp/30361/p2p/12D3KooWGpmytHjdthrkKgkXDZyKm9ABtJ2PtGk9NStJDG4pChy9", "/dns/coretime-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWFsQphSqvqjVyKcEdR1D7LPcXHqjmy6ASuJrTr5isk9JU", - "/dns/coretime-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWFsQphSqvqjVyKcEdR1D7LPcXHqjmy6ASuJrTr5isk9JU" + "/dns/coretime-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWFsQphSqvqjVyKcEdR1D7LPcXHqjmy6ASuJrTr5isk9JU", + "/dns/coretime-polkadot-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWFG9WQQTf3MX3YQypZjJtoJM5zCQgJcqYdxxTStsbhZGU" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/coretime-westend.json b/cumulus/parachains/chain-specs/coretime-westend.json index 42f67526c29a..de6923bd7669 100644 --- a/cumulus/parachains/chain-specs/coretime-westend.json +++ b/cumulus/parachains/chain-specs/coretime-westend.json @@ -30,7 +30,8 @@ "/dns/coretime-westend.bootnodes.polkadotters.com/tcp/30358/wss/p2p/12D3KooWDc9T2vQ8rHvX7hAt9eLWktD9Q89NDTcLm5STkuNbzUGf", "/dns/coretime-westend.bootnodes.polkadotters.com/tcp/30356/p2p/12D3KooWDc9T2vQ8rHvX7hAt9eLWktD9Q89NDTcLm5STkuNbzUGf", "/dns/coretime-westend.bootnode.amforc.com/tcp/29999/wss/p2p/12D3KooWG9a9H9An96E3kgXL1sirHta117iuacJXnJRaUywkMiSd", - "/dns/coretime-westend.bootnode.amforc.com/tcp/30013/p2p/12D3KooWG9a9H9An96E3kgXL1sirHta117iuacJXnJRaUywkMiSd" + "/dns/coretime-westend.bootnode.amforc.com/tcp/30013/p2p/12D3KooWG9a9H9An96E3kgXL1sirHta117iuacJXnJRaUywkMiSd", + "/dns/coretime-westend-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWCFNzjaiq45ZpW2qStmQdG5w7ZHrmi3RWUeG8cV2pPc2Y" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/people-kusama.json b/cumulus/parachains/chain-specs/people-kusama.json index 300b9fcfb183..701e6e7dc1ec 100644 --- a/cumulus/parachains/chain-specs/people-kusama.json +++ b/cumulus/parachains/chain-specs/people-kusama.json @@ -28,7 +28,8 @@ "/dns/ibp-boot-kusama-people.luckyfriday.io/tcp/30342/p2p/12D3KooWM4bRafMH2StfBEQtyj5cMWfGLYbuikCZmvKv9m1MQVPn", "/dns/ibp-boot-kusama-people.luckyfriday.io/tcp/443/wss/p2p/12D3KooWM4bRafMH2StfBEQtyj5cMWfGLYbuikCZmvKv9m1MQVPn", "/dns4/people-kusama.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWRuKr3ogzXwD8zE2CTWenGdy8vSfViAjYMwGiwvFCsz8n", - "/dns/people-kusama.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWFkDKdFxBJFyj9zumuJ4Mmctec2GqdYHcKYq8MTVe8dxf" + "/dns/people-kusama.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWFkDKdFxBJFyj9zumuJ4Mmctec2GqdYHcKYq8MTVe8dxf", + "/dns/people-kusama-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWN32MmhPgZN8e1Dmc8DzEUKsfC2hga3Lqekko4VWvrbhq" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/people-polkadot.json b/cumulus/parachains/chain-specs/people-polkadot.json index 083c0fbf44a4..ff8d57b9284d 100644 --- a/cumulus/parachains/chain-specs/people-polkadot.json +++ b/cumulus/parachains/chain-specs/people-polkadot.json @@ -8,7 +8,8 @@ "/dns/polkadot-people-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWP7BoJ7nAF9QnsreN8Eft1yHNUhvhxFiQyKFEUePi9mu3", "/dns/polkadot-people-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWSSfWY3fTGJvGkuNUNBSNVCdLLNJnwkZSNQt7GCRYXu4o", "/dns/people-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWKMYu1L28TkDf1ooMW8D8PHcztLnjV3bausH9eiVTRUYN", - "/dns/people-polkadot-boot-ng.dwellir.com/tcp/30346/p2p/12D3KooWKMYu1L28TkDf1ooMW8D8PHcztLnjV3bausH9eiVTRUYN" + "/dns/people-polkadot-boot-ng.dwellir.com/tcp/30346/p2p/12D3KooWKMYu1L28TkDf1ooMW8D8PHcztLnjV3bausH9eiVTRUYN", + "/dns/people-polkadot-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWDf2aLDKHQyLkDzdEGs6exNzWWw62s2EK9g1wrujJzRZt" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/people-westend.json b/cumulus/parachains/chain-specs/people-westend.json index ac24b2e64359..e52d7b299e1d 100644 --- a/cumulus/parachains/chain-specs/people-westend.json +++ b/cumulus/parachains/chain-specs/people-westend.json @@ -28,7 +28,8 @@ "/dns/wppl16.rotko.net/tcp/33766/p2p/12D3KooWHwUXBUo2WRMUBwPLC2ttVbnEk1KvDyESYAeKcNoCn7WS", "/dns/wppl16.rotko.net/tcp/35766/wss/p2p/12D3KooWHwUXBUo2WRMUBwPLC2ttVbnEk1KvDyESYAeKcNoCn7WS", "/dns/people-westend-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBdCpCabhgBpLn67LWcXE2JJCCTMhuJHrfDNiTiCCr3KX", - "/dns/people-westend-boot-ng.dwellir.com/tcp/30355/p2p/12D3KooWBdCpCabhgBpLn67LWcXE2JJCCTMhuJHrfDNiTiCCr3KX" + "/dns/people-westend-boot-ng.dwellir.com/tcp/30355/p2p/12D3KooWBdCpCabhgBpLn67LWcXE2JJCCTMhuJHrfDNiTiCCr3KX", + "/dns/people-westend-01.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWJzL4R3kq9Ms88gsV6bS9zGT8DHySdqwau5SHNqTzToNM" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 6d436bdf799a..6c52c3201c71 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Logic which is common to all parachain runtimes" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -37,9 +39,9 @@ xcm = { workspace = true } xcm-executor = { workspace = true } # Cumulus -pallet-collator-selection = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-utility = { workspace = true } +pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } [dev-dependencies] @@ -90,4 +92,5 @@ runtime-benchmarks = [ "polkadot-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml index 25796e7d64b4..a164a8197f72 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -13,15 +13,15 @@ workspace = true [dependencies] # Substrate +frame-support = { workspace = true } sp-core = { workspace = true } sp-keyring = { workspace = true } -frame-support = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } +asset-hub-rococo-runtime = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } -asset-hub-rococo-runtime = { workspace = true, default-features = true } +parachains-common = { workspace = true, default-features = true } rococo-emulated-chain = { workspace = true } testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs index 606d04060b6b..3ffb9a704b46 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs @@ -20,8 +20,9 @@ use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, PenpalSiblingSovereignAccount, - PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID, + accounts, build_genesis_storage, collators, PenpalASiblingSovereignAccount, + PenpalATeleportableAssetLocation, PenpalBSiblingSovereignAccount, + PenpalBTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID, }; use parachains_common::{AccountId, Balance}; @@ -77,10 +78,17 @@ pub fn genesis() -> Storage { }, foreign_assets: asset_hub_rococo_runtime::ForeignAssetsConfig { assets: vec![ - // Penpal's teleportable asset representation + // PenpalA's teleportable asset representation ( - PenpalTeleportableAssetLocation::get(), - PenpalSiblingSovereignAccount::get(), + PenpalATeleportableAssetLocation::get(), + PenpalASiblingSovereignAccount::get(), + false, + ED, + ), + // PenpalB's teleportable asset representation + ( + PenpalBTeleportableAssetLocation::get(), + PenpalBSiblingSovereignAccount::get(), false, ED, ), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 75b61d6a4cd7..1a075b9fe6be 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -59,7 +59,7 @@ impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); impl_assets_helpers_for_parachain!(AssetHubRococo); -impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v4::Location); +impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, xcm::v5::Location); impl_xcm_helpers_for_parachain!(AssetHubRococo); impl_bridge_helpers_for_chain!( AssetHubRococo, diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml index 8e423ebbf9c2..c67b94d0db73 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -13,17 +13,17 @@ workspace = true [dependencies] # Substrate +frame-support = { workspace = true } sp-core = { workspace = true } sp-keyring = { workspace = true } -frame-support = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } +asset-hub-westend-runtime = { workspace = true } cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } -asset-hub-westend-runtime = { workspace = true } -westend-emulated-chain = { workspace = true, default-features = true } +parachains-common = { workspace = true, default-features = true } testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } +westend-emulated-chain = { workspace = true, default-features = true } # Polkadot xcm = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs index 30e7279a383f..ef7997322da7 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs @@ -20,9 +20,9 @@ use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, PenpalBSiblingSovereignAccount, - PenpalBTeleportableAssetLocation, PenpalSiblingSovereignAccount, - PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID, + accounts, build_genesis_storage, collators, PenpalASiblingSovereignAccount, + PenpalATeleportableAssetLocation, PenpalBSiblingSovereignAccount, + PenpalBTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID, }; use parachains_common::{AccountId, Balance}; @@ -75,10 +75,10 @@ pub fn genesis() -> Storage { }, foreign_assets: asset_hub_westend_runtime::ForeignAssetsConfig { assets: vec![ - // Penpal's teleportable asset representation + // PenpalA's teleportable asset representation ( - PenpalTeleportableAssetLocation::get(), - PenpalSiblingSovereignAccount::get(), + PenpalATeleportableAssetLocation::get(), + PenpalASiblingSovereignAccount::get(), false, ED, ), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index c44f4b010c0a..3e240ed67482 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -59,7 +59,7 @@ impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); impl_assets_helpers_for_parachain!(AssetHubWestend); -impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v4::Location); +impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, xcm::v5::Location); impl_xcm_helpers_for_parachain!(AssetHubWestend); impl_bridge_helpers_for_chain!( AssetHubWestend, 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 231265085eda..8b16d8ac27ae 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 @@ -13,9 +13,9 @@ workspace = true [dependencies] # Substrate +frame-support = { workspace = true } sp-core = { workspace = true } sp-keyring = { workspace = true } -frame-support = { workspace = true } # Polkadot Dependencies xcm = { workspace = true } @@ -24,8 +24,8 @@ xcm = { workspace = true } bp-messages = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -bridge-hub-rococo-runtime = { workspace = true, default-features = true } bridge-hub-common = { workspace = true } +bridge-hub-rococo-runtime = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = 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 0268a6a7a1b3..575017f88bb5 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 @@ -22,7 +22,7 @@ use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::Balance; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; pub const ASSETHUB_PARA_ID: u32 = 1000; pub const PARA_ID: u32 = 1013; @@ -73,7 +73,7 @@ pub fn genesis() -> Storage { // open AHR -> AHW bridge ( Location::new(1, [Parachain(1000)]), - Junctions::from([Westend.into(), Parachain(1000)]), + Junctions::from([ByGenesis(WESTEND_GENESIS_HASH).into(), Parachain(1000)]), Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), ), ], 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 8292e132809c..292b5bd3e434 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 @@ -13,9 +13,9 @@ workspace = true [dependencies] # Substrate +frame-support = { workspace = true } sp-core = { workspace = true } sp-keyring = { workspace = true } -frame-support = { workspace = true } # Polkadot Dependencies xcm = { workspace = true } @@ -24,8 +24,8 @@ xcm = { workspace = true } bp-messages = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -bridge-hub-westend-runtime = { workspace = true, default-features = true } bridge-hub-common = { workspace = true } +bridge-hub-westend-runtime = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = 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 f72eaa30026d..eb4623084f85 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 @@ -22,7 +22,7 @@ use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::Balance; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; pub const PARA_ID: u32 = 1002; pub const ASSETHUB_PARA_ID: u32 = 1000; @@ -73,7 +73,10 @@ pub fn genesis() -> Storage { // open AHW -> AHR bridge ( Location::new(1, [Parachain(1000)]), - Junctions::from([Rococo.into(), Parachain(1000)]), + Junctions::from([ + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH).into(), + Parachain(1000), + ]), Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), ), ], diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index e7a28ebf4a46..b548e3b7e64c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -16,7 +16,7 @@ pub mod genesis; pub use bridge_hub_westend_runtime::{ - xcm_config::XcmConfig as BridgeHubWestendXcmConfig, + self, xcm_config::XcmConfig as BridgeHubWestendXcmConfig, ExistentialDeposit as BridgeHubWestendExistentialDeposit, }; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml index 87dfd73ab05b..55e3ad6743ed 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml @@ -13,12 +13,12 @@ workspace = true [dependencies] # Substrate -sp-core = { workspace = true } frame-support = { workspace = true } +sp-core = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } +collectives-westend-runtime = { workspace = true } cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } -collectives-westend-runtime = { workspace = true } +parachains-common = { workspace = true, default-features = true } testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml index 94d43c5eee2f..8f12dc675199 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml @@ -13,12 +13,12 @@ workspace = true [dependencies] # Substrate -sp-core = { workspace = true } frame-support = { workspace = true } +sp-core = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true } coretime-rococo-runtime = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml index 2640c27d016b..fad1000ac66c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml @@ -13,12 +13,12 @@ workspace = true [dependencies] # Substrate -sp-core = { workspace = true } frame-support = { workspace = true } +sp-core = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true } coretime-westend-runtime = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml index 1549d6a2ab6b..c98e8629e31d 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml @@ -10,12 +10,12 @@ publish = false [dependencies] # Substrate -sp-core = { workspace = true } frame-support = { workspace = true } +sp-core = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } people-rococo-runtime = { workspace = true } testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml index 9c5ac0bca9de..598ba5488f85 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml @@ -10,12 +10,12 @@ publish = false [dependencies] # Substrate -sp-core = { workspace = true } frame-support = { workspace = true } +sp-core = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } people-westend-runtime = { workspace = true } testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 743cd7dc54a2..7e92e3bf9448 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -13,15 +13,15 @@ workspace = true [dependencies] # Substrate +frame-support = { workspace = true } sp-core = { workspace = true } sp-keyring = { workspace = true } -frame-support = { workspace = true } # Polkadot xcm = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } penpal-runtime = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 92dfa30f2e83..f5642dbb0daa 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -31,6 +31,9 @@ use emulated_integration_tests_common::{ xcm_emulator::decl_test_parachains, }; +// Polkadot +use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}; + // Penpal Parachain declaration decl_test_parachains! { pub struct PenpalA { @@ -39,7 +42,7 @@ decl_test_parachains! { penpal_runtime::AuraExt::on_initialize(1); frame_support::assert_ok!(penpal_runtime::System::set_storage( penpal_runtime::RuntimeOrigin::root(), - vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Rococo.encode())], + vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::ByGenesis(ROCOCO_GENESIS_HASH).encode())], )); }, runtime = penpal_runtime, @@ -63,7 +66,7 @@ decl_test_parachains! { penpal_runtime::AuraExt::on_initialize(1); frame_support::assert_ok!(penpal_runtime::System::set_storage( penpal_runtime::RuntimeOrigin::root(), - vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Westend.encode())], + vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::ByGenesis(WESTEND_GENESIS_HASH).encode())], )); }, runtime = penpal_runtime, diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml index 6db1263df8c7..ccf3854e67d8 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -13,18 +13,18 @@ workspace = true [dependencies] # Substrate -sp-core = { workspace = true } -sp-keyring = { workspace = true } +sc-consensus-grandpa = { workspace = true } sp-authority-discovery = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true } +sp-core = { workspace = true } +sp-keyring = { workspace = true } # Polkadot polkadot-primitives = { workspace = true } -rococo-runtime-constants = { workspace = true } rococo-runtime = { workspace = true } +rococo-runtime-constants = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml index de285d9885a2..9b980d7d39cc 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -13,21 +13,21 @@ workspace = true [dependencies] # Substrate -sp-core = { workspace = true } -sp-runtime = { workspace = true } +pallet-staking = { workspace = true } +sc-consensus-grandpa = { workspace = true } sp-authority-discovery = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true } -pallet-staking = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } # Polkadot polkadot-primitives = { workspace = true } -westend-runtime-constants = { workspace = true } westend-runtime = { workspace = true } +westend-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-runtime-apis = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 23edaf6bfe65..e921deb9c628 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Common resources for integration testing with xcm-emulator" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,36 +16,36 @@ codec = { workspace = true } paste = { workspace = true, default-features = true } # Substrate -sp-consensus-beefy = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true, default-features = true } -sp-authority-discovery = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-consensus-babe = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-message-queue = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } # Cumulus -parachains-common = { workspace = true, default-features = true } +asset-test-utils = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } +cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } +parachains-common = { workspace = true, default-features = true } xcm-emulator = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } -asset-test-utils = { workspace = true, default-features = true } # Bridges bp-messages = { workspace = true, default-features = true } bp-xcm-bridge-hub = { workspace = true, default-features = true } +bridge-runtime-common = { workspace = true, default-features = true } pallet-bridge-messages = { workspace = true, default-features = true } pallet-xcm-bridge-hub = { workspace = true, default-features = true } -bridge-runtime-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index c0d42cf2758e..9dad323aa19c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -370,6 +370,8 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { let destination: $crate::impls::Location = ::child_location_of(recipient); let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser); + $crate::impls::dmp::Pallet::<::Runtime>::make_parachain_reachable(recipient); + // Send XCM `Transact` $crate::impls::assert_ok!(]>::XcmPallet::send( root_origin, diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 07fde111d3dc..e2757f8b9a35 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -41,6 +41,7 @@ use polkadot_primitives::{AssignmentId, ValidatorId}; pub const XCM_V2: u32 = 2; pub const XCM_V3: u32 = 3; pub const XCM_V4: u32 = 4; +pub const XCM_V5: u32 = 5; pub const REF_TIME_THRESHOLD: u64 = 33; pub const PROOF_SIZE_THRESHOLD: u64 = 33; @@ -55,26 +56,26 @@ pub const TELEPORTABLE_ASSET_ID: u32 = 2; // USDT registered on AH as (trust-backed) Asset and reserve-transferred between Parachain and AH pub const USDT_ID: u32 = 1984; -pub const PENPAL_ID: u32 = 2000; +pub const PENPAL_A_ID: u32 = 2000; pub const PENPAL_B_ID: u32 = 2001; pub const ASSETS_PALLET_ID: u8 = 50; parameter_types! { - pub PenpalTeleportableAssetLocation: xcm::v4::Location - = xcm::v4::Location::new(1, [ - xcm::v4::Junction::Parachain(PENPAL_ID), - xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v4::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), + pub PenpalATeleportableAssetLocation: xcm::v5::Location + = xcm::v5::Location::new(1, [ + xcm::v5::Junction::Parachain(PENPAL_A_ID), + xcm::v5::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v5::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), ] ); - pub PenpalSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating(); - pub PenpalBTeleportableAssetLocation: xcm::v4::Location - = xcm::v4::Location::new(1, [ - xcm::v4::Junction::Parachain(PENPAL_B_ID), - xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v4::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), + pub PenpalBTeleportableAssetLocation: xcm::v5::Location + = xcm::v5::Location::new(1, [ + xcm::v5::Junction::Parachain(PENPAL_B_ID), + xcm::v5::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v5::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), ] ); + pub PenpalASiblingSovereignAccount: AccountId = Sibling::from(PENPAL_A_ID).into_account_truncating(); pub PenpalBSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_B_ID).into_account_truncating(); } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 3ff5ed388a39..cd2b41e5198f 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -23,6 +23,7 @@ pub use pallet_message_queue; pub use pallet_xcm; // Polkadot +pub use polkadot_runtime_parachains::dmp::Pallet as Dmp; pub use xcm::{ prelude::{ AccountId32, All, Asset, AssetId, BuyExecution, DepositAsset, ExpectTransactStatus, @@ -156,6 +157,8 @@ macro_rules! test_relay_is_trusted_teleporter { // Send XCM message from Relay <$sender_relay>::execute_with(|| { + $crate::macros::Dmp::<<$sender_relay as $crate::macros::Chain>::Runtime>::make_parachain_reachable(<$receiver_para>::para_id()); + assert_ok!(<$sender_relay as [<$sender_relay Pallet>]>::XcmPallet::limited_teleport_assets( origin.clone(), bx!(para_destination.clone().into()), @@ -404,6 +407,230 @@ macro_rules! test_chain_can_claim_assets { }; } +#[macro_export] +macro_rules! test_can_estimate_and_pay_exact_fees { + ( $sender_para:ty, $asset_hub:ty, $receiver_para:ty, ($asset_id:expr, $amount:expr), $owner_prefix:ty ) => { + $crate::macros::paste::paste! { + // We first define the call we'll use throughout the test. + fn get_call( + estimated_local_fees: impl Into, + estimated_intermediate_fees: impl Into, + estimated_remote_fees: impl Into, + ) -> <$sender_para as Chain>::RuntimeCall { + type RuntimeCall = <$sender_para as Chain>::RuntimeCall; + + let beneficiary = [<$receiver_para Receiver>]::get(); + let xcm_in_destination = Xcm::<()>::builder_unsafe() + .pay_fees(estimated_remote_fees) + .deposit_asset(AllCounted(1), beneficiary) + .build(); + let ah_to_receiver = $asset_hub::sibling_location_of($receiver_para::para_id()); + let xcm_in_reserve = Xcm::<()>::builder_unsafe() + .pay_fees(estimated_intermediate_fees) + .deposit_reserve_asset( + AllCounted(1), + ah_to_receiver, + xcm_in_destination, + ) + .build(); + let sender_to_ah = $sender_para::sibling_location_of($asset_hub::para_id()); + let local_xcm = Xcm::<<$sender_para as Chain>::RuntimeCall>::builder() + .withdraw_asset(($asset_id, $amount)) + .pay_fees(estimated_local_fees) + .initiate_reserve_withdraw(AllCounted(1), sender_to_ah, xcm_in_reserve) + .build(); + + RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute { + message: bx!(VersionedXcm::from(local_xcm)), + max_weight: Weight::from_parts(10_000_000_000, 500_000), + }) + } + + let destination = $sender_para::sibling_location_of($receiver_para::para_id()); + let sender = [<$sender_para Sender>]::get(); + let sender_as_seen_by_ah = $asset_hub::sibling_location_of($sender_para::para_id()); + let sov_of_sender_on_ah = $asset_hub::sovereign_account_id_of(sender_as_seen_by_ah.clone()); + let asset_owner = [<$owner_prefix AssetOwner>]::get(); + + // Fund parachain's sender account. + $sender_para::mint_foreign_asset( + <$sender_para as Chain>::RuntimeOrigin::signed(asset_owner.clone()), + $asset_id.clone().into(), + sender.clone(), + $amount * 2, + ); + + // Fund the parachain origin's SA on Asset Hub with the native tokens. + $asset_hub::fund_accounts(vec![(sov_of_sender_on_ah.clone(), $amount * 2)]); + + let beneficiary_id = [<$receiver_para Receiver>]::get(); + + let test_args = TestContext { + sender: sender.clone(), + receiver: beneficiary_id.clone(), + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + $amount, + ($asset_id, $amount).into(), + None, + 0, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // We get these from the closure. + let mut local_execution_fees = 0; + let mut local_delivery_fees = 0; + let mut remote_message = VersionedXcm::from(Xcm::<()>(Vec::new())); + <$sender_para as TestExt>::execute_with(|| { + type Runtime = <$sender_para as Chain>::Runtime; + type OriginCaller = <$sender_para as Chain>::OriginCaller; + + let call = get_call( + (Parent, 100_000_000_000u128), + (Parent, 100_000_000_000u128), + (Parent, 100_000_000_000u128), + ); + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call).unwrap(); + let local_xcm = result.local_xcm.unwrap().clone(); + let local_xcm_weight = Runtime::query_xcm_weight(local_xcm).unwrap(); + local_execution_fees = Runtime::query_weight_to_asset_fee( + local_xcm_weight, + VersionedAssetId::from(AssetId(Location::parent())), + ) + .unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::from(Location::new(1, [Parachain(1000)])) + }) + .unwrap(); + assert_eq!(messages_to_query.len(), 1); + remote_message = messages_to_query[0].clone(); + let delivery_fees = + Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) + .unwrap(); + local_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees); + }); + + // These are set in the AssetHub closure. + let mut intermediate_execution_fees = 0; + let mut intermediate_delivery_fees = 0; + let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new())); + <$asset_hub as TestExt>::execute_with(|| { + type Runtime = <$asset_hub as Chain>::Runtime; + type RuntimeCall = <$asset_hub as Chain>::RuntimeCall; + + // First we get the execution fees. + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = Runtime::query_weight_to_asset_fee( + weight, + VersionedAssetId::from(AssetId(Location::new(1, []))), + ) + .unwrap(); + + // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. + let xcm_program = + VersionedXcm::from(Xcm::::from(remote_message.clone().try_into().unwrap())); + + // Now we get the delivery fees to the final destination. + let result = + Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::from(Location::new(1, [Parachain(2001)])) + }) + .unwrap(); + // There's actually two messages here. + // One created when the message we sent from `$sender_para` arrived and was executed. + // The second one when we dry-run the xcm. + // We could've gotten the message from the queue without having to dry-run, but + // offchain applications would have to dry-run, so we do it here as well. + intermediate_remote_message = messages_to_query[0].clone(); + let delivery_fees = Runtime::query_delivery_fees( + destination_to_query.clone(), + intermediate_remote_message.clone(), + ) + .unwrap(); + intermediate_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees); + }); + + // Get the final execution fees in the destination. + let mut final_execution_fees = 0; + <$receiver_para as TestExt>::execute_with(|| { + type Runtime = <$sender_para as Chain>::Runtime; + + let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); + final_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(Location::parent()))) + .unwrap(); + }); + + // Dry-running is done. + $sender_para::reset_ext(); + $asset_hub::reset_ext(); + $receiver_para::reset_ext(); + + // Fund accounts again. + $sender_para::mint_foreign_asset( + <$sender_para as Chain>::RuntimeOrigin::signed(asset_owner), + $asset_id.clone().into(), + sender.clone(), + $amount * 2, + ); + $asset_hub::fund_accounts(vec![(sov_of_sender_on_ah, $amount * 2)]); + + // Actually run the extrinsic. + let sender_assets_before = $sender_para::execute_with(|| { + type ForeignAssets = <$sender_para as [<$sender_para Pallet>]>::ForeignAssets; + >::balance($asset_id.clone().into(), &sender) + }); + let receiver_assets_before = $receiver_para::execute_with(|| { + type ForeignAssets = <$receiver_para as [<$receiver_para Pallet>]>::ForeignAssets; + >::balance($asset_id.clone().into(), &beneficiary_id) + }); + + test.set_assertion::<$sender_para>(sender_assertions); + test.set_assertion::<$asset_hub>(hop_assertions); + test.set_assertion::<$receiver_para>(receiver_assertions); + let call = get_call( + (Parent, local_execution_fees + local_delivery_fees), + (Parent, intermediate_execution_fees + intermediate_delivery_fees), + (Parent, final_execution_fees), + ); + test.set_call(call); + test.assert(); + + let sender_assets_after = $sender_para::execute_with(|| { + type ForeignAssets = <$sender_para as [<$sender_para Pallet>]>::ForeignAssets; + >::balance($asset_id.clone().into(), &sender) + }); + let receiver_assets_after = $receiver_para::execute_with(|| { + type ForeignAssets = <$receiver_para as [<$receiver_para Pallet>]>::ForeignAssets; + >::balance($asset_id.into(), &beneficiary_id) + }); + + // We know the exact fees on every hop. + assert_eq!(sender_assets_after, sender_assets_before - $amount); + assert_eq!( + receiver_assets_after, + receiver_assets_before + $amount - + local_execution_fees - + local_delivery_fees - + intermediate_execution_fees - + intermediate_delivery_fees - + final_execution_fees + ); + } + }; +} + #[macro_export] macro_rules! test_dry_run_transfer_across_pk_bridge { ( $sender_asset_hub:ty, $sender_bridge_hub:ty, $destination:expr ) => { @@ -474,7 +701,7 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { )); type Runtime = <$asset_hub as Chain>::Runtime; - let acceptable_payment_assets = Runtime::query_acceptable_payment_assets(4).unwrap(); + let acceptable_payment_assets = Runtime::query_acceptable_payment_assets(XCM_VERSION).unwrap(); assert_eq!(acceptable_payment_assets, vec![ VersionedAssetId::from(AssetId(wnd.clone())), VersionedAssetId::from(AssetId(usdt.clone())), diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs index 7a289a3f1ac6..380f4983ad98 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -27,12 +27,11 @@ pub fn xcm_transact_paid_execution( beneficiary: AccountId, ) -> VersionedXcm<()> { let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); VersionedXcm::from(Xcm(vec![ WithdrawAsset(fees.clone().into()), BuyExecution { fees, weight_limit }, - Transact { require_weight_at_most, origin_kind, call }, + Transact { origin_kind, call, fallback_max_weight: None }, RefundSurplus, DepositAsset { assets: All.into(), @@ -50,12 +49,11 @@ pub fn xcm_transact_unpaid_execution( origin_kind: OriginKind, ) -> VersionedXcm<()> { let weight_limit = WeightLimit::Unlimited; - let require_weight_at_most = Weight::from_parts(1000000000, 200000); let check_origin = None; VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, - Transact { require_weight_at_most, origin_kind, call }, + Transact { origin_kind, call, fallback_max_weight: None }, ])) } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml index 864f3c6edd7e..2f8889e48162 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml @@ -12,10 +12,10 @@ workspace = true [dependencies] # Cumulus -emulated-integration-tests-common = { workspace = true } -rococo-emulated-chain = { workspace = true } asset-hub-rococo-emulated-chain = { workspace = true } bridge-hub-rococo-emulated-chain = { workspace = true } -people-rococo-emulated-chain = { workspace = true } -penpal-emulated-chain = { workspace = true } coretime-rococo-emulated-chain = { workspace = true } +emulated-integration-tests-common = { workspace = true } +penpal-emulated-chain = { workspace = true } +people-rococo-emulated-chain = { workspace = true } +rococo-emulated-chain = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml index cd0cb272b7f5..1b789b21c7df 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml @@ -12,11 +12,11 @@ workspace = true [dependencies] # Cumulus -emulated-integration-tests-common = { workspace = true } -rococo-emulated-chain = { workspace = true } -westend-emulated-chain = { workspace = true, default-features = true } asset-hub-rococo-emulated-chain = { workspace = true } asset-hub-westend-emulated-chain = { workspace = true } bridge-hub-rococo-emulated-chain = { workspace = true } bridge-hub-westend-emulated-chain = { workspace = true } +emulated-integration-tests-common = { workspace = true } penpal-emulated-chain = { workspace = true } +rococo-emulated-chain = { workspace = true } +westend-emulated-chain = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml index cec2e3733b2a..50e75a6bdd74 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -12,11 +12,11 @@ workspace = true [dependencies] # Cumulus -emulated-integration-tests-common = { workspace = true } -westend-emulated-chain = { workspace = true } asset-hub-westend-emulated-chain = { workspace = true } bridge-hub-westend-emulated-chain = { workspace = true } collectives-westend-emulated-chain = { workspace = true } +coretime-westend-emulated-chain = { workspace = true } +emulated-integration-tests-common = { workspace = true } penpal-emulated-chain = { workspace = true } people-westend-emulated-chain = { workspace = true } -coretime-westend-emulated-chain = { workspace = true } +westend-emulated-chain = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 3d40db6b03ab..9e8b8f2a52d7 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -11,31 +11,31 @@ publish = false workspace = true [dependencies] -codec = { workspace = true } assert_matches = { workspace = true } +codec = { workspace = true } # Substrate -sp-runtime = { workspace = true } -sp-core = { workspace = true } frame-support = { workspace = true } -pallet-balances = { workspace = true } -pallet-assets = { workspace = true } pallet-asset-conversion = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } pallet-treasury = { workspace = true } pallet-utility = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } # Polkadot -xcm = { workspace = true } pallet-xcm = { workspace = true } -xcm-executor = { workspace = true } -xcm-runtime-apis = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true, default-features = true } rococo-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true, default-features = true } # Cumulus asset-test-utils = { workspace = true, default-features = true } cumulus-pallet-parachain-system = { workspace = true } -parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } rococo-system-emulated-network = { workspace = true } 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 1184b5fd7c4a..f3a1b3f5bfa2 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 @@ -27,8 +27,8 @@ mod imports { // Polkadot pub use xcm::{ + latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, prelude::{AccountId32 as AccountId32Junction, *}, - v3, }; pub use xcm_executor::traits::TransferType; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs index 99b31aba4be0..52a20c00c277 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = AssetHubRococoExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount); + test_chain_can_claim_assets!( + AssetHubRococo, + RuntimeCall, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), + assets, + amount + ); } 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 7bb25d7cec62..fb95c361f089 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 @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use rococo_system_emulated_network::rococo_emulated_chain::rococo_runtime::Dmp; + use super::reserve_transfer::*; use crate::{ imports::*, @@ -163,7 +165,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { // Foreign asset used: bridged WND let foreign_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000; let wnd_at_rococo_parachains = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))]); // Configure destination chain to trust AH as reserve of WND PenpalA::execute_with(|| { @@ -171,7 +173,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Westend)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(), )], )); }); @@ -293,7 +295,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() { // Foreign asset used: bridged WND let foreign_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000; let wnd_at_rococo_parachains = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))]); // Configure destination chain to trust AH as reserve of WND PenpalA::execute_with(|| { @@ -301,7 +303,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Westend)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(), )], )); }); @@ -455,7 +457,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Westend)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(), )], )); }); @@ -464,14 +466,14 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Westend)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]).encode(), )], )); }); // Register WND as foreign asset and transfer it around the Rococo ecosystem let wnd_at_rococo_parachains = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))]); AssetHubRococo::force_create_foreign_asset( wnd_at_rococo_parachains.clone().try_into().unwrap(), assets_owner.clone(), @@ -777,6 +779,8 @@ fn transfer_native_asset_from_relay_to_para_through_asset_hub() { xcm: xcm_on_final_dest, }]); + Dmp::make_parachain_reachable(AssetHubRococo::para_id()); + // First leg is a teleport, from there a local-reserve-transfer to final dest ::XcmPallet::transfer_assets_using_type_and_then( t.signed_origin, 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 302f71f89f83..407a581afeb9 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 @@ -14,6 +14,7 @@ // limitations under the License. use crate::imports::*; +use rococo_system_emulated_network::rococo_emulated_chain::rococo_runtime::Dmp; use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; fn relay_to_para_sender_assertions(t: RelayToParaTest) { @@ -115,7 +116,7 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubRococo, vec![ - // Transport fees are paid + // Delivery fees are paid RuntimeEvent::PolkadotXcm(pallet_xcm::Event::FeesPaid { .. }) => {}, ] ); @@ -274,7 +275,7 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { t.args.dest.clone() ), }, - // Transport fees are paid + // Delivery fees are paid RuntimeEvent::PolkadotXcm( pallet_xcm::Event::FeesPaid { .. } ) => {}, @@ -305,7 +306,7 @@ fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { owner: *owner == t.sender.account_id, balance: *balance == t.args.amount, }, - // Transport fees are paid + // Delivery fees are paid RuntimeEvent::PolkadotXcm( pallet_xcm::Event::FeesPaid { .. } ) => {}, @@ -487,6 +488,11 @@ pub fn para_to_para_through_hop_receiver_assertions(t: Test DispatchResult { + let Junction::Parachain(para_id) = *t.args.dest.chain_location().last().unwrap() else { + unimplemented!("Destination is not a parachain?") + }; + + Dmp::make_parachain_reachable(para_id); ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -546,6 +552,13 @@ fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> Dispa fn para_to_para_through_relay_limited_reserve_transfer_assets( t: ParaToParaThroughRelayTest, ) -> DispatchResult { + let Junction::Parachain(para_id) = *t.args.dest.chain_location().last().unwrap() else { + unimplemented!("Destination is not a parachain?") + }; + + Rococo::ext_wrapper(|| { + Dmp::make_parachain_reachable(para_id); + }); ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -1599,7 +1612,7 @@ fn reserve_withdraw_from_untrusted_reserve_fails() { ]); let result = ::PolkadotXcm::execute( signed_origin, - bx!(xcm::VersionedXcm::V4(xcm)), + bx!(xcm::VersionedXcm::from(xcm)), Weight::MAX, ); assert!(result.is_err()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 29eaa9694643..ea8f6c1defba 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -24,7 +24,7 @@ fn send_transact_as_superuser_from_relay_to_asset_hub_works() { ASSET_MIN_BALANCE, true, AssetHubRococoSender::get().into(), - Some(Weight::from_parts(1_019_445_000, 200_000)), + Some(Weight::from_parts(144_933_000, 3675)), ) } @@ -121,7 +121,7 @@ fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() { ASSET_MIN_BALANCE, true, para_sovereign_account.clone(), - Some(Weight::from_parts(1_019_445_000, 200_000)), + Some(Weight::from_parts(144_933_000, 3675)), ASSET_MIN_BALANCE * 1000000000, ); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs index 5662a78ab67f..8da1e56de219 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs @@ -67,7 +67,7 @@ fn system_para_sets_relay_xcm_supported_version() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); + AssetHubRococo::assert_dmp_queue_complete(Some(Weight::from_parts(115_294_000, 0))); assert_expected_events!( AssetHubRococo, 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 470b4d0f389e..7fde929c0dcb 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 @@ -574,7 +574,7 @@ fn teleport_to_untrusted_chain_fails() { ]); let result = ::PolkadotXcm::execute( signed_origin, - bx!(xcm::VersionedXcm::V4(xcm)), + bx!(xcm::VersionedXcm::from(xcm)), Weight::MAX, ); assert!(result.is_err()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs index 3320392b495d..8648c8ce9311 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs @@ -29,6 +29,7 @@ use frame_support::{ use parachains_common::AccountId; use polkadot_runtime_common::impls::VersionedLocatableAsset; use rococo_runtime_constants::currency::GRAND; +use rococo_system_emulated_network::rococo_emulated_chain::rococo_runtime::Dmp; use xcm_executor::traits::ConvertLocation; // Fund Treasury account on Asset Hub from Treasury account on Relay Chain with ROCs. @@ -64,6 +65,7 @@ fn spend_roc_on_asset_hub() { treasury_balance * 2, )); + Dmp::make_parachain_reachable(1000); let native_asset = Location::here(); let asset_hub_location: Location = [Parachain(1000)].into(); let treasury_location: Location = (Parent, PalletInstance(18)).into(); @@ -71,11 +73,12 @@ fn spend_roc_on_asset_hub() { let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { as_origin: bx!(RococoOriginCaller::system(RawOrigin::Signed(treasury_account))), call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { - dest: bx!(VersionedLocation::V4(asset_hub_location.clone())), - beneficiary: bx!(VersionedLocation::V4(treasury_location)), - assets: bx!(VersionedAssets::V4( - Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into() - )), + dest: bx!(VersionedLocation::from(asset_hub_location.clone())), + beneficiary: bx!(VersionedLocation::from(treasury_location)), + assets: bx!(VersionedAssets::from(Assets::from(Asset { + id: native_asset.clone().into(), + fun: treasury_balance.into() + }))), fee_asset_item: 0, })), }); @@ -110,12 +113,12 @@ fn spend_roc_on_asset_hub() { let native_asset = Location::parent(); let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::::spend { - asset_kind: bx!(VersionedLocatableAsset::V4 { - location: asset_hub_location.clone(), - asset_id: native_asset.into(), - }), + asset_kind: bx!(VersionedLocatableAsset::from(( + asset_hub_location.clone(), + native_asset.into() + ))), amount: treasury_spend_balance, - beneficiary: bx!(VersionedLocation::V4(alice_location)), + beneficiary: bx!(VersionedLocation::from(alice_location)), valid_from: None, }); @@ -170,16 +173,12 @@ fn create_and_claim_treasury_spend_in_usdt() { // treasury account on a sibling parachain. let treasury_account = ahr_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap(); - let asset_hub_location = - v3::Location::new(0, v3::Junction::Parachain(AssetHubRococo::para_id().into())); + let asset_hub_location = Location::new(0, Parachain(AssetHubRococo::para_id().into())); let root = ::RuntimeOrigin::root(); - // asset kind to be spend from the treasury. - let asset_kind = VersionedLocatableAsset::V3 { - location: asset_hub_location, - asset_id: v3::AssetId::Concrete( - (v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(USDT_ID.into())).into(), - ), - }; + // asset kind to be spent from the treasury. + let asset_kind: VersionedLocatableAsset = + (asset_hub_location, AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into())) + .into(); // treasury spend beneficiary. let alice: AccountId = Rococo::account_id_of(ALICE); let bob: AccountId = Rococo::account_id_of(BOB); @@ -202,6 +201,8 @@ fn create_and_claim_treasury_spend_in_usdt() { // create a conversion rate from `asset_kind` to the native currency. assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); + Dmp::make_parachain_reachable(1000); + // create and approve a treasury spend. assert_ok!(Treasury::spend( root, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs index aa0e183ecdda..ea210d4f3b65 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs @@ -16,10 +16,8 @@ //! Tests for XCM fee estimation in the runtime. use crate::imports::*; -use frame_support::{ - dispatch::RawOrigin, - sp_runtime::{traits::Dispatchable, DispatchResult}, -}; +use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees; +use frame_support::dispatch::RawOrigin; use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, @@ -76,16 +74,6 @@ fn receiver_assertions(test: ParaToParaThroughAHTest) { ); } -fn transfer_assets_para_to_para_through_ah_dispatchable( - test: ParaToParaThroughAHTest, -) -> DispatchResult { - let call = transfer_assets_para_to_para_through_ah_call(test.clone()); - match call.dispatch(test.signed_origin) { - Ok(_) => Ok(()), - Err(error_with_post_info) => Err(error_with_post_info.error), - } -} - fn transfer_assets_para_to_para_through_ah_call( test: ParaToParaThroughAHTest, ) -> ::RuntimeCall { @@ -100,7 +88,7 @@ fn transfer_assets_para_to_para_through_ah_call( dest: bx!(test.args.dest.into()), assets: bx!(test.args.assets.clone().into()), assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - remote_fees_id: bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))), + remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::new(1, [])))), fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), weight_limit: test.args.weight_limit, @@ -151,7 +139,7 @@ fn multi_hop_works() { // We get them from the PenpalA closure. let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); ::execute_with(|| { type Runtime = ::Runtime; type OriginCaller = ::OriginCaller; @@ -164,7 +152,7 @@ fn multi_hop_works() { .forwarded_xcms .iter() .find(|(destination, _)| { - *destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)])) + *destination == VersionedLocation::from(Location::new(1, [Parachain(1000)])) }) .unwrap(); assert_eq!(messages_to_query.len(), 1); @@ -178,7 +166,7 @@ fn multi_hop_works() { // These are set in the AssetHub closure. let mut intermediate_execution_fees = 0; let mut intermediate_delivery_fees_amount = 0; - let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); + let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new())); ::execute_with(|| { type Runtime = ::Runtime; type RuntimeCall = ::RuntimeCall; @@ -187,13 +175,14 @@ fn multi_hop_works() { let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); intermediate_execution_fees = Runtime::query_weight_to_asset_fee( weight, - VersionedAssetId::V4(Location::new(1, []).into()), + VersionedAssetId::from(AssetId(Location::new(1, []))), ) .unwrap(); // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. - let xcm_program = - VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + let xcm_program = VersionedXcm::from(Xcm::::from( + remote_message.clone().try_into().unwrap(), + )); // Now we get the delivery fees to the final destination. let result = @@ -202,7 +191,7 @@ fn multi_hop_works() { .forwarded_xcms .iter() .find(|(destination, _)| { - *destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)])) + *destination == VersionedLocation::from(Location::new(1, [Parachain(2001)])) }) .unwrap(); // There's actually two messages here. @@ -225,9 +214,11 @@ fn multi_hop_works() { type Runtime = ::Runtime; let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); - final_execution_fees = - Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) - .unwrap(); + final_execution_fees = Runtime::query_weight_to_asset_fee( + weight, + VersionedAssetId::from(AssetId(Location::parent())), + ) + .unwrap(); }); // Dry-running is done. @@ -257,7 +248,8 @@ fn multi_hop_works() { test.set_assertion::(sender_assertions); test.set_assertion::(hop_assertions); test.set_assertion::(receiver_assertions); - test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + test.set_call(call); test.assert(); let sender_assets_after = PenpalA::execute_with(|| { @@ -284,3 +276,14 @@ fn multi_hop_works() { final_execution_fees ); } + +#[test] +fn multi_hop_pay_fees_works() { + test_can_estimate_and_pay_exact_fees!( + PenpalA, + AssetHubRococo, + PenpalB, + (Parent, 1_000_000_000_000u128), + Penpal + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 872a8ffa6a8a..5cd00c239e60 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -11,34 +11,36 @@ publish = false workspace = true [dependencies] -codec = { workspace = true } assert_matches = { workspace = true } +codec = { workspace = true } # Substrate -sp-runtime = { workspace = true } -sp-core = { workspace = true } frame-metadata-hash-extension = { workspace = true, default-features = true } frame-support = { workspace = true } frame-system = { workspace = true } -pallet-balances = { workspace = true } -pallet-assets = { workspace = true } pallet-asset-conversion = { workspace = true } -pallet-treasury = { workspace = true } +pallet-asset-tx-payment = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } pallet-transaction-payment = { workspace = true } -pallet-asset-tx-payment = { workspace = true } +pallet-treasury = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } # Polkadot +pallet-xcm = { workspace = true } polkadot-runtime-common = { workspace = true, default-features = true } xcm = { workspace = true } +xcm-builder = { workspace = true } xcm-executor = { workspace = true } -pallet-xcm = { workspace = true } xcm-runtime-apis = { workspace = true } # Cumulus -parachains-common = { workspace = true, default-features = true } asset-test-utils = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true } +assets-common = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } westend-system-emulated-network = { workspace = true } 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 179a44e14aa1..36630e2d2221 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 @@ -26,7 +26,10 @@ mod imports { }; // Polkadot - pub use xcm::prelude::{AccountId32 as AccountId32Junction, *}; + pub use xcm::{ + latest::{AssetTransferFilter, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, + prelude::{AccountId32 as AccountId32Junction, *}, + }; pub use xcm_executor::traits::TransferType; // Cumulus @@ -42,7 +45,7 @@ mod imports { xcm_helpers::{ get_amount_from_versioned_assets, non_fee_asset, xcm_transact_paid_execution, }, - ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3, + ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, USDT_ID, XCM_V3, }; pub use parachains_common::{AccountId, Balance}; pub use westend_system_emulated_network::{ @@ -59,12 +62,16 @@ mod imports { genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, AssetHubWestendParaPallet as AssetHubWestendPallet, }, + bridge_hub_westend_emulated_chain::bridge_hub_westend_runtime::xcm_config::{ + self as bhw_xcm_config, + }, collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet, penpal_emulated_chain::{ penpal_runtime::xcm_config::{ CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + UniversalLocation as PenpalUniversalLocation, UsdtFromAssetHub as PenpalUsdtFromAssetHub, }, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, @@ -99,6 +106,7 @@ mod imports { pub type ParaToParaThroughRelayTest = Test; pub type ParaToParaThroughAHTest = Test; pub type RelayToParaThroughAHTest = Test; + pub type PenpalToRelayThroughAHTest = Test; } #[cfg(test)] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs index de58839634f1..a7f52eb7e09d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/claim_assets.rs @@ -17,7 +17,9 @@ use crate::imports::*; +use assets_common::runtime_api::runtime_decl_for_fungibles_api::FungiblesApiV2; use emulated_integration_tests_common::test_chain_can_claim_assets; +use frame_support::traits::fungible::Mutate; use xcm_executor::traits::DropAssets; #[test] @@ -25,5 +27,91 @@ fn assets_can_be_claimed() { let amount = AssetHubWestendExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(AssetHubWestend, RuntimeCall, NetworkId::Westend, assets, amount); + test_chain_can_claim_assets!( + AssetHubWestend, + RuntimeCall, + NetworkId::ByGenesis(WESTEND_GENESIS_HASH), + assets, + amount + ); +} + +#[test] +fn chain_can_claim_assets_for_its_users() { + // Many Penpal users have assets trapped in AssetHubWestend. + let beneficiaries: Vec<(Location, Assets)> = vec![ + // Some WND. + ( + Location::new(1, [Parachain(2000), AccountId32 { id: [0u8; 32], network: None }]), + (Parent, 10_000_000_000_000u128).into(), + ), + // Some USDT. + ( + Location::new(1, [Parachain(2000), AccountId32 { id: [1u8; 32], network: None }]), + ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())], 100_000_000u128) + .into(), + ), + ]; + + // Start with those assets trapped. + AssetHubWestend::execute_with(|| { + for (location, assets) in &beneficiaries { + ::PolkadotXcm::drop_assets( + location, + assets.clone().into(), + &XcmContext { origin: None, message_id: [0u8; 32], topic: None }, + ); + } + }); + + let penpal_to_asset_hub = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + let mut builder = Xcm::<()>::builder() + .withdraw_asset((Parent, 1_000_000_000_000u128)) + .pay_fees((Parent, 100_000_000_000u128)); + + // Loop through all beneficiaries. + for (location, assets) in &beneficiaries { + builder = builder.execute_with_origin( + // We take only the last part, the `AccountId32` junction. + Some((*location.interior().last().unwrap()).into()), + Xcm::<()>::builder_unsafe() + .claim_asset(assets.clone(), Location::new(0, [GeneralIndex(5)])) // Means lost assets were version 5. + .deposit_asset(assets.clone(), location.clone()) + .build(), + ) + } + + // Finish assembling the message. + let message = builder.build(); + + // Fund PenpalA's sovereign account on AssetHubWestend so it can pay for fees. + AssetHubWestend::execute_with(|| { + let penpal_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let penpal_sov_account_on_asset_hub = + AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_asset_hub); + type Balances = ::Balances; + assert_ok!(>::mint_into( + &penpal_sov_account_on_asset_hub, + 2_000_000_000_000u128, + )); + }); + + // We can send a message from Penpal root that claims all those assets for each beneficiary. + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + ::RuntimeOrigin::root(), + bx!(penpal_to_asset_hub.into()), + bx!(VersionedXcm::from(message)), + )); + }); + + // We assert beneficiaries have received their funds. + AssetHubWestend::execute_with(|| { + for (location, expected_assets) in &beneficiaries { + let sov_account = AssetHubWestend::sovereign_account_id_of(location.clone()); + let actual_assets = + ::Runtime::query_account_balances(sov_account).unwrap(); + assert_eq!(VersionedAssets::from(expected_assets.clone()), actual_assets); + } + }); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs index 9520659712fc..124ec2ec1f66 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs @@ -34,10 +34,9 @@ fn create_and_claim_treasury_spend() { let asset_hub_location = Location::new(1, [Parachain(AssetHubWestend::para_id().into())]); let root = ::RuntimeOrigin::root(); // asset kind to be spent from the treasury. - let asset_kind = VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into()), - }; + let asset_kind: VersionedLocatableAsset = + (asset_hub_location, AssetId((PalletInstance(50), GeneralIndex(USDT_ID.into())).into())) + .into(); // treasury spend beneficiary. let alice: AccountId = Westend::account_id_of(ALICE); let bob: AccountId = CollectivesWestend::account_id_of(BOB); 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 4d6cdd9a94d6..91ebdda16828 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 @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp; + use super::reserve_transfer::*; use crate::{ imports::*, @@ -163,7 +165,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { // Foreign asset used: bridged ROC let foreign_amount_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; let roc_at_westend_parachains = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]); + Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))]); // Configure destination chain to trust AH as reserve of ROC PenpalA::execute_with(|| { @@ -171,7 +173,7 @@ fn transfer_foreign_assets_from_asset_hub_to_para() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Rococo)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(), )], )); }); @@ -293,7 +295,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() { // Foreign asset used: bridged ROC let foreign_amount_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; let roc_at_westend_parachains = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]); + Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))]); // Configure destination chain to trust AH as reserve of ROC PenpalA::execute_with(|| { @@ -301,7 +303,7 @@ fn transfer_foreign_assets_from_para_to_asset_hub() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Rococo)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(), )], )); }); @@ -456,7 +458,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Rococo)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(), )], )); }); @@ -465,14 +467,14 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { ::RuntimeOrigin::root(), vec![( PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Rococo)]).encode(), + Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]).encode(), )], )); }); // Register ROC as foreign asset and transfer it around the Westend ecosystem let roc_at_westend_parachains = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Rococo)]); + Location::new(2, [Junction::GlobalConsensus(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))]); AssetHubWestend::force_create_foreign_asset( roc_at_westend_parachains.clone().try_into().unwrap(), assets_owner.clone(), @@ -658,13 +660,13 @@ fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explici } // =============================================================== -// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== +// ====== Transfer - Native Asset - Relay->AssetHub->Penpal ====== // =============================================================== -/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid +/// Transfers of native asset Relay to Penpal (using AssetHub reserve). Parachains want to avoid /// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their /// Sovereign Account on Asset Hub. #[test] -fn transfer_native_asset_from_relay_to_para_through_asset_hub() { +fn transfer_native_asset_from_relay_to_penpal_through_asset_hub() { // Init values for Relay let destination = Westend::child_location_of(PenpalA::para_id()); let sender = WestendSender::get(); @@ -778,6 +780,8 @@ fn transfer_native_asset_from_relay_to_para_through_asset_hub() { xcm: xcm_on_final_dest, }]); + Dmp::make_parachain_reachable(AssetHubWestend::para_id()); + // First leg is a teleport, from there a local-reserve-transfer to final dest ::XcmPallet::transfer_assets_using_type_and_then( t.signed_origin, @@ -819,3 +823,219 @@ fn transfer_native_asset_from_relay_to_para_through_asset_hub() { // should be non-zero assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } + +// =============================================================== +// ===== Transfer - Native Asset - Penpal->AssetHub->Relay ======= +// =============================================================== +/// Transfers of native asset Penpal to Relay (using AssetHub reserve). Parachains want to avoid +/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their +/// Sovereign Account on Asset Hub. +#[test] +fn transfer_native_asset_from_penpal_to_relay_through_asset_hub() { + // Init values for Penpal + let destination = RelayLocation::get(); + let sender = PenpalASender::get(); + let amount_to_send: Balance = WESTEND_ED * 100; + + // Init values for Penpal + let relay_native_asset_location = RelayLocation::get(); + let receiver = WestendReceiver::get(); + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + amount_to_send, + (Parent, amount_to_send).into(), + None, + 0, + ), + }; + let mut test = PenpalToRelayThroughAHTest::new(test_args); + + let sov_penpal_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + // fund Penpal's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + // fund Penpal's SA on AssetHub with the assets held in reserve + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ah.clone().into(), amount_to_send * 2)]); + + // prefund Relay checking account so we accept teleport "back" from AssetHub + let check_account = + Westend::execute_with(|| ::XcmPallet::check_account()); + Westend::fund_accounts(vec![(check_account, amount_to_send)]); + + // Query initial balances + let sender_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let sov_penpal_on_ah_before = AssetHubWestend::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah.clone()) + }); + let receiver_balance_before = Westend::execute_with(|| { + ::Balances::free_balance(receiver.clone()) + }); + + fn transfer_assets_dispatchable(t: PenpalToRelayThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + let context = PenpalUniversalLocation::get(); + + // reanchor fees to the view of destination (Westend Relay) + let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); + if let Fungible(ref mut amount) = remote_fees.fun { + // we already spent some fees along the way, just use half of what we started with + *amount = *amount / 2; + } + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, + DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }, + ]); + + // reanchor final dest (Westend Relay) to the view of hop (Asset Hub) + let mut dest = t.args.dest.clone(); + dest.reanchor(&asset_hub_location, &context).unwrap(); + // on Asset Hub + let xcm_on_hop = Xcm::<()>(vec![InitiateTeleport { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + dest, + xcm: xcm_on_final_dest, + }]); + + // First leg is a reserve-withdraw, from there a teleport to final dest + ::PolkadotXcm::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(asset_hub_location.into()), + bx!(t.args.assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(xcm_on_hop)), + t.args.weight_limit, + ) + } + test.set_dispatchable::(transfer_assets_dispatchable); + test.assert(); + + // Query final balances + let sender_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let sov_penpal_on_ah_after = AssetHubWestend::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah.clone()) + }); + let receiver_balance_after = Westend::execute_with(|| { + ::Balances::free_balance(receiver.clone()) + }); + + // Sender's asset balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // SA on AH balance is decreased by `amount_to_send` + assert_eq!(sov_penpal_on_ah_after, sov_penpal_on_ah_before - amount_to_send); + // Receiver's balance is increased + assert!(receiver_balance_after > receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_balance_after < receiver_balance_before + amount_to_send); +} + +// ============================================================================================== +// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Parachain<->AssetHub ==== +// ============================================================================================== +/// Transfers of native asset plus teleportable foreign asset from Parachain to AssetHub and back +/// with fees paid using native asset. +#[test] +fn bidirectional_transfer_multiple_assets_between_penpal_and_asset_hub() { + fn execute_xcm_penpal_to_asset_hub(t: ParaToSystemParaTest) -> DispatchResult { + let all_assets = t.args.assets.clone().into_inner(); + let mut assets = all_assets.clone(); + let mut fees = assets.remove(t.args.fee_asset_item as usize); + // TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get exact fees. + // For now just use half the fees locally, half on dest + if let Fungible(fees_amount) = fees.fun { + fees.fun = Fungible(fees_amount / 2); + } + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + // since this is the last hop, we don't need to further use any assets previously + // reserved for fees (there are no further hops to cover delivery fees for); we + // RefundSurplus to get back any unspent fees + RefundSurplus, + DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary }, + ]); + let xcm = Xcm::<()>(vec![ + WithdrawAsset(all_assets.into()), + PayFees { asset: fees.clone() }, + InitiateTransfer { + destination: t.args.dest, + remote_fees: Some(AssetTransferFilter::ReserveWithdraw(fees.into())), + preserve_origin: false, + assets: vec![AssetTransferFilter::Teleport(assets.into())], + remote_xcm: xcm_on_dest, + }, + ]); + ::PolkadotXcm::execute( + t.signed_origin, + bx!(xcm::VersionedXcm::from(xcm.into())), + Weight::MAX, + ) + .unwrap(); + Ok(()) + } + fn execute_xcm_asset_hub_to_penpal(t: SystemParaToParaTest) -> DispatchResult { + let all_assets = t.args.assets.clone().into_inner(); + let mut assets = all_assets.clone(); + let mut fees = assets.remove(t.args.fee_asset_item as usize); + // TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get exact fees. + // For now just use half the fees locally, half on dest + if let Fungible(fees_amount) = fees.fun { + fees.fun = Fungible(fees_amount / 2); + } + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + // since this is the last hop, we don't need to further use any assets previously + // reserved for fees (there are no further hops to cover delivery fees for); we + // RefundSurplus to get back any unspent fees + RefundSurplus, + DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary }, + ]); + let xcm = Xcm::<()>(vec![ + WithdrawAsset(all_assets.into()), + PayFees { asset: fees.clone() }, + InitiateTransfer { + destination: t.args.dest, + remote_fees: Some(AssetTransferFilter::ReserveDeposit(fees.into())), + preserve_origin: false, + assets: vec![AssetTransferFilter::Teleport(assets.into())], + remote_xcm: xcm_on_dest, + }, + ]); + ::PolkadotXcm::execute( + t.signed_origin, + bx!(xcm::VersionedXcm::from(xcm.into())), + Weight::MAX, + ) + .unwrap(); + Ok(()) + } + do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( + execute_xcm_penpal_to_asset_hub, + execute_xcm_asset_hub_to_penpal, + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index 73b73b239a1b..0dfe7a85f4c2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -18,8 +18,86 @@ mod fellowship_treasury; mod hybrid_transfers; mod reserve_transfer; mod send; +mod set_asset_claimer; mod set_xcm_versions; mod swap; mod teleport; +mod transact; mod treasury; mod xcm_fee_estimation; + +#[macro_export] +macro_rules! foreign_balance_on { + ( $chain:ident, $id:expr, $who:expr ) => { + emulated_integration_tests_common::impls::paste::paste! { + <$chain>::execute_with(|| { + type ForeignAssets = <$chain as [<$chain Pallet>]>::ForeignAssets; + >::balance($id, $who) + }) + } + }; +} + +#[macro_export] +macro_rules! create_pool_with_wnd_on { + ( $chain:ident, $asset_id:expr, $is_foreign:expr, $asset_owner:expr ) => { + emulated_integration_tests_common::impls::paste::paste! { + <$chain>::execute_with(|| { + type RuntimeEvent = <$chain as Chain>::RuntimeEvent; + let owner = $asset_owner; + let signed_owner = <$chain as Chain>::RuntimeOrigin::signed(owner.clone()); + let wnd_location: Location = Parent.into(); + if $is_foreign { + assert_ok!(<$chain as [<$chain Pallet>]>::ForeignAssets::mint( + signed_owner.clone(), + $asset_id.clone().into(), + owner.clone().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + } else { + let asset_id = match $asset_id.interior.last() { + Some(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + assert_ok!(<$chain as [<$chain Pallet>]>::Assets::mint( + signed_owner.clone(), + asset_id.into(), + owner.clone().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + } + + assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::create_pool( + signed_owner.clone(), + Box::new(wnd_location.clone()), + Box::new($asset_id.clone()), + )); + + assert_expected_events!( + $chain, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity( + signed_owner, + Box::new(wnd_location), + Box::new($asset_id), + 1_000_000_000_000, + 2_000_000_000_000, // $asset_id is worth half of wnd + 0, + 0, + owner.into() + )); + + assert_expected_events!( + $chain, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + } + }; +} 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 10c27c338ec7..dc36fed42932 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 @@ -13,8 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::imports::*; +use crate::{create_pool_with_wnd_on, foreign_balance_on, imports::*}; use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; +use westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -115,7 +116,7 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubWestend, vec![ - // Transport fees are paid + // Delivery fees are paid RuntimeEvent::PolkadotXcm(pallet_xcm::Event::FeesPaid { .. }) => {}, ] ); @@ -274,7 +275,7 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { t.args.dest.clone() ), }, - // Transport fees are paid + // Delivery fees are paid RuntimeEvent::PolkadotXcm( pallet_xcm::Event::FeesPaid { .. } ) => {}, @@ -305,7 +306,7 @@ fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { owner: *owner == t.sender.account_id, balance: *balance == t.args.amount, }, - // Transport fees are paid + // Delivery fees are paid RuntimeEvent::PolkadotXcm( pallet_xcm::Event::FeesPaid { .. } ) => {}, @@ -487,6 +488,11 @@ pub fn para_to_para_through_hop_receiver_assertions(t: Test DispatchResult { + let Junction::Parachain(para_id) = *t.args.dest.chain_location().last().unwrap() else { + unimplemented!("Destination is not a parachain?") + }; + + Dmp::make_parachain_reachable(para_id); ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -533,6 +539,13 @@ fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> Dispa fn para_to_para_through_relay_limited_reserve_transfer_assets( t: ParaToParaThroughRelayTest, ) -> DispatchResult { + let Junction::Parachain(para_id) = *t.args.dest.chain_location().last().unwrap() else { + unimplemented!("Destination is not a parachain?") + }; + + Westend::ext_wrapper(|| { + Dmp::make_parachain_reachable(para_id); + }); ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -651,10 +664,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() { // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); + let receiver_assets_before = + foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &receiver); // Set assertions and dispatchables test.set_assertion::(relay_to_para_sender_assertions); @@ -664,10 +675,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() { // Query final balances let sender_balance_after = test.sender.balance; - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); + let receiver_assets_after = + foreign_balance_on!(PenpalA, relay_native_asset_location, &receiver); // Sender's balance is reduced by amount sent plus delivery fees assert!(sender_balance_after < sender_balance_before - amount_to_send); @@ -722,10 +731,8 @@ fn reserve_transfer_native_asset_from_para_to_relay() { let mut test = ParaToRelayTest::new(test_args); // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); + let sender_assets_before = + foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &sender); let receiver_balance_before = test.receiver.balance; // Set assertions and dispatchables @@ -735,10 +742,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { test.assert(); // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &sender) - }); + let sender_assets_after = foreign_balance_on!(PenpalA, relay_native_asset_location, &sender); let receiver_balance_after = test.receiver.balance; // Sender's balance is reduced by amount sent plus delivery fees @@ -784,10 +788,8 @@ fn reserve_transfer_native_asset_from_asset_hub_to_para() { // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); + let receiver_assets_before = + foreign_balance_on!(PenpalA, system_para_native_asset_location.clone(), &receiver); // Set assertions and dispatchables test.set_assertion::(system_para_to_para_sender_assertions); @@ -797,10 +799,8 @@ fn reserve_transfer_native_asset_from_asset_hub_to_para() { // Query final balances let sender_balance_after = test.sender.balance; - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &receiver) - }); + let receiver_assets_after = + foreign_balance_on!(PenpalA, system_para_native_asset_location, &receiver); // Sender's balance is reduced by amount sent plus delivery fees assert!(sender_balance_after < sender_balance_before - amount_to_send); @@ -856,10 +856,8 @@ fn reserve_transfer_native_asset_from_para_to_asset_hub() { let mut test = ParaToSystemParaTest::new(test_args); // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &sender) - }); + let sender_assets_before = + foreign_balance_on!(PenpalA, system_para_native_asset_location.clone(), &sender); let receiver_balance_before = test.receiver.balance; // Set assertions and dispatchables @@ -869,10 +867,8 @@ fn reserve_transfer_native_asset_from_para_to_asset_hub() { test.assert(); // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &sender) - }); + let sender_assets_after = + foreign_balance_on!(PenpalA, system_para_native_asset_location, &sender); let receiver_balance_after = test.receiver.balance; // Sender's balance is reduced by amount sent plus delivery fees @@ -950,17 +946,10 @@ fn reserve_transfer_multiple_assets_from_asset_hub_to_para() { type Assets = ::Assets; >::balance(RESERVABLE_ASSET_ID, &sender) }); - let receiver_system_native_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - let receiver_foreign_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_foreign_asset_location.clone(), - &receiver, - ) - }); + let receiver_system_native_assets_before = + foreign_balance_on!(PenpalA, system_para_native_asset_location.clone(), &receiver); + let receiver_foreign_assets_before = + foreign_balance_on!(PenpalA, system_para_foreign_asset_location.clone(), &receiver); // Set assertions and dispatchables test.set_assertion::(system_para_to_para_assets_sender_assertions); @@ -974,14 +963,10 @@ fn reserve_transfer_multiple_assets_from_asset_hub_to_para() { type Assets = ::Assets; >::balance(RESERVABLE_ASSET_ID, &sender) }); - let receiver_system_native_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &receiver) - }); - let receiver_foreign_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location, &receiver) - }); + let receiver_system_native_assets_after = + foreign_balance_on!(PenpalA, system_para_native_asset_location, &receiver); + let receiver_foreign_assets_after = + foreign_balance_on!(PenpalA, system_para_foreign_asset_location.clone(), &receiver); // Sender's balance is reduced assert!(sender_balance_after < sender_balance_before); // Receiver's foreign asset balance is increased @@ -1082,14 +1067,10 @@ fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { let mut test = ParaToSystemParaTest::new(para_test_args); // Query initial balances - let sender_system_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_asset_location_on_penpal.clone(), &sender) - }); - let sender_foreign_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(asset_location_on_penpal.clone(), &sender) - }); + let sender_system_assets_before = + foreign_balance_on!(PenpalA, system_asset_location_on_penpal.clone(), &sender); + let sender_foreign_assets_before = + foreign_balance_on!(PenpalA, asset_location_on_penpal.clone(), &sender); let receiver_balance_before = test.receiver.balance; let receiver_assets_before = AssetHubWestend::execute_with(|| { type Assets = ::Assets; @@ -1103,14 +1084,10 @@ fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { test.assert(); // Query final balances - let sender_system_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_asset_location_on_penpal, &sender) - }); - let sender_foreign_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(asset_location_on_penpal, &sender) - }); + let sender_system_assets_after = + foreign_balance_on!(PenpalA, system_asset_location_on_penpal, &sender); + let sender_foreign_assets_after = + foreign_balance_on!(PenpalA, asset_location_on_penpal, &sender); let receiver_balance_after = test.receiver.balance; let receiver_assets_after = AssetHubWestend::execute_with(|| { type Assets = ::Assets; @@ -1171,14 +1148,10 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() { let mut test = ParaToParaThroughRelayTest::new(test_args); // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); + let sender_assets_before = + foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &sender); + let receiver_assets_before = + foreign_balance_on!(PenpalB, relay_native_asset_location.clone(), &receiver); // Set assertions and dispatchables test.set_assertion::(para_to_para_through_hop_sender_assertions); @@ -1188,14 +1161,10 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() { test.assert(); // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); + let sender_assets_after = + foreign_balance_on!(PenpalA, relay_native_asset_location.clone(), &sender); + let receiver_assets_after = + foreign_balance_on!(PenpalB, relay_native_asset_location, &receiver); // Sender's balance is reduced by amount sent plus delivery fees. assert!(sender_assets_after < sender_assets_before - amount_to_send); @@ -1231,55 +1200,11 @@ fn reserve_transfer_usdt_from_asset_hub_to_para() { )); }); - let relay_asset_penpal_pov = RelayLocation::get(); - let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); - // Setup the pool between `relay_asset_penpal_pov` and `usdt_from_asset_hub` on PenpalA. // So we can swap the custom asset that comes from AssetHubWestend for native asset to pay for // fees. - PenpalA::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), - usdt_from_asset_hub.clone().into(), - PenpalASender::get().into(), - 10_000_000_000_000, // For it to have more than enough. - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(PenpalASender::get()), - Box::new(relay_asset_penpal_pov.clone()), - Box::new(usdt_from_asset_hub.clone()), - )); - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(PenpalASender::get()), - Box::new(relay_asset_penpal_pov), - Box::new(usdt_from_asset_hub.clone()), - // `usdt_from_asset_hub` is worth a third of `relay_asset_penpal_pov` - 1_000_000_000_000, - 3_000_000_000_000, - 0, - 0, - PenpalASender::get().into() - )); - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, - ] - ); - }); + create_pool_with_wnd_on!(PenpalA, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get()); let assets: Assets = vec![( [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(usdt_id.into())], @@ -1310,10 +1235,8 @@ fn reserve_transfer_usdt_from_asset_hub_to_para() { type Balances = ::Balances; Balances::free_balance(&sender) }); - let receiver_initial_balance = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(usdt_from_asset_hub.clone(), &receiver) - }); + let receiver_initial_balance = + foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &receiver); test.set_assertion::(system_para_to_para_sender_assertions); test.set_assertion::(system_para_to_para_receiver_assertions); @@ -1328,10 +1251,7 @@ fn reserve_transfer_usdt_from_asset_hub_to_para() { type Balances = ::Balances; Balances::free_balance(&sender) }); - let receiver_after_balance = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(usdt_from_asset_hub, &receiver) - }); + let receiver_after_balance = foreign_balance_on!(PenpalA, usdt_from_asset_hub, &receiver); // TODO(https://github.com/paritytech/polkadot-sdk/issues/5160): When we allow payment with different assets locally, this should be the same, since // they aren't used for fees. @@ -1371,7 +1291,7 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { ]); // Give USDT to sov account of sender. - let usdt_id = 1984; + let usdt_id: u32 = 1984; AssetHubWestend::execute_with(|| { use frame_support::traits::tokens::fungibles::Mutate; type Assets = ::Assets; @@ -1383,101 +1303,15 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { }); // We create a pool between WND and USDT in AssetHub. - let native_asset: Location = Parent.into(); let usdt = Location::new( 0, [Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(usdt_id.into())], ); - - // set up pool with USDT <> native pair - AssetHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - usdt_id.into(), - AssetHubWestendSender::get().into(), - 10_000_000_000_000, // For it to have more than enough. - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(native_asset.clone()), - Box::new(usdt.clone()), - )); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(native_asset), - Box::new(usdt), - 1_000_000_000_000, - 2_000_000_000_000, // usdt is worth half of `native_asset` - 0, - 0, - AssetHubWestendSender::get().into() - )); - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, - ] - ); - }); - - let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); - + create_pool_with_wnd_on!(AssetHubWestend, usdt, false, AssetHubWestendSender::get()); // We also need a pool between WND and USDT on PenpalB. - PenpalB::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - let relay_asset = RelayLocation::get(); - - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), - usdt_from_asset_hub.clone().into(), - PenpalBReceiver::get().into(), - 10_000_000_000_000, // For it to have more than enough. - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(PenpalBReceiver::get()), - Box::new(relay_asset.clone()), - Box::new(usdt_from_asset_hub.clone()), - )); - - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(PenpalBReceiver::get()), - Box::new(relay_asset), - Box::new(usdt_from_asset_hub.clone()), - 1_000_000_000_000, - 2_000_000_000_000, // `usdt_from_asset_hub` is worth half of `relay_asset` - 0, - 0, - PenpalBReceiver::get().into() - )); - - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, - ] - ); - }); + create_pool_with_wnd_on!(PenpalB, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get()); + let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); PenpalA::execute_with(|| { use frame_support::traits::tokens::fungibles::Mutate; type ForeignAssets = ::ForeignAssets; @@ -1523,14 +1357,9 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { let mut test = ParaToParaThroughAHTest::new(test_args); // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(usdt_from_asset_hub.clone(), &sender) - }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(usdt_from_asset_hub.clone(), &receiver) - }); + let sender_assets_before = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender); + let receiver_assets_before = + foreign_balance_on!(PenpalB, usdt_from_asset_hub.clone(), &receiver); test.set_assertion::(para_to_para_through_hop_sender_assertions); test.set_assertion::(para_to_para_asset_hub_hop_assertions); test.set_assertion::(para_to_para_through_hop_receiver_assertions); @@ -1540,14 +1369,8 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { test.assert(); // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(usdt_from_asset_hub.clone(), &sender) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(usdt_from_asset_hub, &receiver) - }); + let sender_assets_after = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender); + let receiver_assets_after = foreign_balance_on!(PenpalB, usdt_from_asset_hub, &receiver); // Sender's balance is reduced by amount assert!(sender_assets_after < sender_assets_before - asset_amount_to_send); @@ -1603,7 +1426,7 @@ fn reserve_withdraw_from_untrusted_reserve_fails() { ]); let result = ::PolkadotXcm::execute( signed_origin, - bx!(xcm::VersionedXcm::V4(xcm)), + bx!(xcm::VersionedXcm::from(xcm)), Weight::MAX, ); assert!(result.is_err()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index 761c7c12255c..d4f239df4877 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -24,7 +24,7 @@ fn send_transact_as_superuser_from_relay_to_asset_hub_works() { ASSET_MIN_BALANCE, true, AssetHubWestendSender::get().into(), - Some(Weight::from_parts(1_019_445_000, 200_000)), + Some(Weight::from_parts(144_759_000, 3675)), ) } @@ -121,7 +121,7 @@ fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() { ASSET_MIN_BALANCE, true, para_sovereign_account.clone(), - Some(Weight::from_parts(1_019_445_000, 200_000)), + Some(Weight::from_parts(144_759_000, 3675)), ASSET_MIN_BALANCE * 1000000000, ); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs new file mode 100644 index 000000000000..bc00106b47c1 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_asset_claimer.rs @@ -0,0 +1,154 @@ +// 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. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::{bhw_xcm_config::LocationToAccountId, *}; +use emulated_integration_tests_common::{ + accounts::{ALICE, BOB}, + impls::AccountId32, +}; +use frame_support::{assert_ok, sp_runtime::traits::Dispatchable}; +use westend_system_emulated_network::{ + asset_hub_westend_emulated_chain::asset_hub_westend_runtime::RuntimeOrigin as AssetHubRuntimeOrigin, + bridge_hub_westend_emulated_chain::bridge_hub_westend_runtime::RuntimeOrigin as BridgeHubRuntimeOrigin, +}; +use xcm_executor::traits::ConvertLocation; + +#[test] +fn test_set_asset_claimer_within_a_chain() { + let (alice_account, _) = account_and_location(ALICE); + let (bob_account, bob_location) = account_and_location(BOB); + + let trap_amount = 16_000_000_000_000; + let assets: Assets = (Parent, trap_amount).into(); + + let alice_balance_before = + ::account_data_of(alice_account.clone()).free; + AssetHubWestend::fund_accounts(vec![(alice_account.clone(), trap_amount * 2)]); + let alice_balance_after = + ::account_data_of(alice_account.clone()).free; + assert_eq!(alice_balance_after - alice_balance_before, trap_amount * 2); + + type RuntimeCall = ::RuntimeCall; + let asset_trap_xcm = Xcm::::builder_unsafe() + .set_hints(vec![AssetClaimer { location: bob_location.clone() }]) + .withdraw_asset(assets.clone()) + .clear_origin() + .build(); + + AssetHubWestend::execute_with(|| { + assert_ok!(RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute { + message: bx!(VersionedXcm::from(asset_trap_xcm)), + max_weight: Weight::from_parts(4_000_000_000_000, 300_000), + }) + .dispatch(AssetHubRuntimeOrigin::signed(alice_account.clone()))); + }); + + let balance_after_trap = + ::account_data_of(alice_account.clone()).free; + assert_eq!(alice_balance_after - balance_after_trap, trap_amount); + + let bob_balance_before = ::account_data_of(bob_account.clone()).free; + let claim_xcm = Xcm::::builder_unsafe() + .claim_asset(assets.clone(), Here) + .deposit_asset(AllCounted(assets.len() as u32), bob_location.clone()) + .build(); + + AssetHubWestend::execute_with(|| { + assert_ok!(RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute { + message: bx!(VersionedXcm::from(claim_xcm)), + max_weight: Weight::from_parts(4_000_000_000_000, 300_000), + }) + .dispatch(AssetHubRuntimeOrigin::signed(bob_account.clone()))); + }); + + let bob_balance_after = ::account_data_of(bob_account.clone()).free; + assert_eq!(bob_balance_after - bob_balance_before, trap_amount); +} + +fn account_and_location(account: &str) -> (AccountId32, Location) { + let account_id = AssetHubWestend::account_id_of(account); + let account_clone = account_id.clone(); + let location: Location = [Junction::AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: account_id.into(), + }] + .into(); + (account_clone, location) +} + +// The test: +// 1. Funds Bob account on BridgeHub, withdraws the funds, sets asset claimer to +// sibling-account-of(AssetHub/Alice) and traps the funds. +// 2. Alice on AssetHub sends an XCM to BridgeHub to claim assets, pay fees and deposit +// remaining to her sibling account on BridgeHub. +#[test] +fn test_set_asset_claimer_between_the_chains() { + let alice = AssetHubWestend::account_id_of(ALICE); + let alice_bh_sibling = Location::new( + 1, + [ + Parachain(AssetHubWestend::para_id().into()), + Junction::AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: alice.clone().into(), + }, + ], + ); + + let bob = BridgeHubWestend::account_id_of(BOB); + let trap_amount = 16_000_000_000_000u128; + BridgeHubWestend::fund_accounts(vec![(bob.clone(), trap_amount * 2)]); + + let assets: Assets = (Parent, trap_amount).into(); + type RuntimeCall = ::RuntimeCall; + let trap_xcm = Xcm::::builder_unsafe() + .set_hints(vec![AssetClaimer { location: alice_bh_sibling.clone() }]) + .withdraw_asset(assets.clone()) + .clear_origin() + .build(); + + BridgeHubWestend::execute_with(|| { + assert_ok!(RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute { + message: bx!(VersionedXcm::from(trap_xcm)), + max_weight: Weight::from_parts(4_000_000_000_000, 700_000), + }) + .dispatch(BridgeHubRuntimeOrigin::signed(bob.clone()))); + }); + + let alice_bh_acc = LocationToAccountId::convert_location(&alice_bh_sibling).unwrap(); + let balance = ::account_data_of(alice_bh_acc.clone()).free; + assert_eq!(balance, 0); + + let pay_fees = 6_000_000_000_000u128; + let xcm_on_bh = Xcm::<()>::builder_unsafe() + .claim_asset(assets.clone(), Here) + .pay_fees((Parent, pay_fees)) + .deposit_asset(All, alice_bh_sibling.clone()) + .build(); + let bh_on_ah = AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()).into(); + AssetHubWestend::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + AssetHubRuntimeOrigin::signed(alice.clone()), + bx!(bh_on_ah), + bx!(VersionedXcm::from(xcm_on_bh)), + )); + }); + + let alice_bh_acc = LocationToAccountId::convert_location(&alice_bh_sibling).unwrap(); + let balance = ::account_data_of(alice_bh_acc).free; + assert_eq!(balance, trap_amount - pay_fees); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs index 474e9a86ccc2..4405ed2988a9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs @@ -67,10 +67,7 @@ fn system_para_sets_relay_xcm_supported_version() { AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts( - 1_019_210_000, - 200_000, - ))); + AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(115_688_000, 0))); assert_expected_events!( AssetHubWestend, 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 ee0f297792f8..0897c187e7cb 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 @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::imports::*; +use crate::{foreign_balance_on, imports::*}; fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Westend::assert_ump_queue_processed( @@ -112,16 +112,6 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { assert_expected_events!( AssetHubWestend, vec![ - // native asset used for fees is transferred to Parachain's Sovereign account as reserve - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubWestend::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, // foreign asset is burned locally as part of teleportation RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { asset_id: *asset_id == expected_foreign_asset_id, @@ -283,13 +273,13 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult, ) { // Init values for Parachain - let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 100; + let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); let asset_id_on_penpal = match asset_location_on_penpal.last() { Some(Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; - let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100; + let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 1000; let asset_owner = PenpalAssetOwner::get(); let system_para_native_asset_location = RelayLocation::get(); let sender = PenpalASender::get(); @@ -318,7 +308,7 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using ::RuntimeOrigin::signed(asset_owner.clone()), asset_id_on_penpal, sender.clone(), - asset_amount_to_send, + asset_amount_to_send * 2, ); // fund Parachain's check account to be able to teleport PenpalA::fund_accounts(vec![( @@ -335,7 +325,7 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using )]); // Init values for System Parachain - let foreign_asset_at_asset_hub_westend = + let foreign_asset_at_asset_hub = Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); @@ -355,13 +345,11 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using ), }; let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); - let penpal_sender_balance_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalASender::get(), - ) - }); + let penpal_sender_balance_before = foreign_balance_on!( + PenpalA, + system_para_native_asset_location.clone(), + &PenpalASender::get() + ); let ah_receiver_balance_before = penpal_to_ah.receiver.balance; @@ -369,26 +357,22 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using type Assets = ::Assets; >::balance(asset_id_on_penpal, &PenpalASender::get()) }); - let ah_receiver_assets_before = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(), - &AssetHubWestendReceiver::get(), - ) - }); + let ah_receiver_assets_before = foreign_balance_on!( + AssetHubWestend, + foreign_asset_at_asset_hub.clone(), + &AssetHubWestendReceiver::get() + ); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); penpal_to_ah.set_dispatchable::(para_to_ah_dispatchable); penpal_to_ah.assert(); - let penpal_sender_balance_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalASender::get(), - ) - }); + let penpal_sender_balance_after = foreign_balance_on!( + PenpalA, + system_para_native_asset_location.clone(), + &PenpalASender::get() + ); let ah_receiver_balance_after = penpal_to_ah.receiver.balance; @@ -396,13 +380,11 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using type Assets = ::Assets; >::balance(asset_id_on_penpal, &PenpalASender::get()) }); - let ah_receiver_assets_after = AssetHubWestend::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(), - &AssetHubWestendReceiver::get(), - ) - }); + let ah_receiver_assets_after = foreign_balance_on!( + AssetHubWestend, + foreign_asset_at_asset_hub.clone(), + &AssetHubWestendReceiver::get() + ); // Sender's balance is reduced assert!(penpal_sender_balance_after < penpal_sender_balance_before); @@ -427,17 +409,21 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using type ForeignAssets = ::ForeignAssets; assert_ok!(ForeignAssets::transfer( ::RuntimeOrigin::signed(AssetHubWestendReceiver::get()), - foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(), + foreign_asset_at_asset_hub.clone().try_into().unwrap(), AssetHubWestendSender::get().into(), asset_amount_to_send, )); }); + // Only send back half the amount. + let asset_amount_to_send = asset_amount_to_send / 2; + let fee_amount_to_send = fee_amount_to_send / 2; + let ah_to_penpal_beneficiary_id = PenpalAReceiver::get(); let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let ah_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - (foreign_asset_at_asset_hub_westend.clone(), asset_amount_to_send).into(), + (foreign_asset_at_asset_hub.clone(), asset_amount_to_send).into(), ] .into(); let fee_asset_index = ah_assets @@ -462,21 +448,17 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); let ah_sender_balance_before = ah_to_penpal.sender.balance; - let penpal_receiver_balance_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalAReceiver::get(), - ) - }); + let penpal_receiver_balance_before = foreign_balance_on!( + PenpalA, + system_para_native_asset_location.clone(), + &PenpalAReceiver::get() + ); - let ah_sender_assets_before = AssetHubWestend::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(), - &AssetHubWestendSender::get(), - ) - }); + let ah_sender_assets_before = foreign_balance_on!( + AssetHubWestend, + foreign_asset_at_asset_hub.clone(), + &AssetHubWestendSender::get() + ); let penpal_receiver_assets_before = PenpalA::execute_with(|| { type Assets = ::Assets; >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) @@ -488,21 +470,14 @@ pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using ah_to_penpal.assert(); let ah_sender_balance_after = ah_to_penpal.sender.balance; - let penpal_receiver_balance_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location, - &PenpalAReceiver::get(), - ) - }); + let penpal_receiver_balance_after = + foreign_balance_on!(PenpalA, system_para_native_asset_location, &PenpalAReceiver::get()); - let ah_sender_assets_after = AssetHubWestend::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_westend.clone().try_into().unwrap(), - &AssetHubWestendSender::get(), - ) - }); + let ah_sender_assets_after = foreign_balance_on!( + AssetHubWestend, + foreign_asset_at_asset_hub.clone(), + &AssetHubWestendSender::get() + ); let penpal_receiver_assets_after = PenpalA::execute_with(|| { type Assets = ::Assets; >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) @@ -577,7 +552,7 @@ fn teleport_to_untrusted_chain_fails() { ]); let result = ::PolkadotXcm::execute( signed_origin, - bx!(xcm::VersionedXcm::V4(xcm)), + bx!(xcm::VersionedXcm::from(xcm)), Weight::MAX, ); assert!(result.is_err()); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs new file mode 100644 index 000000000000..7e881a332a53 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/transact.rs @@ -0,0 +1,246 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{create_pool_with_wnd_on, foreign_balance_on, imports::*}; +use frame_support::traits::tokens::fungibles::Mutate; +use xcm_builder::{DescribeAllTerminal, DescribeFamily, HashedDescription}; +use xcm_executor::traits::ConvertLocation; + +/// PenpalA transacts on PenpalB, paying fees using USDT. XCM has to go through Asset Hub as the +/// reserve location of USDT. The original origin `PenpalA/PenpalASender` is proxied by Asset Hub. +fn transfer_and_transact_in_same_xcm( + destination: Location, + usdt: Asset, + beneficiary: Location, + call: xcm::DoubleEncoded<()>, +) { + let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get().into()); + let context = PenpalUniversalLocation::get(); + let asset_hub_location = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + + let Fungible(total_usdt) = usdt.fun else { unreachable!() }; + + // TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get local fees, for now use hardcoded value. + let local_fees_amount = 80_000_000_000; // current exact value 69_200_786_622 + let ah_fees_amount = 90_000_000_000; // current exact value 79_948_099_299 + let usdt_to_ah_then_onward_amount = total_usdt - local_fees_amount - ah_fees_amount; + + let local_fees: Asset = (usdt.id.clone(), local_fees_amount).into(); + let fees_for_ah: Asset = (usdt.id.clone(), ah_fees_amount).into(); + let usdt_to_ah_then_onward: Asset = (usdt.id.clone(), usdt_to_ah_then_onward_amount).into(); + + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + Transact { origin_kind: OriginKind::Xcm, call, fallback_max_weight: None }, + ExpectTransactStatus(MaybeErrorCode::Success), + // since this is the last hop, we don't need to further use any assets previously + // reserved for fees (there are no further hops to cover delivery fees for); we + // RefundSurplus to get back any unspent fees + RefundSurplus, + DepositAsset { assets: Wild(All), beneficiary }, + ]); + let destination = destination.reanchored(&asset_hub_location, &context).unwrap(); + let xcm_on_ah = Xcm(vec![InitiateTransfer { + destination, + remote_fees: Some(AssetTransferFilter::ReserveDeposit(Wild(All))), + preserve_origin: true, + assets: vec![], + remote_xcm: xcm_on_dest, + }]); + let xcm = Xcm::<()>(vec![ + WithdrawAsset(usdt.into()), + PayFees { asset: local_fees }, + InitiateTransfer { + destination: asset_hub_location, + remote_fees: Some(AssetTransferFilter::ReserveWithdraw(fees_for_ah.into())), + preserve_origin: true, + assets: vec![AssetTransferFilter::ReserveWithdraw(usdt_to_ah_then_onward.into())], + remote_xcm: xcm_on_ah, + }, + ]); + ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::from(xcm.into())), + Weight::MAX, + ) + .unwrap(); +} + +/// PenpalA transacts on PenpalB, paying fees using USDT. XCM has to go through Asset Hub as the +/// reserve location of USDT. The original origin `PenpalA/PenpalASender` is proxied by Asset Hub. +#[test] +fn transact_from_para_to_para_through_asset_hub() { + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let fee_amount_to_send: Balance = WESTEND_ED * 10000; + let sender_chain_as_seen_by_asset_hub = + AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_asset_hub = + AssetHubWestend::sovereign_account_id_of(sender_chain_as_seen_by_asset_hub); + let receiver_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_asset_hub = + AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_asset_hub); + + // Create SA-of-Penpal-on-AHW with ED. + AssetHubWestend::fund_accounts(vec![ + (sov_of_sender_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED), + (sov_of_receiver_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED), + ]); + + // Prefund USDT to sov account of sender. + AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + assert_ok!(>::mint_into( + USDT_ID, + &sov_of_sender_on_asset_hub.clone().into(), + fee_amount_to_send, + )); + }); + + // We create a pool between WND and USDT in AssetHub. + let usdt = Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]); + create_pool_with_wnd_on!(AssetHubWestend, usdt, false, AssetHubWestendSender::get()); + // We also need a pool between WND and USDT on PenpalA. + create_pool_with_wnd_on!(PenpalA, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get()); + // We also need a pool between WND and USDT on PenpalB. + create_pool_with_wnd_on!(PenpalB, PenpalUsdtFromAssetHub::get(), true, PenpalAssetOwner::get()); + + let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); + PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + assert_ok!(>::mint_into( + usdt_from_asset_hub.clone(), + &sender, + fee_amount_to_send, + )); + }); + + // Give the sender enough Relay tokens to pay for local delivery fees. + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + RelayLocation::get(), + sender.clone(), + 10_000_000_000_000, // Large estimate to make sure it works. + ); + + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); + + // Query initial balances + let sender_assets_before = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender); + let receiver_assets_before = + foreign_balance_on!(PenpalB, usdt_from_asset_hub.clone(), &receiver); + + // Now register a new asset on PenpalB from PenpalA/sender account while paying fees using USDT + // (going through Asset Hub) + + let usdt_to_send: Asset = (usdt_from_asset_hub.clone(), fee_amount_to_send).into(); + let assets: Assets = usdt_to_send.clone().into(); + let asset_location_on_penpal_a = + Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())]); + let penpal_a_as_seen_by_penpal_b = PenpalB::sibling_location_of(PenpalA::para_id()); + let sender_as_seen_by_penpal_b = + penpal_a_as_seen_by_penpal_b.clone().appended_with(sender.clone()).unwrap(); + let foreign_asset_at_penpal_b = + penpal_a_as_seen_by_penpal_b.appended_with(asset_location_on_penpal_a).unwrap(); + // Encoded `create_asset` call to be executed in PenpalB + let call = PenpalB::create_foreign_asset_call( + foreign_asset_at_penpal_b.clone(), + ASSET_MIN_BALANCE, + receiver.clone(), + ); + PenpalA::execute_with(|| { + // initiate transaction + transfer_and_transact_in_same_xcm(destination, usdt_to_send, receiver.clone().into(), call); + + // verify expected events; + PenpalA::assert_xcm_pallet_attempted_complete(None); + }); + AssetHubWestend::execute_with(|| { + let sov_penpal_a_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + asset_hub_hop_assertions(&assets, sov_penpal_a_on_ah, sov_penpal_b_on_ah); + }); + PenpalB::execute_with(|| { + let expected_creator = + HashedDescription::>::convert_location( + &sender_as_seen_by_penpal_b, + ) + .unwrap(); + penpal_b_assertions(foreign_asset_at_penpal_b, expected_creator, receiver.clone()); + }); + + // Query final balances + let sender_assets_after = foreign_balance_on!(PenpalA, usdt_from_asset_hub.clone(), &sender); + let receiver_assets_after = foreign_balance_on!(PenpalB, usdt_from_asset_hub, &receiver); + + // Sender's balance is reduced by amount + assert_eq!(sender_assets_after, sender_assets_before - fee_amount_to_send); + // Receiver's balance is increased + assert!(receiver_assets_after > receiver_assets_before); +} + +fn asset_hub_hop_assertions(assets: &Assets, sender_sa: AccountId, receiver_sa: AccountId) { + type RuntimeEvent = ::RuntimeEvent; + for asset in assets.inner() { + let amount = if let Fungible(a) = asset.fun { a } else { unreachable!() }; + assert_expected_events!( + AssetHubWestend, + vec![ + // Withdrawn from sender parachain SA + RuntimeEvent::Assets( + pallet_assets::Event::Burned { owner, balance, .. } + ) => { + owner: *owner == sender_sa, + balance: *balance == amount, + }, + // Deposited to receiver parachain SA + RuntimeEvent::Assets( + pallet_assets::Event::Deposited { who, .. } + ) => { + who: *who == receiver_sa, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } +} + +fn penpal_b_assertions( + expected_asset: Location, + expected_creator: AccountId, + expected_owner: AccountId, +) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcmp_queue_success(None); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Created { asset_id, creator, owner } + ) => { + asset_id: *asset_id == expected_asset, + creator: *creator == expected_creator, + owner: *owner == expected_owner, + }, + ] + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs index b70967184387..3b53557fc05c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs @@ -20,6 +20,7 @@ use emulated_integration_tests_common::{ }; use frame_support::traits::fungibles::{Inspect, Mutate}; use polkadot_runtime_common::impls::VersionedLocatableAsset; +use westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp; use xcm_executor::traits::ConvertLocation; #[test] @@ -32,11 +33,10 @@ fn create_and_claim_treasury_spend() { ahw_xcm_config::LocationToAccountId::convert_location(&treasury_location).unwrap(); let asset_hub_location = Location::new(0, Parachain(AssetHubWestend::para_id().into())); let root = ::RuntimeOrigin::root(); - // asset kind to be spend from the treasury. - let asset_kind = VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: AssetId([PalletInstance(50), GeneralIndex(USDT_ID.into())].into()), - }; + // asset kind to be spent from the treasury. + let asset_kind: VersionedLocatableAsset = + (asset_hub_location, AssetId([PalletInstance(50), GeneralIndex(USDT_ID.into())].into())) + .into(); // treasury spend beneficiary. let alice: AccountId = Westend::account_id_of(ALICE); let bob: AccountId = Westend::account_id_of(BOB); @@ -59,6 +59,8 @@ fn create_and_claim_treasury_spend() { // create a conversion rate from `asset_kind` to the native currency. assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); + Dmp::make_parachain_reachable(1000); + // create and approve a treasury spend. assert_ok!(Treasury::spend( root, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs index 037d6604ea4d..ec05a074c5ac 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs @@ -17,10 +17,8 @@ use crate::imports::*; -use frame_support::{ - dispatch::RawOrigin, - sp_runtime::{traits::Dispatchable, DispatchResult}, -}; +use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees; +use frame_support::dispatch::RawOrigin; use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, @@ -77,22 +75,12 @@ fn receiver_assertions(test: ParaToParaThroughAHTest) { ); } -fn transfer_assets_para_to_para_through_ah_dispatchable( - test: ParaToParaThroughAHTest, -) -> DispatchResult { - let call = transfer_assets_para_to_para_through_ah_call(test.clone()); - match call.dispatch(test.signed_origin) { - Ok(_) => Ok(()), - Err(error_with_post_info) => Err(error_with_post_info.error), - } -} - fn transfer_assets_para_to_para_through_ah_call( test: ParaToParaThroughAHTest, ) -> ::RuntimeCall { type RuntimeCall = ::RuntimeCall; - let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubWestend::para_id()); let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { assets: Wild(AllCounted(test.args.assets.len() as u32)), beneficiary: test.args.beneficiary, @@ -101,7 +89,7 @@ fn transfer_assets_para_to_para_through_ah_call( dest: bx!(test.args.dest.into()), assets: bx!(test.args.assets.clone().into()), assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - remote_fees_id: bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))), + remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::parent()))), fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), weight_limit: test.args.weight_limit, @@ -153,7 +141,7 @@ fn multi_hop_works() { // We get them from the PenpalA closure. let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); ::execute_with(|| { type Runtime = ::Runtime; type OriginCaller = ::OriginCaller; @@ -166,7 +154,7 @@ fn multi_hop_works() { .forwarded_xcms .iter() .find(|(destination, _)| { - *destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)])) + *destination == VersionedLocation::from(Location::new(1, [Parachain(1000)])) }) .unwrap(); assert_eq!(messages_to_query.len(), 1); @@ -180,7 +168,7 @@ fn multi_hop_works() { // These are set in the AssetHub closure. let mut intermediate_execution_fees = 0; let mut intermediate_delivery_fees_amount = 0; - let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); + let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new())); ::execute_with(|| { type Runtime = ::Runtime; type RuntimeCall = ::RuntimeCall; @@ -189,13 +177,14 @@ fn multi_hop_works() { let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); intermediate_execution_fees = Runtime::query_weight_to_asset_fee( weight, - VersionedAssetId::V4(Location::new(1, []).into()), + VersionedAssetId::from(AssetId(Location::new(1, []))), ) .unwrap(); // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. - let xcm_program = - VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + let xcm_program = VersionedXcm::from(Xcm::::from( + remote_message.clone().try_into().unwrap(), + )); // Now we get the delivery fees to the final destination. let result = @@ -204,7 +193,7 @@ fn multi_hop_works() { .forwarded_xcms .iter() .find(|(destination, _)| { - *destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)])) + *destination == VersionedLocation::from(Location::new(1, [Parachain(2001)])) }) .unwrap(); // There's actually two messages here. @@ -228,7 +217,7 @@ fn multi_hop_works() { let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); final_execution_fees = - Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(Location::parent())) .unwrap(); }); @@ -259,7 +248,8 @@ fn multi_hop_works() { test.set_assertion::(sender_assertions); test.set_assertion::(hop_assertions); test.set_assertion::(receiver_assertions); - test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + test.set_call(call); test.assert(); let sender_assets_after = PenpalA::execute_with(|| { @@ -286,3 +276,14 @@ fn multi_hop_works() { final_execution_fees ); } + +#[test] +fn multi_hop_pay_fees_works() { + test_can_estimate_and_pay_exact_fees!( + PenpalA, + AssetHubWestend, + PenpalB, + (Parent, 1_000_000_000_000u128), + Penpal + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 9f6fe78a33ee..7bb7277df45c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -12,21 +12,21 @@ workspace = true [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } hex-literal = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } # Substrate -sp-core = { workspace = true } frame-support = { workspace = true } -pallet-assets = { workspace = true } pallet-asset-conversion = { workspace = true } +pallet-assets = { workspace = true } pallet-balances = { workspace = true } pallet-message-queue = { workspace = true, default-features = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } # Polkadot -xcm = { workspace = true } pallet-xcm = { workspace = true } +xcm = { workspace = true } xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } @@ -44,7 +44,7 @@ testnet-parachains-constants = { features = ["rococo", "westend"], workspace = t # Snowbridge snowbridge-core = { workspace = true } -snowbridge-router-primitives = { workspace = true } -snowbridge-pallet-system = { workspace = true } -snowbridge-pallet-outbound-queue = { workspace = true } snowbridge-pallet-inbound-queue-fixtures = { workspace = true, default-features = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-router-primitives = { workspace = true } 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 77e4c8183e65..54bc395c86f0 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 @@ -22,9 +22,8 @@ mod imports { // Polkadot pub use xcm::{ - latest::ParentThen, + latest::{ParentThen, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, prelude::{AccountId32 as AccountId32Junction, *}, - v4::{self, NetworkId::Westend as WestendId}, }; pub use xcm_executor::traits::TransferType; 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 0e1cfdd82aaf..a2a61660afff 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 @@ -16,7 +16,7 @@ use crate::tests::*; fn send_assets_over_bridge(send_fn: F) { - // fund the AHR's SA on BHR for paying bridge transport fees + // fund the AHR's SA on BHR for paying bridge delivery fees BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); // set XCM versions @@ -39,7 +39,7 @@ fn send_assets_over_bridge(send_fn: F) { fn set_up_rocs_for_penpal_rococo_through_ahr_to_ahw( sender: &AccountId, amount: u128, -) -> (Location, v4::Location) { +) -> (Location, v5::Location) { let roc_at_rococo_parachains = roc_at_ah_rococo(); let roc_at_asset_hub_westend = bridged_roc_at_ah_westend(); create_foreign_on_ah_westend(roc_at_asset_hub_westend.clone(), true); @@ -70,7 +70,7 @@ fn send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah( ); let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, + ByGenesis(WESTEND_GENESIS_HASH), AssetHubWestend::para_id(), ); // send message over bridge @@ -125,7 +125,7 @@ fn send_roc_from_asset_hub_rococo_to_asset_hub_westend() { set_up_pool_with_wnd_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true); let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, + ByGenesis(WESTEND_GENESIS_HASH), AssetHubWestend::para_id(), ); let rocs_in_reserve_on_ahr_before = @@ -199,7 +199,7 @@ fn send_back_wnds_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { // 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( - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), prefund_amount)]); @@ -271,7 +271,7 @@ fn send_back_wnds_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true); // prefund AHR's sovereign account on AHW to be able to withdraw USDT and wETH from reserves let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); AssetHubWestend::mint_asset( @@ -357,7 +357,7 @@ fn send_rocs_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_westend() set_up_rocs_for_penpal_rococo_through_ahr_to_ahw(&sender, amount); let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, + ByGenesis(WESTEND_GENESIS_HASH), AssetHubWestend::para_id(), ); let rocs_in_reserve_on_ahr_before = @@ -463,7 +463,7 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste // 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( - NetworkId::Rococo, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); AssetHubWestend::fund_accounts(vec![(sov_ahr_on_ahw.clone(), amount * 2)]); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs index e61dc35bdf8a..e678cc40a3cb 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = BridgeHubRococoExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount); + test_chain_can_claim_assets!( + AssetHubRococo, + RuntimeCall, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), + assets, + amount + ); } 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 767f74f6ad7f..8aff87755961 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 @@ -14,6 +14,7 @@ // limitations under the License. use crate::imports::*; +use xcm::opaque::v5; mod asset_transfers; mod claim_assets; @@ -23,10 +24,22 @@ mod snowbridge; mod teleport; pub(crate) fn asset_hub_westend_location() -> Location { - Location::new(2, [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())]) + Location::new( + 2, + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), + ], + ) } pub(crate) fn bridge_hub_westend_location() -> Location { - Location::new(2, [GlobalConsensus(Westend), Parachain(BridgeHubWestend::para_id().into())]) + Location::new( + 2, + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(BridgeHubWestend::para_id().into()), + ], + ) } // ROC and wROC @@ -34,7 +47,7 @@ pub(crate) fn roc_at_ah_rococo() -> Location { Parent.into() } pub(crate) fn bridged_roc_at_ah_westend() -> Location { - Location::new(2, [GlobalConsensus(Rococo)]) + Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]) } // WND and wWND @@ -42,7 +55,7 @@ pub(crate) fn wnd_at_ah_westend() -> Location { Parent.into() } pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { - Location::new(2, [GlobalConsensus(Westend)]) + Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]) } // USDT and wUSDT @@ -53,7 +66,7 @@ pub(crate) fn bridged_usdt_at_ah_rococo() -> Location { Location::new( 2, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into()), @@ -73,7 +86,7 @@ pub(crate) fn weth_at_asset_hubs() -> Location { } pub(crate) fn create_foreign_on_ah_rococo( - id: v4::Location, + id: v5::Location, sufficient: bool, prefund_accounts: Vec<(AccountId, u128)>, ) { @@ -82,18 +95,18 @@ pub(crate) fn create_foreign_on_ah_rococo( AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); } -pub(crate) fn create_foreign_on_ah_westend(id: v4::Location, sufficient: bool) { +pub(crate) fn create_foreign_on_ah_westend(id: v5::Location, sufficient: bool) { let owner = AssetHubWestend::account_id_of(ALICE); AssetHubWestend::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]); } -pub(crate) fn foreign_balance_on_ah_rococo(id: v4::Location, who: &AccountId) -> u128 { +pub(crate) fn foreign_balance_on_ah_rococo(id: v5::Location, who: &AccountId) -> u128 { AssetHubRococo::execute_with(|| { type Assets = ::ForeignAssets; >::balance(id, who) }) } -pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -> u128 { +pub(crate) fn foreign_balance_on_ah_westend(id: v5::Location, who: &AccountId) -> u128 { AssetHubWestend::execute_with(|| { type Assets = ::ForeignAssets; >::balance(id, who) @@ -101,8 +114,8 @@ pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) - } // set up pool -pub(crate) fn set_up_pool_with_wnd_on_ah_westend(asset: v4::Location, is_foreign: bool) { - let wnd: v4::Location = v4::Parent.into(); +pub(crate) fn set_up_pool_with_wnd_on_ah_westend(asset: v5::Location, is_foreign: bool) { + let wnd: v5::Location = v5::Parent.into(); AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; let owner = AssetHubWestendSender::get(); @@ -117,7 +130,7 @@ pub(crate) fn set_up_pool_with_wnd_on_ah_westend(asset: v4::Location, is_foreign )); } else { let asset_id = match asset.interior.last() { - Some(v4::Junction::GeneralIndex(id)) => *id as u32, + Some(GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; assert_ok!(::Assets::mint( @@ -237,7 +250,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5); AssetHubRococo::open_bridge( AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()), - [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(), + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), + ] + .into(), Some(( (roc_at_ah_rococo(), ROC * 1).into(), BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of( @@ -250,7 +267,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); AssetHubWestend::open_bridge( AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()), - [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(), + [ + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), + Parachain(AssetHubRococo::para_id().into()), + ] + .into(), Some(( (wnd_at_ah_westend(), WND * 1).into(), BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs index 44637670112b..70e7a7a3ddd3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs @@ -22,7 +22,7 @@ const XCM_FEE: u128 = 4_000_000_000_000; fn register_rococo_asset_on_wah_from_rah() { let sa_of_rah_on_wah = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); @@ -30,7 +30,7 @@ fn register_rococo_asset_on_wah_from_rah() { let bridged_asset_at_wah = Location::new( 2, [ - GlobalConsensus(Rococo), + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(AssetHubRococo::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), @@ -58,7 +58,7 @@ fn register_rococo_asset_on_wah_from_rah() { let destination = asset_hub_westend_location(); - // fund the RAH's SA on RBH for paying bridge transport fees + // fund the RAH's SA on RBH for paying bridge delivery fees BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); // set XCM versions diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index 12f05742a080..cfcb581238e6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use rococo_system_emulated_network::rococo_emulated_chain::rococo_runtime::Dmp; + use crate::tests::*; #[test] @@ -29,7 +31,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable let xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { - network: WestendId, + network: ByGenesis(WESTEND_GENESIS_HASH), destination: [Parachain(AssetHubWestend::para_id().into())].into(), xcm: remote_xcm, }, @@ -38,6 +40,8 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { + Dmp::make_parachain_reachable(BridgeHubRococo::para_id()); + assert_ok!(::XcmPallet::send( sudo_origin, bx!(destination), @@ -60,21 +64,12 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable #[test] fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { - // Initially set only default version on all runtimes - let newer_xcm_version = xcm::prelude::XCM_VERSION; - let older_xcm_version = newer_xcm_version - 1; - - AssetHubRococo::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version)); - AssetHubWestend::force_default_xcm_version(Some(older_xcm_version)); - // prepare data let destination = asset_hub_westend_location(); let native_token = Location::parent(); let amount = ASSET_HUB_ROCOCO_ED * 1_000; - // fund the AHR's SA on BHR for paying bridge transport fees + // fund the AHR's SA on BHR for paying bridge delivery fees BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); // fund sender AssetHubRococo::fund_accounts(vec![(AssetHubRococoSender::get().into(), amount * 10)]); @@ -82,6 +77,14 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // open bridge open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // Initially set only default version on all runtimes + let newer_xcm_version = xcm::prelude::XCM_VERSION; + let older_xcm_version = newer_xcm_version - 1; + AssetHubRococo::force_default_xcm_version(Some(older_xcm_version)); + BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version)); + BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version)); + AssetHubWestend::force_default_xcm_version(Some(older_xcm_version)); + // send XCM from AssetHubRococo - fails - destination version not known assert_err!( send_assets_from_asset_hub_rococo( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index d91a0c6895f9..c72d5045ddc0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -25,7 +25,7 @@ use snowbridge_pallet_inbound_queue_fixtures::{ }; use snowbridge_pallet_system; use snowbridge_router_primitives::inbound::{ - Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, + Command, Destination, EthereumLocationsConverterFor, MessageV1, VersionedMessage, }; use sp_core::H256; use sp_runtime::{DispatchError::Token, TokenError::FundsUnavailable}; @@ -85,9 +85,9 @@ fn create_agent() { UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { - require_weight_at_most: 3000000000.into(), origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into(), + fallback_max_weight: None, }, ])); @@ -143,9 +143,9 @@ fn create_channel() { UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { - require_weight_at_most: 3000000000.into(), origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into(), + fallback_max_weight: None, }, ])); @@ -156,9 +156,9 @@ fn create_channel() { UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { - require_weight_at_most: 3000000000.into(), origin_kind: OriginKind::Xcm, call: create_channel_call.encode().into(), + fallback_max_weight: None, }, ])); @@ -310,24 +310,26 @@ fn send_token_from_ethereum_to_penpal() { )); }); + let ethereum_network_v5: NetworkId = EthereumNetwork::get().into(); + // The Weth asset location, identified by the contract address on Ethereum let weth_asset_location: Location = - (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); + (Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into(); - let origin_location = (Parent, Parent, EthereumNetwork::get()).into(); + let origin_location = (Parent, Parent, ethereum_network_v5).into(); // Fund ethereum sovereign on AssetHub let ethereum_sovereign: AccountId = - GlobalConsensusEthereumConvertsFor::::convert_location(&origin_location) - .unwrap(); + EthereumLocationsConverterFor::::convert_location(&origin_location).unwrap(); AssetHubRococo::fund_accounts(vec![(ethereum_sovereign.clone(), INITIAL_FUND)]); // Create asset on the Penpal parachain. PenpalA::execute_with(|| { - assert_ok!(::ForeignAssets::create( - ::RuntimeOrigin::signed(PenpalASender::get()), + assert_ok!(::ForeignAssets::force_create( + ::RuntimeOrigin::root(), weth_asset_location.clone(), asset_hub_sovereign.into(), + false, 1000, )); @@ -448,14 +450,14 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { )), fun: Fungible(WETH_AMOUNT), }]; - let multi_assets = VersionedAssets::V4(Assets::from(assets)); + let multi_assets = VersionedAssets::from(Assets::from(assets)); - let destination = VersionedLocation::V4(Location::new( + let destination = VersionedLocation::from(Location::new( 2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], )); - let beneficiary = VersionedLocation::V4(Location::new( + let beneficiary = VersionedLocation::from(Location::new( 0, [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], )); @@ -564,10 +566,9 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { } fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) { - let weth_asset_location: Location = Location::new( - 2, - [EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }], - ); + let ethereum_network_v5: NetworkId = EthereumNetwork::get().into(); + let weth_asset_location: Location = + Location::new(2, [ethereum_network_v5.into(), AccountKey20 { network: None, key: WETH }]); // Fund asset hub sovereign on bridge hub let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( 1, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index b87f25ac0f01..dc3bbb269d70 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -11,23 +11,23 @@ publish = false workspace = true [dependencies] -hex-literal = { workspace = true, default-features = true } codec = { workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } scale-info = { workspace = true } # Substrate frame-support = { workspace = true } -pallet-assets = { workspace = true } pallet-asset-conversion = { workspace = true } +pallet-assets = { workspace = true } pallet-balances = { workspace = true } pallet-message-queue = { workspace = true, default-features = true } sp-core = { workspace = true } sp-runtime = { workspace = true } # Polkadot -xcm = { workspace = true } pallet-xcm = { workspace = true } +xcm = { workspace = true } xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } @@ -36,18 +36,18 @@ pallet-bridge-messages = { workspace = true } pallet-xcm-bridge-hub = { workspace = true } # Cumulus +asset-hub-westend-runtime = { workspace = true } +bridge-hub-westend-runtime = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } emulated-integration-tests-common = { workspace = true } parachains-common = { workspace = true, default-features = true } rococo-westend-system-emulated-network = { workspace = true } testnet-parachains-constants = { features = ["rococo", "westend"], workspace = true, default-features = true } -asset-hub-westend-runtime = { workspace = true } -bridge-hub-westend-runtime = { workspace = true } # Snowbridge snowbridge-core = { workspace = true } -snowbridge-router-primitives = { workspace = true } -snowbridge-pallet-system = { workspace = true } -snowbridge-pallet-outbound-queue = { workspace = true } snowbridge-pallet-inbound-queue = { workspace = true } snowbridge-pallet-inbound-queue-fixtures = { workspace = true } +snowbridge-pallet-outbound-queue = { workspace = true } +snowbridge-pallet-system = { workspace = true } +snowbridge-router-primitives = { workspace = true } 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 76e8312921de..501ddb84d425 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 @@ -22,9 +22,9 @@ mod imports { // Polkadot pub use xcm::{ - latest::ParentThen, + latest::{ParentThen, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, prelude::{AccountId32 as AccountId32Junction, *}, - v4::{self, NetworkId::Rococo as RococoId}, + v5, }; pub use xcm_executor::traits::TransferType; @@ -56,6 +56,7 @@ mod imports { penpal_emulated_chain::{ penpal_runtime::xcm_config::{ CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, UniversalLocation as PenpalUniversalLocation, }, PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, @@ -71,8 +72,9 @@ mod imports { BridgeHubWestendPara as BridgeHubWestend, BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, BridgeHubWestendParaSender as BridgeHubWestendSender, PenpalBPara as PenpalB, - PenpalBParaSender as PenpalBSender, WestendRelay as Westend, - WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, + PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender, + WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, + WestendRelaySender as WestendSender, }; pub const ASSET_ID: u32 = 1; 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 0856c9526009..cc90c10b54bc 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 @@ -12,10 +12,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crate::tests::*; + +use crate::{create_pool_with_native_on, tests::*}; +use xcm::latest::AssetTransferFilter; fn send_assets_over_bridge(send_fn: F) { - // fund the AHW's SA on BHW for paying bridge transport fees + // fund the AHW's SA on BHW for paying bridge delivery fees BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); // set XCM versions @@ -38,7 +40,7 @@ fn send_assets_over_bridge(send_fn: F) { fn set_up_wnds_for_penpal_westend_through_ahw_to_ahr( sender: &AccountId, amount: u128, -) -> (Location, v4::Location) { +) -> (Location, v5::Location) { let wnd_at_westend_parachains = wnd_at_ah_westend(); let wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), true); @@ -69,10 +71,9 @@ fn send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah( ); let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); - // send message over bridge assert_ok!(PenpalB::execute_with(|| { let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); @@ -128,13 +129,18 @@ fn send_wnds_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { let bridged_wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); create_foreign_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), true); - set_up_pool_with_roc_on_ah_rococo(bridged_wnd_at_asset_hub_rococo.clone(), true); + create_pool_with_native_on!( + AssetHubRococo, + bridged_wnd_at_asset_hub_rococo.clone(), + true, + AssetHubRococoSender::get() + ); //////////////////////////////////////////////////////////// // Let's first send over just some WNDs as a simple example //////////////////////////////////////////////////////////// let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); let wnds_in_reserve_on_ahw_before = @@ -206,7 +212,12 @@ fn send_wnds_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { ); create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true); create_foreign_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true); - set_up_pool_with_roc_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true); + create_pool_with_native_on!( + AssetHubRococo, + bridged_usdt_at_asset_hub_rococo.clone(), + true, + AssetHubRococoSender::get() + ); let receiver_usdts_before = foreign_balance_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), &receiver); @@ -269,7 +280,7 @@ fn send_back_rocs_from_asset_hub_westend_to_asset_hub_rococo() { // 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( - Westend, + ByGenesis(WESTEND_GENESIS_HASH), AssetHubWestend::para_id(), ); AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), prefund_amount)]); @@ -339,7 +350,7 @@ fn send_wnds_from_penpal_westend_through_asset_hub_westend_to_asset_hub_rococo() set_up_wnds_for_penpal_westend_through_ahw_to_ahr(&sender, amount); let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), AssetHubRococo::para_id(), ); let wnds_in_reserve_on_ahw_before = @@ -445,7 +456,7 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc // 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( - Westend, + ByGenesis(WESTEND_GENESIS_HASH), AssetHubWestend::para_id(), ); AssetHubRococo::fund_accounts(vec![(sov_ahw_on_ahr.clone(), amount * 2)]); @@ -543,3 +554,295 @@ fn dry_run_transfer_to_rococo_sends_xcm_to_bridge_hub() { asset_hub_rococo_location() ); } + +fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo( + wnds: (Location, u128), + pens: (Location, u128), +) { + let (wnds_id, wnds_amount) = wnds; + let (pens_id, pens_amount) = pens; + send_assets_over_bridge(|| { + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + let sov_ahr_on_ahw = + AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + ByGenesis(ROCOCO_GENESIS_HASH), + AssetHubRococo::para_id(), + ); + // send message over bridge + assert_ok!(PenpalB::execute_with(|| { + let destination = asset_hub_rococo_location(); + let local_asset_hub = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); + let beneficiary: Location = + AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() } + .into(); + let wnds: Asset = (wnds_id.clone(), wnds_amount).into(); + let pens: Asset = (pens_id, pens_amount).into(); + let assets: Assets = vec![wnds.clone(), pens.clone()].into(); + + // TODO: dry-run to get exact fees, for now just some static value 100_000_000_000 + let penpal_fees_amount = 100_000_000_000; + // use 100_000_000_000 WNDs in fees on AHW + // (exec fees: 3_593_000_000, transpo fees: 69_021_561_290 = 72_614_561_290) + // TODO: make this exact once we have bridge dry-running + let ahw_fee_amount = 100_000_000_000; + + // XCM to be executed at dest (Rococo Asset Hub) + let xcm_on_dest = Xcm(vec![ + // since this is the last hop, we don't need to further use any assets previously + // reserved for fees (there are no further hops to cover delivery fees for); we + // RefundSurplus to get back any unspent fees + RefundSurplus, + // deposit everything to final beneficiary + DepositAsset { assets: Wild(All), beneficiary: beneficiary.clone() }, + ]); + + // XCM to be executed at (intermediary) Westend Asset Hub + let context = PenpalUniversalLocation::get(); + let reanchored_dest = + destination.clone().reanchored(&local_asset_hub, &context).unwrap(); + let reanchored_pens = pens.clone().reanchored(&local_asset_hub, &context).unwrap(); + let mut onward_wnds = wnds.clone().reanchored(&local_asset_hub, &context).unwrap(); + onward_wnds.fun = Fungible(wnds_amount - ahw_fee_amount - penpal_fees_amount); + let xcm_on_ahw = Xcm(vec![ + // both WNDs and PENs are local-reserve transferred to Rococo Asset Hub + // initially, all WNDs are reserved for fees on destination, but at the end of the + // program we RefundSurplus to get back any unspent and deposit them to final + // beneficiary + InitiateTransfer { + destination: reanchored_dest, + remote_fees: Some(AssetTransferFilter::ReserveDeposit(onward_wnds.into())), + preserve_origin: false, + assets: vec![AssetTransferFilter::ReserveDeposit(reanchored_pens.into())], + remote_xcm: xcm_on_dest, + }, + ]); + + let penpal_fees = (wnds.id.clone(), Fungible(penpal_fees_amount)); + let ahw_fees: Asset = (wnds.id.clone(), Fungible(ahw_fee_amount)).into(); + let ahw_non_fees_wnds: Asset = + (wnds.id.clone(), Fungible(wnds_amount - ahw_fee_amount - penpal_fees_amount)) + .into(); + // XCM to be executed locally + let xcm = Xcm::<()>(vec![ + // Withdraw both WNDs and PENs from origin account + WithdrawAsset(assets.into()), + PayFees { asset: penpal_fees.into() }, + // Execute the transfers while paying remote fees with WNDs + InitiateTransfer { + destination: local_asset_hub, + // WNDs for fees are reserve-withdrawn at AHW and reserved for fees + remote_fees: Some(AssetTransferFilter::ReserveWithdraw(ahw_fees.into())), + preserve_origin: false, + // PENs are teleported to AHW, rest of non-fee WNDs are reserve-withdrawn at AHW + assets: vec![ + AssetTransferFilter::Teleport(pens.into()), + AssetTransferFilter::ReserveWithdraw(ahw_non_fees_wnds.into()), + ], + remote_xcm: xcm_on_ahw, + }, + ]); + + ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V5(xcm.into())), + Weight::MAX, + ) + })); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount to reserve transfer is withdrawn from Penpal's sovereign account + RuntimeEvent::Balances( + pallet_balances::Event::Burned { who, amount } + ) => { + who: *who == sov_penpal_on_ahw.clone().into(), + amount: *amount == wnds_amount, + }, + // Amount deposited in AHR's sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sov_ahr_on_ahw.clone().into(), + }, + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }); + }); +} + +/// Transfer "PEN"s plus "WND"s from PenpalWestend to AssetHubWestend, over bridge to +/// AssetHubRococo. PENs need to be teleported to AHW, while WNDs reserve-withdrawn, then both +/// reserve transferred further to AHR. (transfer 2 different assets with different transfer types +/// across 3 different chains) +#[test] +fn send_pens_and_wnds_from_penpal_westend_via_ahw_to_ahr() { + let penpal_check_account = ::PolkadotXcm::check_account(); + let owner: AccountId = AssetHubRococo::account_id_of(ALICE); + let sender = PenpalBSender::get(); + let amount = ASSET_HUB_WESTEND_ED * 10_000_000; + + let (wnd_at_westend_parachains, wnd_at_rococo_parachains) = + set_up_wnds_for_penpal_westend_through_ahw_to_ahr(&sender, amount); + + let pens_location_on_penpal = + Location::try_from(PenpalLocalTeleportableToAssetHub::get()).unwrap(); + let pens_id_on_penpal = match pens_location_on_penpal.last() { + Some(Junction::GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + + let penpal_parachain_junction = Junction::Parachain(PenpalB::para_id().into()); + let pens_at_ahw = Location::new( + 1, + pens_location_on_penpal + .interior() + .clone() + .pushed_front_with(penpal_parachain_junction) + .unwrap(), + ); + let pens_at_rococo_parachains = Location::new( + 2, + pens_at_ahw + .interior() + .clone() + .pushed_front_with(Junction::GlobalConsensus(NetworkId::ByGenesis( + WESTEND_GENESIS_HASH, + ))) + .unwrap(), + ); + let wnds_to_send = amount; + let pens_to_send = amount; + + // ---------- Set up Penpal Westend ---------- + // Fund Penpal's sender account. No need to create the asset (only mint), it exists in genesis. + PenpalB::mint_asset( + ::RuntimeOrigin::signed(owner.clone()), + pens_id_on_penpal, + sender.clone(), + pens_to_send * 2, + ); + // fund Penpal's check account to be able to teleport + PenpalB::fund_accounts(vec![(penpal_check_account.clone().into(), pens_to_send * 2)]); + + // ---------- Set up Asset Hub Rococo ---------- + // create PEN at AHR + AssetHubRococo::force_create_foreign_asset( + pens_at_rococo_parachains.clone(), + owner.clone(), + false, + ASSET_MIN_BALANCE, + vec![], + ); + + // account balances before + let sender_wnds_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_westend_parachains.clone().into(), + &PenpalBSender::get(), + ) + }); + let sender_pens_before = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(pens_id_on_penpal, &PenpalBSender::get()) + }); + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + ByGenesis(ROCOCO_GENESIS_HASH), + AssetHubRococo::para_id(), + ); + let wnds_in_reserve_on_ahw_before = + ::account_data_of(sov_ahr_on_ahw.clone()).free; + let pens_in_reserve_on_ahw_before = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(pens_at_ahw.clone(), &sov_ahr_on_ahw) + }); + let receiver_wnds_before = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone(), + &AssetHubRococoReceiver::get(), + ) + }); + let receiver_pens_before = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + pens_at_rococo_parachains.clone(), + &AssetHubRococoReceiver::get(), + ) + }); + + // transfer assets + do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo( + (wnd_at_westend_parachains.clone(), wnds_to_send), + (pens_location_on_penpal.try_into().unwrap(), pens_to_send), + ); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubRococo, + vec![ + // issue WNDs on AHR + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == wnd_at_westend_parachains.clone().try_into().unwrap(), + owner: *owner == AssetHubRococoReceiver::get(), + }, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // account balances after + let sender_wnds_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + wnd_at_westend_parachains.into(), + &PenpalBSender::get(), + ) + }); + let sender_pens_after = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(pens_id_on_penpal, &PenpalBSender::get()) + }); + let wnds_in_reserve_on_ahw_after = + ::account_data_of(sov_ahr_on_ahw.clone()).free; + let pens_in_reserve_on_ahw_after = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(pens_at_ahw, &sov_ahr_on_ahw) + }); + let receiver_wnds_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + wnd_at_rococo_parachains.clone(), + &AssetHubRococoReceiver::get(), + ) + }); + let receiver_pens_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(pens_at_rococo_parachains, &AssetHubRococoReceiver::get()) + }); + + // Sender's balance is reduced + assert!(sender_wnds_after < sender_wnds_before); + // Receiver's balance is increased + assert!(receiver_wnds_after > receiver_wnds_before); + // Reserve balance is increased by sent amount (less fess) + assert!(wnds_in_reserve_on_ahw_after > wnds_in_reserve_on_ahw_before); + assert!(wnds_in_reserve_on_ahw_after <= wnds_in_reserve_on_ahw_before + wnds_to_send); + + // Sender's balance is reduced by sent amount + assert_eq!(sender_pens_after, sender_pens_before - pens_to_send); + // Reserve balance is increased by sent amount + assert_eq!(pens_in_reserve_on_ahw_after, pens_in_reserve_on_ahw_before + pens_to_send); + // Receiver's balance is increased by sent amount + assert_eq!(receiver_pens_after, receiver_pens_before + pens_to_send); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs index e62ce6843258..c111eb86501a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = BridgeHubWestendExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(AssetHubWestend, RuntimeCall, NetworkId::Westend, assets, amount); + test_chain_can_claim_assets!( + AssetHubWestend, + RuntimeCall, + NetworkId::ByGenesis(WESTEND_GENESIS_HASH), + assets, + amount + ); } 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 af11f0f7ba72..6c1cdb98e8b2 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 @@ -19,16 +19,28 @@ mod asset_transfers; mod claim_assets; mod register_bridged_assets; mod send_xcm; -mod teleport; - mod snowbridge; +mod teleport; +mod transact; pub(crate) fn asset_hub_rococo_location() -> Location { - Location::new(2, [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())]) + Location::new( + 2, + [ + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), + Parachain(AssetHubRococo::para_id().into()), + ], + ) } pub(crate) fn bridge_hub_rococo_location() -> Location { - Location::new(2, [GlobalConsensus(Rococo), Parachain(BridgeHubRococo::para_id().into())]) + Location::new( + 2, + [ + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), + Parachain(BridgeHubRococo::para_id().into()), + ], + ) } // WND and wWND @@ -36,7 +48,7 @@ pub(crate) fn wnd_at_ah_westend() -> Location { Parent.into() } pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { - Location::new(2, [GlobalConsensus(Westend)]) + Location::new(2, [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))]) } // ROC and wROC @@ -44,7 +56,7 @@ pub(crate) fn roc_at_ah_rococo() -> Location { Parent.into() } pub(crate) fn bridged_roc_at_ah_westend() -> Location { - Location::new(2, [GlobalConsensus(Rococo)]) + Location::new(2, [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH))]) } // USDT and wUSDT @@ -55,7 +67,7 @@ pub(crate) fn bridged_usdt_at_ah_rococo() -> Location { Location::new( 2, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into()), @@ -74,13 +86,13 @@ pub(crate) fn weth_at_asset_hubs() -> Location { ) } -pub(crate) fn create_foreign_on_ah_rococo(id: v4::Location, sufficient: bool) { +pub(crate) fn create_foreign_on_ah_rococo(id: v5::Location, sufficient: bool) { let owner = AssetHubRococo::account_id_of(ALICE); AssetHubRococo::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]); } pub(crate) fn create_foreign_on_ah_westend( - id: v4::Location, + id: v5::Location, sufficient: bool, prefund_accounts: Vec<(AccountId, u128)>, ) { @@ -89,74 +101,83 @@ pub(crate) fn create_foreign_on_ah_westend( AssetHubWestend::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); } -pub(crate) fn foreign_balance_on_ah_rococo(id: v4::Location, who: &AccountId) -> u128 { +pub(crate) fn foreign_balance_on_ah_rococo(id: v5::Location, who: &AccountId) -> u128 { AssetHubRococo::execute_with(|| { type Assets = ::ForeignAssets; >::balance(id, who) }) } -pub(crate) fn foreign_balance_on_ah_westend(id: v4::Location, who: &AccountId) -> u128 { +pub(crate) fn foreign_balance_on_ah_westend(id: v5::Location, who: &AccountId) -> u128 { AssetHubWestend::execute_with(|| { type Assets = ::ForeignAssets; >::balance(id, who) }) } -// set up pool -pub(crate) fn set_up_pool_with_roc_on_ah_rococo(asset: v4::Location, is_foreign: bool) { - let roc: v4::Location = v4::Parent.into(); - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - let owner = AssetHubRococoSender::get(); - let signed_owner = ::RuntimeOrigin::signed(owner.clone()); +/// note: $asset needs to be prefunded outside this function +#[macro_export] +macro_rules! create_pool_with_native_on { + ( $chain:ident, $asset:expr, $is_foreign:expr, $asset_owner:expr ) => { + emulated_integration_tests_common::impls::paste::paste! { + <$chain>::execute_with(|| { + type RuntimeEvent = <$chain as Chain>::RuntimeEvent; + let owner = $asset_owner; + let signed_owner = <$chain as Chain>::RuntimeOrigin::signed(owner.clone()); + let native_asset: Location = Parent.into(); - if is_foreign { - assert_ok!(::ForeignAssets::mint( - signed_owner.clone(), - asset.clone().into(), - owner.clone().into(), - 3_000_000_000_000, - )); - } else { - let asset_id = match asset.interior.last() { - Some(v4::Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - assert_ok!(::Assets::mint( - signed_owner.clone(), - asset_id.into(), - owner.clone().into(), - 3_000_000_000_000, - )); + if $is_foreign { + assert_ok!(<$chain as [<$chain Pallet>]>::ForeignAssets::mint( + signed_owner.clone(), + $asset.clone().into(), + owner.clone().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + } else { + let asset_id = match $asset.interior.last() { + Some(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + assert_ok!(<$chain as [<$chain Pallet>]>::Assets::mint( + signed_owner.clone(), + asset_id.into(), + owner.clone().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + } + + assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::create_pool( + signed_owner.clone(), + Box::new(native_asset.clone()), + Box::new($asset.clone()), + )); + + assert_expected_events!( + $chain, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity( + signed_owner, + Box::new(native_asset), + Box::new($asset), + 1_000_000_000_000, + 2_000_000_000_000, // $asset is worth half of native_asset + 0, + 0, + owner.into() + )); + + assert_expected_events!( + $chain, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); } - assert_ok!(::AssetConversion::create_pool( - signed_owner.clone(), - Box::new(roc.clone()), - Box::new(asset.clone()), - )); - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - assert_ok!(::AssetConversion::add_liquidity( - signed_owner.clone(), - Box::new(roc), - Box::new(asset), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - owner.into() - )); - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); + }; } pub(crate) fn send_assets_from_asset_hub_westend( @@ -239,7 +260,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5); AssetHubRococo::open_bridge( AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()), - [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(), + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), + ] + .into(), Some(( (roc_at_ah_rococo(), ROC * 1).into(), BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of( @@ -252,7 +277,11 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); AssetHubWestend::open_bridge( AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()), - [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(), + [ + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), + Parachain(AssetHubRococo::para_id().into()), + ] + .into(), Some(( (wnd_at_ah_westend(), WND * 1).into(), BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs index 7a7ad6da2d55..952fc35e6703 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs @@ -30,7 +30,7 @@ fn register_westend_asset_on_rah_from_wah() { let bridged_asset_at_rah = Location::new( 2, [ - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), @@ -57,7 +57,7 @@ fn register_ethereum_asset_on_rah_from_wah() { fn register_asset_on_rah_from_wah(bridged_asset_at_rah: Location) { let sa_of_wah_on_rah = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, + ByGenesis(WESTEND_GENESIS_HASH), AssetHubWestend::para_id(), ); @@ -82,7 +82,7 @@ fn register_asset_on_rah_from_wah(bridged_asset_at_rah: Location) { let destination = asset_hub_rococo_location(); - // fund the WAH's SA on WBH for paying bridge transport fees + // fund the WAH's SA on WBH for paying bridge delivery fees BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); // set XCM versions diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index ae05e4223b07..60f8af2242f9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use rococo_westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp; + use crate::tests::*; #[test] @@ -29,7 +31,7 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable let xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { - network: RococoId, + network: ByGenesis(ROCOCO_GENESIS_HASH), destination: [Parachain(AssetHubRococo::para_id().into())].into(), xcm: remote_xcm, }, @@ -38,6 +40,8 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable // Westend Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Westend::execute_with(|| { + Dmp::make_parachain_reachable(BridgeHubWestend::para_id()); + assert_ok!(::XcmPallet::send( sudo_origin, bx!(destination), @@ -60,21 +64,12 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable #[test] fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { - // Initially set only default version on all runtimes - let newer_xcm_version = xcm::prelude::XCM_VERSION; - let older_xcm_version = newer_xcm_version - 1; - - AssetHubRococo::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version)); - AssetHubWestend::force_default_xcm_version(Some(older_xcm_version)); - // prepare data let destination = asset_hub_rococo_location(); let native_token = Location::parent(); let amount = ASSET_HUB_WESTEND_ED * 1_000; - // fund the AHR's SA on BHR for paying bridge transport fees + // fund the AHR's SA on BHR for paying bridge delivery fees BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); // fund sender AssetHubWestend::fund_accounts(vec![(AssetHubWestendSender::get().into(), amount * 10)]); @@ -82,6 +77,14 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // open bridge open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // Initially set only default version on all runtimes + let newer_xcm_version = xcm::prelude::XCM_VERSION; + let older_xcm_version = newer_xcm_version - 1; + AssetHubRococo::force_default_xcm_version(Some(older_xcm_version)); + BridgeHubRococo::force_default_xcm_version(Some(older_xcm_version)); + BridgeHubWestend::force_default_xcm_version(Some(older_xcm_version)); + AssetHubWestend::force_default_xcm_version(Some(older_xcm_version)); + // send XCM from AssetHubWestend - fails - destination version not known assert_err!( send_assets_from_asset_hub_westend( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs index 4e9dd5a77dd7..ffa60a4f52e7 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs @@ -22,7 +22,7 @@ use hex_literal::hex; use rococo_westend_system_emulated_network::asset_hub_westend_emulated_chain::genesis::AssetHubWestendAssetOwner; use snowbridge_core::{outbound::OperatingMode, AssetMetadata, TokenIdOf}; use snowbridge_router_primitives::inbound::{ - Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, + Command, Destination, EthereumLocationsConverterFor, MessageV1, VersionedMessage, }; use sp_core::H256; use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; @@ -96,8 +96,10 @@ fn send_token_from_ethereum_to_asset_hub() { // Fund ethereum sovereign on AssetHub AssetHubWestend::fund_accounts(vec![(AssetHubWestendReceiver::get(), INITIAL_FUND)]); + let ethereum_network_v5: NetworkId = EthereumNetwork::get().into(); + let weth_asset_location: Location = - (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); + (Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into(); AssetHubWestend::execute_with(|| { type RuntimeOrigin = ::RuntimeOrigin; @@ -156,8 +158,9 @@ fn send_token_from_ethereum_to_asset_hub() { fn send_weth_asset_from_asset_hub_to_ethereum() { let assethub_location = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()); let assethub_sovereign = BridgeHubWestend::sovereign_account_id_of(assethub_location); + let ethereum_network_v5: NetworkId = EthereumNetwork::get().into(); let weth_asset_location: Location = - (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); + (Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into(); BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); @@ -218,14 +221,14 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { )), fun: Fungible(TOKEN_AMOUNT), }]; - let versioned_assets = VersionedAssets::V4(Assets::from(assets)); + let versioned_assets = VersionedAssets::from(Assets::from(assets)); - let destination = VersionedLocation::V4(Location::new( + let destination = VersionedLocation::from(Location::new( 2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], )); - let beneficiary = VersionedLocation::V4(Location::new( + let beneficiary = VersionedLocation::from(Location::new( 0, [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], )); @@ -291,13 +294,15 @@ fn transfer_relay_token() { BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); let asset_id: Location = Location { parents: 1, interior: [].into() }; - let expected_asset_id: Location = - Location { parents: 1, interior: [GlobalConsensus(Westend)].into() }; + let expected_asset_id: Location = Location { + parents: 1, + interior: [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH))].into(), + }; let expected_token_id = TokenIdOf::convert_location(&expected_asset_id).unwrap(); let ethereum_sovereign: AccountId = - GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(&Location::new( + EthereumLocationsConverterFor::<[u8; 32]>::convert_location(&Location::new( 2, [GlobalConsensus(EthereumNetwork::get())], )) @@ -317,7 +322,7 @@ fn transfer_relay_token() { assert_ok!(::EthereumSystem::register_token( RuntimeOrigin::root(), - Box::new(VersionedLocation::V4(asset_id.clone())), + Box::new(VersionedLocation::from(asset_id.clone())), AssetMetadata { name: "wnd".as_bytes().to_vec().try_into().unwrap(), symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), @@ -337,14 +342,14 @@ fn transfer_relay_token() { type RuntimeEvent = ::RuntimeEvent; let assets = vec![Asset { id: AssetId(Location::parent()), fun: Fungible(TOKEN_AMOUNT) }]; - let versioned_assets = VersionedAssets::V4(Assets::from(assets)); + let versioned_assets = VersionedAssets::from(Assets::from(assets)); - let destination = VersionedLocation::V4(Location::new( + let destination = VersionedLocation::from(Location::new( 2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], )); - let beneficiary = VersionedLocation::V4(Location::new( + let beneficiary = VersionedLocation::from(Location::new( 0, [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], )); @@ -445,7 +450,7 @@ fn transfer_ah_token() { let ethereum_destination = Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]); let ethereum_sovereign: AccountId = - GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(ðereum_destination) + EthereumLocationsConverterFor::<[u8; 32]>::convert_location(ðereum_destination) .unwrap() .into(); AssetHubWestend::fund_accounts(vec![(ethereum_sovereign.clone(), INITIAL_FUND)]); @@ -462,10 +467,15 @@ fn transfer_ah_token() { ], ); - let asset_id_after_reanchored = - Location::new(1, [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())]) - .appended_with(asset_id.clone().interior) - .unwrap(); + let asset_id_after_reanchored = Location::new( + 1, + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), + ], + ) + .appended_with(asset_id.clone().interior) + .unwrap(); let token_id = TokenIdOf::convert_location(&asset_id_after_reanchored).unwrap(); @@ -475,7 +485,7 @@ fn transfer_ah_token() { assert_ok!(::EthereumSystem::register_token( RuntimeOrigin::root(), - Box::new(VersionedLocation::V4(asset_id_in_bh.clone())), + Box::new(VersionedLocation::from(asset_id_in_bh.clone())), AssetMetadata { name: "ah_asset".as_bytes().to_vec().try_into().unwrap(), symbol: "ah_asset".as_bytes().to_vec().try_into().unwrap(), @@ -500,9 +510,9 @@ fn transfer_ah_token() { // Send partial of the token, will fail if send all let assets = vec![Asset { id: AssetId(asset_id.clone()), fun: Fungible(TOKEN_AMOUNT / 10) }]; - let versioned_assets = VersionedAssets::V4(Assets::from(assets)); + let versioned_assets = VersionedAssets::from(Assets::from(assets)); - let beneficiary = VersionedLocation::V4(Location::new( + let beneficiary = VersionedLocation::from(Location::new( 0, [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], )); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs new file mode 100644 index 000000000000..f6a3c53c4bf5 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/transact.rs @@ -0,0 +1,248 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{ + create_pool_with_native_on, + tests::{snowbridge::CHAIN_ID, *}, +}; +use sp_core::Get; +use xcm::latest::AssetTransferFilter; + +const ETHEREUM_BOB: [u8; 20] = hex_literal::hex!("11b0b11000011b0b11000011b0b11000011b0b11"); + +/// Bob on Ethereum transacts on PenpalB, paying fees using WETH. XCM has to go through Asset Hub +/// as the reserve location of WETH. The original origin `Ethereum/Bob` is proxied by Asset Hub. +/// +/// This particular test is not testing snowbridge, but only Bridge Hub, so the tested XCM flow from +/// Ethereum starts from Bridge Hub. +// TODO(https://github.com/paritytech/polkadot-sdk/issues/6243): Once Snowbridge supports Transact, start the flow from Ethereum and test completely e2e. +fn transfer_and_transact_in_same_xcm( + sender: Location, + weth: Asset, + destination: Location, + beneficiary: Location, + call: xcm::DoubleEncoded<()>, +) { + let signed_origin = ::RuntimeOrigin::root(); + let context: InteriorLocation = [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(::ParachainInfo::get().into()), + ] + .into(); + let asset_hub_location = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()); + + // TODO(https://github.com/paritytech/polkadot-sdk/issues/6197): dry-run to get local fees, for now use hardcoded value. + let ah_fees_amount = 90_000_000_000u128; // current exact value 79_948_099_299 + let fees_for_ah: Asset = (weth.id.clone(), ah_fees_amount).into(); + + // xcm to be executed at dest + let xcm_on_dest = Xcm(vec![ + Transact { origin_kind: OriginKind::Xcm, call, fallback_max_weight: None }, + ExpectTransactStatus(MaybeErrorCode::Success), + // since this is the last hop, we don't need to further use any assets previously + // reserved for fees (there are no further hops to cover delivery fees for); we + // RefundSurplus to get back any unspent fees + RefundSurplus, + DepositAsset { assets: Wild(All), beneficiary }, + ]); + let destination = destination.reanchored(&asset_hub_location, &context).unwrap(); + let xcm_to_ah = Xcm::<()>(vec![ + UnpaidExecution { check_origin: None, weight_limit: Unlimited }, + DescendOrigin([PalletInstance(80)].into()), // snowbridge pallet + UniversalOrigin(GlobalConsensus(Ethereum { chain_id: CHAIN_ID })), + ReserveAssetDeposited(weth.clone().into()), + AliasOrigin(sender), + PayFees { asset: fees_for_ah }, + InitiateTransfer { + destination, + // on the last hop we can just put everything in fees and `RefundSurplus` to get any + // unused back + remote_fees: Some(AssetTransferFilter::ReserveDeposit(Wild(All))), + preserve_origin: true, + assets: vec![], + remote_xcm: xcm_on_dest, + }, + ]); + ::PolkadotXcm::send( + signed_origin, + bx!(asset_hub_location.into()), + bx!(xcm::VersionedXcm::from(xcm_to_ah.into())), + ) + .unwrap(); +} + +/// Bob on Ethereum transacts on PenpalB, paying fees using WETH. XCM has to go through Asset Hub +/// as the reserve location of WETH. The original origin `Ethereum/Bob` is proxied by Asset Hub. +/// +/// This particular test is not testing snowbridge, but only Bridge Hub, so the tested XCM flow from +/// Ethereum starts from Bridge Hub. +// TODO(https://github.com/paritytech/polkadot-sdk/issues/6243): Once Snowbridge supports Transact, start the flow from Ethereum and test completely e2e. +#[test] +fn transact_from_ethereum_to_penpalb_through_asset_hub() { + // Snowbridge doesn't support transact yet, we are emulating it by sending one from Bridge Hub + // as if it comes from Snowbridge. + let destination = BridgeHubWestend::sibling_location_of(PenpalB::para_id()); + let sender = Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: ETHEREUM_BOB }, + ], + ); + + let bridged_weth = weth_at_asset_hubs(); + AssetHubWestend::force_create_foreign_asset( + bridged_weth.clone(), + PenpalAssetOwner::get(), + true, + ASSET_MIN_BALANCE, + vec![], + ); + PenpalB::force_create_foreign_asset( + bridged_weth.clone(), + PenpalAssetOwner::get(), + true, + ASSET_MIN_BALANCE, + vec![], + ); + // Configure source Penpal chain to trust local AH as reserve of bridged WETH + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + bridged_weth.encode(), + )], + )); + }); + + let fee_amount_to_send: parachains_common::Balance = ASSET_HUB_WESTEND_ED * 10000; + let sender_chain_as_seen_by_asset_hub = + Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]); + + let sov_of_sender_on_asset_hub = AssetHubWestend::execute_with(|| { + AssetHubWestend::sovereign_account_id_of(sender_chain_as_seen_by_asset_hub) + }); + let receiver_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_asset_hub = AssetHubWestend::execute_with(|| { + AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_asset_hub) + }); + // Create SAs of sender and receiver on AHW with ED. + AssetHubWestend::fund_accounts(vec![ + (sov_of_sender_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED), + (sov_of_receiver_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED), + ]); + + // We create a pool between WND and WETH in AssetHub to support paying for fees with WETH. + let ahw_owner = AssetHubWestendSender::get(); + create_pool_with_native_on!(AssetHubWestend, bridged_weth.clone(), true, ahw_owner); + // We also need a pool between WND and WETH on PenpalB to support paying for fees with WETH. + create_pool_with_native_on!(PenpalB, bridged_weth.clone(), true, PenpalAssetOwner::get()); + + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); + + // Query initial balances + let receiver_assets_before = PenpalB::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(bridged_weth.clone(), &receiver) + }); + + // Now register a new asset on PenpalB from Ethereum/Bob account while paying fees using WETH + // (going through Asset Hub) + let weth_to_send: Asset = (bridged_weth.clone(), fee_amount_to_send).into(); + // Silly example of a Transact: Bob creates his own foreign assset on PenpalB based on his + // Ethereum address + let foreign_asset_at_penpal_b = Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: ETHEREUM_BOB }, + ], + ); + // Encoded `create_asset` call to be executed in PenpalB + let call = PenpalB::create_foreign_asset_call( + foreign_asset_at_penpal_b.clone(), + ASSET_MIN_BALANCE, + receiver.clone(), + ); + BridgeHubWestend::execute_with(|| { + // initiate transaction + transfer_and_transact_in_same_xcm( + sender.clone(), + weth_to_send, + destination, + receiver.clone().into(), + call, + ); + }); + AssetHubWestend::execute_with(|| { + let sov_penpal_b_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + asset_hub_hop_assertions(sov_penpal_b_on_ah); + }); + PenpalB::execute_with(|| { + let expected_creator = PenpalB::sovereign_account_id_of(sender); + penpal_b_assertions(foreign_asset_at_penpal_b, expected_creator, receiver.clone()); + }); + + // Query final balances + let receiver_assets_after = PenpalB::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance(bridged_weth, &receiver) + }); + // Receiver's balance is increased + assert!(receiver_assets_after > receiver_assets_before); +} + +fn asset_hub_hop_assertions(receiver_sa: AccountId) { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + AssetHubWestend, + vec![ + // Deposited to receiver parachain SA + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Deposited { who, .. } + ) => { + who: *who == receiver_sa, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn penpal_b_assertions( + expected_asset: Location, + expected_creator: AccountId, + expected_owner: AccountId, +) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcmp_queue_success(None); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Created { asset_id, creator, owner } + ) => { + asset_id: *asset_id == expected_asset, + creator: *creator == expected_creator, + owner: *owner == expected_owner, + }, + ] + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml index c4d281b75a77..1d4e93d40da4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml @@ -11,31 +11,31 @@ publish = false workspace = true [dependencies] -codec = { workspace = true } assert_matches = { workspace = true } +codec = { workspace = true } # Substrate -sp-runtime = { workspace = true } frame-support = { workspace = true } -pallet-balances = { workspace = true } pallet-asset-rate = { workspace = true } pallet-assets = { workspace = true } -pallet-treasury = { workspace = true } +pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } +pallet-treasury = { workspace = true } pallet-utility = { workspace = true } pallet-whitelist = { workspace = true } +sp-runtime = { workspace = true } # Polkadot +pallet-xcm = { workspace = true } polkadot-runtime-common = { workspace = true, default-features = true } +westend-runtime-constants = { workspace = true, default-features = true } xcm = { workspace = true } xcm-executor = { workspace = true } -pallet-xcm = { workspace = true } -westend-runtime-constants = { workspace = true, default-features = true } # Cumulus -parachains-common = { workspace = true, default-features = true } -testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } emulated-integration-tests-common = { workspace = true } +parachains-common = { workspace = true, default-features = true } +testnet-parachains-constants = { features = ["westend"], workspace = true, default-features = true } westend-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs index f97599bda7f0..802fed1e681d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs @@ -36,12 +36,12 @@ fn fellows_whitelist_call() { UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), call: WestendCall::Whitelist( pallet_whitelist::Call::::whitelist_call { call_hash } ) .encode() .into(), + fallback_max_weight: None } ]))), }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs index 943f8965540d..ed7c9bafc607 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs @@ -20,6 +20,7 @@ use frame_support::{ }; use polkadot_runtime_common::impls::VersionedLocatableAsset; use westend_runtime_constants::currency::UNITS; +use westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp; use xcm_executor::traits::ConvertLocation; // Fund Fellowship Treasury from Westend Treasury and spend from Fellowship Treasury. @@ -57,6 +58,8 @@ fn fellowship_treasury_spend() { treasury_balance * 2, )); + Dmp::make_parachain_reachable(1000); + let native_asset = Location::here(); let asset_hub_location: Location = [Parachain(1000)].into(); let treasury_location: Location = (Parent, PalletInstance(37)).into(); @@ -64,11 +67,12 @@ fn fellowship_treasury_spend() { let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { as_origin: bx!(WestendOriginCaller::system(RawOrigin::Signed(treasury_account))), call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { - dest: bx!(VersionedLocation::V4(asset_hub_location.clone())), - beneficiary: bx!(VersionedLocation::V4(treasury_location)), - assets: bx!(VersionedAssets::V4( - Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into() - )), + dest: bx!(VersionedLocation::from(asset_hub_location.clone())), + beneficiary: bx!(VersionedLocation::from(treasury_location)), + assets: bx!(VersionedAssets::from(Assets::from(Asset { + id: native_asset.clone().into(), + fun: treasury_balance.into() + }))), fee_asset_item: 0, })), }); @@ -101,12 +105,12 @@ fn fellowship_treasury_spend() { let native_asset = Location::parent(); let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::::spend { - asset_kind: bx!(VersionedLocatableAsset::V4 { - location: asset_hub_location.clone(), - asset_id: native_asset.into(), - }), + asset_kind: bx!(VersionedLocatableAsset::from(( + asset_hub_location.clone(), + native_asset.into() + ))), amount: fellowship_treasury_balance, - beneficiary: bx!(VersionedLocation::V4(fellowship_treasury_location)), + beneficiary: bx!(VersionedLocation::from(fellowship_treasury_location)), valid_from: None, }); @@ -179,12 +183,12 @@ fn fellowship_treasury_spend() { let fellowship_treasury_spend_call = RuntimeCall::FellowshipTreasury(pallet_treasury::Call::::spend { - asset_kind: bx!(VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: native_asset.into(), - }), + asset_kind: bx!(VersionedLocatableAsset::from(( + asset_hub_location, + native_asset.into() + ))), amount: fellowship_spend_balance, - beneficiary: bx!(VersionedLocation::V4(alice_location)), + beneficiary: bx!(VersionedLocation::from(alice_location)), valid_from: None, }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml index 28d9da0993ff..61397b1b8d40 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml @@ -13,8 +13,8 @@ publish = false frame-support = { workspace = true } pallet-balances = { workspace = true } pallet-broker = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } +pallet-message-queue = { workspace = true } sp-runtime = { workspace = true } # Polkadot diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs index 055bd50d8298..d3fec4230368 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs @@ -20,7 +20,7 @@ mod imports { pub use frame_support::assert_ok; // Polkadot - pub use xcm::prelude::*; + pub use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*}; // Cumulus pub use emulated_integration_tests_common::xcm_emulator::{ diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs index e37b915174d3..bdab86f5cbf2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = CoretimeRococoExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(CoretimeRococo, RuntimeCall, NetworkId::Rococo, assets, amount); + test_chain_can_claim_assets!( + CoretimeRococo, + RuntimeCall, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), + assets, + amount + ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs index 9915b1753ef6..554025e1ecfe 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs @@ -17,6 +17,7 @@ use crate::imports::*; use frame_support::traits::OnInitialize; use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; use rococo_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; +use rococo_system_emulated_network::rococo_emulated_chain::rococo_runtime::Dmp; use sp_runtime::Perbill; #[test] @@ -34,6 +35,10 @@ fn transact_hardcoded_weights_are_sane() { type CoretimeEvent = ::RuntimeEvent; type RelayEvent = ::RuntimeEvent; + Rococo::execute_with(|| { + Dmp::make_parachain_reachable(CoretimeRococo::para_id()); + }); + // Reserve a workload, configure broker and start sales. CoretimeRococo::execute_with(|| { // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml index d57e7926b0ec..9f0eadf13650 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml @@ -13,8 +13,8 @@ publish = false frame-support = { workspace = true } pallet-balances = { workspace = true } pallet-broker = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } +pallet-message-queue = { workspace = true } sp-runtime = { workspace = true } # Polkadot diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs index ac844e0f3284..4fb619aba3d3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs @@ -20,7 +20,7 @@ mod imports { pub use frame_support::assert_ok; // Polkadot - pub use xcm::prelude::*; + pub use xcm::{latest::WESTEND_GENESIS_HASH, prelude::*}; // Cumulus pub use emulated_integration_tests_common::xcm_emulator::{ diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs index c8d853698444..3cabc3f8ac51 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = CoretimeWestendExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(CoretimeWestend, RuntimeCall, NetworkId::Westend, assets, amount); + test_chain_can_claim_assets!( + CoretimeWestend, + RuntimeCall, + NetworkId::ByGenesis(WESTEND_GENESIS_HASH), + assets, + amount + ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs index 00530f80b958..900994b1afc1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs @@ -18,6 +18,7 @@ use frame_support::traits::OnInitialize; use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; use sp_runtime::Perbill; use westend_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; +use westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp; #[test] fn transact_hardcoded_weights_are_sane() { @@ -34,6 +35,10 @@ fn transact_hardcoded_weights_are_sane() { type CoretimeEvent = ::RuntimeEvent; type RelayEvent = ::RuntimeEvent; + Westend::execute_with(|| { + Dmp::make_parachain_reachable(CoretimeWestend::para_id()); + }); + // Reserve a workload, configure broker and start sales. CoretimeWestend::execute_with(|| { // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml index 011be93ecac7..8b12897ef018 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml @@ -13,8 +13,8 @@ codec = { workspace = true } # Substrate frame-support = { workspace = true } pallet-balances = { workspace = true } -pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } +pallet-message-queue = { workspace = true } sp-runtime = { workspace = true } # Polkadot diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs index 06b0b6ba6005..a95396d5070b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs @@ -19,7 +19,7 @@ mod imports { pub use frame_support::{assert_ok, sp_runtime::DispatchResult, traits::fungibles::Inspect}; // Polkadot - pub use xcm::prelude::*; + pub use xcm::{latest::ROCOCO_GENESIS_HASH, prelude::*}; // Cumulus pub use asset_test_utils::xcm_helpers; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs index 793200e1d06b..6795b1e7f397 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = PeopleRococoExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(PeopleRococo, RuntimeCall, NetworkId::Rococo, assets, amount); + test_chain_can_claim_assets!( + PeopleRococo, + RuntimeCall, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), + assets, + amount + ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml index aa6eebc5458f..e069c1f61783 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml @@ -13,13 +13,14 @@ codec = { workspace = true } # Substrate frame-support = { workspace = true } pallet-balances = { workspace = true } -pallet-message-queue = { workspace = true } pallet-identity = { workspace = true } +pallet-message-queue = { workspace = true } pallet-xcm = { workspace = true } sp-runtime = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true, default-features = true } +westend-runtime = { workspace = true } westend-runtime-constants = { workspace = true, default-features = true } xcm = { workspace = true } xcm-executor = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs index 418cfea07ddc..59d87e1ea3f0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs @@ -19,7 +19,7 @@ mod imports { pub use frame_support::{assert_ok, sp_runtime::DispatchResult, traits::fungibles::Inspect}; // Polkadot - pub use xcm::prelude::*; + pub use xcm::{latest::WESTEND_GENESIS_HASH, prelude::*}; // Cumulus pub use asset_test_utils::xcm_helpers; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs index 42ccc459286a..055c713abfd8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/claim_assets.rs @@ -25,5 +25,11 @@ fn assets_can_be_claimed() { let amount = PeopleWestendExistentialDeposit::get(); let assets: Assets = (Parent, amount).into(); - test_chain_can_claim_assets!(PeopleWestend, RuntimeCall, NetworkId::Westend, assets, amount); + test_chain_can_claim_assets!( + PeopleWestend, + RuntimeCall, + NetworkId::ByGenesis(WESTEND_GENESIS_HASH), + assets, + amount + ); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs new file mode 100644 index 000000000000..ea438f80552e --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs @@ -0,0 +1,550 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::imports::*; +use frame_support::traits::ProcessMessageError; + +use codec::Encode; +use frame_support::sp_runtime::traits::Dispatchable; +use parachains_common::AccountId; +use people_westend_runtime::people::IdentityInfo; +use westend_runtime::{ + governance::pallet_custom_origins::Origin::GeneralAdmin as GeneralAdminOrigin, Dmp, +}; +use westend_system_emulated_network::people_westend_emulated_chain::people_westend_runtime; + +use pallet_identity::Data; + +use emulated_integration_tests_common::accounts::{ALICE, BOB}; + +#[test] +fn relay_commands_add_registrar() { + let (origin_kind, origin) = (OriginKind::Superuser, ::RuntimeOrigin::root()); + + let registrar: AccountId = [1; 32].into(); + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let add_registrar_call = + PeopleCall::Identity(pallet_identity::Call::::add_registrar { + account: registrar.into(), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: add_registrar_call.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleWestend, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::RegistrarAdded { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_add_registrar_wrong_origin() { + let people_westend_alice = PeopleWestend::account_id_of(ALICE); + + let origins = vec![ + ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_westend_alice), + ), + (OriginKind::Xcm, GeneralAdminOrigin.into()), + ]; + + let mut signed_origin = true; + + for (origin_kind, origin) in origins { + let registrar: AccountId = [1; 32].into(); + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let add_registrar_call = + PeopleCall::Identity(pallet_identity::Call::::add_registrar { + account: registrar.into(), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: add_registrar_call.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + if signed_origin { + assert_expected_events!( + PeopleWestend, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, + ] + ); + } else { + assert_expected_events!( + PeopleWestend, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + } + }); + + signed_origin = false; + } +} + +#[test] +fn relay_commands_kill_identity() { + // To kill an identity, first one must be set + PeopleWestend::execute_with(|| { + type PeopleRuntime = ::Runtime; + type PeopleRuntimeEvent = ::RuntimeEvent; + + let people_westend_alice = + ::RuntimeOrigin::signed(PeopleWestend::account_id_of(ALICE)); + + let identity_info = IdentityInfo { + email: Data::Raw(b"test@test.io".to_vec().try_into().unwrap()), + ..Default::default() + }; + let identity: Box<::IdentityInformation> = + Box::new(identity_info); + + assert_ok!(::Identity::set_identity( + people_westend_alice, + identity + )); + + assert_expected_events!( + PeopleWestend, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::IdentitySet { .. }) => {}, + ] + ); + }); + + let (origin_kind, origin) = (OriginKind::Superuser, ::RuntimeOrigin::root()); + + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type PeopleCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let kill_identity_call = + PeopleCall::Identity(pallet_identity::Call::::kill_identity { + target: people_westend_runtime::MultiAddress::Id(PeopleWestend::account_id_of( + ALICE, + )), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: kill_identity_call.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleWestend, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::IdentityKilled { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_kill_identity_wrong_origin() { + let people_westend_alice = PeopleWestend::account_id_of(BOB); + + let origins = vec![ + ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_westend_alice), + ), + (OriginKind::Xcm, GeneralAdminOrigin.into()), + ]; + + for (origin_kind, origin) in origins { + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type PeopleCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let kill_identity_call = + PeopleCall::Identity(pallet_identity::Call::::kill_identity { + target: people_westend_runtime::MultiAddress::Id(PeopleWestend::account_id_of( + ALICE, + )), + }); + + let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: kill_identity_call.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(xcm_message.dispatch(origin)); + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleWestend::execute_with(|| { + assert_expected_events!(PeopleWestend, vec![]); + }); + } +} + +#[test] +fn relay_commands_add_remove_username_authority() { + let people_westend_alice = PeopleWestend::account_id_of(ALICE); + let people_westend_bob = PeopleWestend::account_id_of(BOB); + + let (origin_kind, origin, usr) = + (OriginKind::Superuser, ::RuntimeOrigin::root(), "rootusername"); + + // First, add a username authority. + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let add_username_authority = + PeopleCall::Identity(pallet_identity::Call::::add_username_authority { + authority: people_westend_runtime::MultiAddress::Id(people_westend_alice.clone()), + suffix: b"suffix1".into(), + allocation: 10, + }); + + let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: add_username_authority.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(add_authority_xcm_msg.dispatch(origin.clone())); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Check events system-parachain-side + PeopleWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleWestend, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::AuthorityAdded { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); + + // Now, use the previously added username authority to concede a username to an account. + PeopleWestend::execute_with(|| { + type PeopleRuntimeEvent = ::RuntimeEvent; + let full_username = [usr.to_owned(), ".suffix1".to_owned()].concat().into_bytes(); + + assert_ok!(::Identity::set_username_for( + ::RuntimeOrigin::signed(people_westend_alice.clone()), + people_westend_runtime::MultiAddress::Id(people_westend_bob.clone()), + full_username, + None, + true + )); + + assert_expected_events!( + PeopleWestend, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameQueued { .. }) => {}, + ] + ); + }); + + // Accept the given username + PeopleWestend::execute_with(|| { + type PeopleRuntimeEvent = ::RuntimeEvent; + let full_username = [usr.to_owned(), ".suffix1".to_owned()].concat().into_bytes(); + + assert_ok!(::Identity::accept_username( + ::RuntimeOrigin::signed(people_westend_bob.clone()), + full_username.try_into().unwrap(), + )); + + assert_expected_events!( + PeopleWestend, + vec![ + PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameSet { .. }) => {}, + ] + ); + }); + + // Now, remove the username authority with another priviledged XCM call. + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::remove_username_authority { + authority: people_westend_runtime::MultiAddress::Id(people_westend_alice.clone()), + suffix: b"suffix1".into(), + }); + + let remove_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: remove_username_authority.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(remove_authority_xcm_msg.dispatch(origin)); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Final event check. + PeopleWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PeopleWestend, + vec![ + RuntimeEvent::Identity(pallet_identity::Event::AuthorityRemoved { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, + ] + ); + }); +} + +#[test] +fn relay_commands_add_remove_username_authority_wrong_origin() { + let people_westend_alice = PeopleWestend::account_id_of(ALICE); + + let origins = vec![ + ( + OriginKind::SovereignAccount, + ::RuntimeOrigin::signed(people_westend_alice.clone()), + ), + (OriginKind::Xcm, GeneralAdminOrigin.into()), + ]; + + for (origin_kind, origin) in origins { + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + Dmp::make_parachain_reachable(1004); + + let add_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::add_username_authority { + authority: people_westend_runtime::MultiAddress::Id(people_westend_alice.clone()), + suffix: b"suffix1".into(), + allocation: 10, + }); + + let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind, + call: add_username_authority.encode().into(), + fallback_max_weight: None + } + ]))), + }); + + assert_ok!(add_authority_xcm_msg.dispatch(origin.clone())); + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + // Check events system-parachain-side + PeopleWestend::execute_with(|| { + assert_expected_events!(PeopleWestend, vec![]); + }); + + Westend::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + type RuntimeEvent = ::RuntimeEvent; + type PeopleCall = ::RuntimeCall; + type PeopleRuntime = ::Runtime; + + let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< + PeopleRuntime, + >::remove_username_authority { + authority: people_westend_runtime::MultiAddress::Id(people_westend_alice.clone()), + suffix: b"suffix1".into(), + }); + + Dmp::make_parachain_reachable(1004); + + let remove_authority_xcm_msg = + RuntimeCall::XcmPallet(pallet_xcm::Call::::send { + dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), + message: bx!(VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + Transact { + origin_kind: OriginKind::SovereignAccount, + call: remove_username_authority.encode().into(), + fallback_max_weight: None, + } + ]))), + }); + + assert_ok!(remove_authority_xcm_msg.dispatch(origin)); + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + PeopleWestend::execute_with(|| { + assert_expected_events!(PeopleWestend, vec![]); + }); + } +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs index 08749b295dc2..b9ad9e3db467 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/mod.rs @@ -14,4 +14,5 @@ // limitations under the License. mod claim_assets; +mod governance; mod teleport; diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index c52021f67e36..09301bd738f3 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Parity Technologies "] edition.workspace = true description = "Managed content" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index e0bed23c4f8c..604441c65f29 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -5,6 +5,8 @@ name = "staging-parachain-info" version = "0.7.0" license = "Apache-2.0" description = "Pallet to store the parachain ID" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 51fc384a4f14..248b5d7202fa 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -5,6 +5,8 @@ name = "cumulus-ping" version = "0.7.0" license = "Apache-2.0" description = "Ping Pallet for Cumulus XCM/UMP testing." +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -13,14 +15,14 @@ workspace = true codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } -sp-runtime = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-runtime = { workspace = true } xcm = { workspace = true } -cumulus-primitives-core = { workspace = true } cumulus-pallet-xcm = { workspace = true } +cumulus-primitives-core = { workspace = true } [features] default = ["std"] diff --git a/cumulus/parachains/pallets/ping/src/lib.rs b/cumulus/parachains/pallets/ping/src/lib.rs index 729494cbd251..b6423a81db3c 100644 --- a/cumulus/parachains/pallets/ping/src/lib.rs +++ b/cumulus/parachains/pallets/ping/src/lib.rs @@ -108,13 +108,13 @@ pub mod pallet { (Parent, Junction::Parachain(para.into())).into(), Xcm(vec![Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1_000, 1_000), call: ::RuntimeCall::from(Call::::ping { seq, payload: payload.clone().to_vec(), }) .encode() .into(), + fallback_max_weight: None, }]), ) { Ok((hash, cost)) => { @@ -209,13 +209,13 @@ pub mod pallet { (Parent, Junction::Parachain(para.into())).into(), Xcm(vec![Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1_000, 1_000), call: ::RuntimeCall::from(Call::::pong { seq, payload: payload.clone(), }) .encode() .into(), + fallback_max_weight: None, }]), ) { Ok((hash, cost)) => diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 42adaba7a27c..c954ddb7b8c7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Rococo variant of Asset Hub parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -25,10 +27,10 @@ frame-system = { workspace = true } frame-system-benchmarking = { optional = true, workspace = true } frame-system-rpc-runtime-api = { workspace = true } frame-try-runtime = { optional = true, workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-asset-conversion-ops = { workspace = true } pallet-asset-conversion-tx-payment = { workspace = true } pallet-assets = { workspace = true } -pallet-asset-conversion-ops = { workspace = true } -pallet-asset-conversion = { workspace = true } pallet-assets-freezer = { workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } @@ -49,9 +51,9 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-keyring = { workspace = true } -sp-inherents = { workspace = true } sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -63,17 +65,18 @@ sp-weights = { workspace = true } primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } # Polkadot -rococo-runtime-constants = { workspace = true } pallet-xcm = { workspace = true } pallet-xcm-benchmarks = { optional = true, workspace = true } polkadot-parachain-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } +rococo-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } # Cumulus +assets-common = { workspace = true } cumulus-pallet-aura-ext = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-session-benchmarking = { workspace = true } @@ -81,24 +84,24 @@ cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["rococo"], workspace = true } -assets-common = { workspace = true } # Bridges -pallet-xcm-bridge-hub-router = { workspace = true } bp-asset-hub-rococo = { workspace = true } bp-asset-hub-westend = { workspace = true } bp-bridge-hub-rococo = { workspace = true } bp-bridge-hub-westend = { workspace = true } +pallet-xcm-bridge-hub-router = { workspace = true } snowbridge-router-primitives = { workspace = true } [dev-dependencies] asset-test-utils = { workspace = true, default-features = true } +parachains-runtimes-test-utils = { workspace = true, default-features = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } @@ -143,6 +146,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs index d15dd971a819..d58d2f6d5f4d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs @@ -67,8 +67,8 @@ mod preset_names { /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { use preset_names::*; - let patch = match id.try_into() { - Ok(PRESET_GENESIS) => asset_hub_rococo_genesis( + let patch = match id.as_ref() { + PRESET_GENESIS => asset_hub_rococo_genesis( // initial collators. vec![ // E8XC6rTJRsioKCp6KMy6zd24ykj4gWsusZ3AkSeyavpVBAG @@ -100,7 +100,7 @@ pub fn get_preset(id: &PresetId) -> Option> { ASSET_HUB_ROCOCO_ED * 524_288, 1000.into(), ), - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => asset_hub_rococo_genesis( + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => asset_hub_rococo_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), @@ -110,7 +110,7 @@ pub fn get_preset(id: &PresetId) -> Option> { testnet_parachains_constants::rococo::currency::UNITS * 1_000_000, 1000.into(), ), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => asset_hub_rococo_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => asset_hub_rococo_genesis( // initial collators. vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ 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 420fa67f41f3..dd1535826152 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -42,7 +42,7 @@ use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSele use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{AccountIdConversion, BlakeTwo256, Block as BlockT, Saturating, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Permill, @@ -62,7 +62,8 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, - ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, TransformOrigin, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, + TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -120,10 +121,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("statemine"), - impl_name: create_runtime_str!("statemine"), + spec_name: alloc::borrow::Cow::Borrowed("statemine"), + impl_name: alloc::borrow::Cow::Borrowed("statemine"), authoring_version: 1, - spec_version: 1_016_002, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -330,11 +331,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< Assets, ForeignAssets, LocalFromLeft< - AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssetsConvert, AssetIdForTrustBackedAssets, - xcm::v4::Location, + xcm::v5::Location, >, - xcm::v4::Location, + xcm::v5::Location, AccountId, >; @@ -342,21 +343,21 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< pub type NativeAndAssets = fungible::UnionOf< Balances, LocalAndForeignAssets, - TargetFromLeft, - xcm::v4::Location, + TargetFromLeft, + xcm::v5::Location, AccountId, >; pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< AssetConversionPalletId, - (xcm::v4::Location, xcm::v4::Location), + (xcm::v5::Location, xcm::v5::Location), >; impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type AssetKind = xcm::v4::Location; + type AssetKind = xcm::v5::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = pallet_asset_conversion::WithFirstAsset< @@ -381,7 +382,7 @@ impl pallet_asset_conversion::Config for Runtime { TokenLocation, parachain_info::Pallet, xcm_config::TrustBackedAssetsPalletIndex, - xcm::v4::Location, + xcm::v5::Location, >; } @@ -415,18 +416,18 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2; impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = xcm::v4::Location; - type AssetIdParameter = xcm::v4::Location; + type AssetId = xcm::v5::Location; + type AssetIdParameter = xcm::v5::Location; type Currency = Balances; type CreateOrigin = ForeignCreators< ( - FromSiblingParachain, xcm::v4::Location>, - FromNetwork, + FromSiblingParachain, xcm::v5::Location>, + FromNetwork, xcm_config::bridging::to_westend::WestendOrEthereumAssetFromAssetHubWestend, ), LocationToAccountId, AccountId, - xcm::v4::Location, + xcm::v5::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -467,6 +468,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = MaxSignatories; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -652,6 +654,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -813,7 +816,7 @@ parameter_types! { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type AssetId = xcm::v4::Location; + type AssetId = xcm::v5::Location; type OnChargeAssetTransaction = SwapAssetAdapter< TokenLocation, NativeAndAssets, @@ -918,6 +921,7 @@ impl pallet_nfts::Config for Runtime { type WeightInfo = weights::pallet_nfts::WeightInfo; #[cfg(feature = "runtime-benchmarks")] type Helper = (); + type BlockNumberProvider = frame_system::Pallet; } /// XCM router instance to BridgeHub with bridging capabilities for `Westend` global @@ -933,6 +937,10 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; + type BridgeHubOrigin = frame_support::traits::EitherOfDiverse< + EnsureRoot, + EnsureXcm>, + >; type ToBridgeHubSender = XcmpQueue; type LocalXcmChannelManager = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; @@ -1308,16 +1316,16 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - xcm::v4::Location, + xcm::v5::Location, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: xcm::v4::Location, asset2: xcm::v4::Location) -> Option<(Balance, Balance)> { + fn get_reserves(asset1: xcm::v5::Location, asset2: xcm::v5::Location) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(asset1, asset2).ok() } } @@ -1412,37 +1420,31 @@ impl_runtime_apis! { // We accept the native token to pay fees. let mut acceptable_assets = vec![AssetId(native_token.clone())]; // We also accept all assets in a pool with the native token. - let assets_in_pool_with_native = assets_common::get_assets_in_pool_with::< - Runtime, - xcm::v4::Location - >(&native_token).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?.into_iter(); - acceptable_assets.extend(assets_in_pool_with_native); + acceptable_assets.extend( + assets_common::PoolAdapter::::get_assets_in_pool_with(native_token) + .map_err(|()| XcmPaymentApiError::VersionedConversionFailed)? + ); PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { let native_asset = xcm_config::TokenLocation::get(); let fee_in_native = WeightToFee::weight_to_fee(&weight); - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == native_asset => { // for native token Ok(fee_in_native) }, Ok(asset_id) => { - let assets_in_pool_with_this_asset: Vec<_> = assets_common::get_assets_in_pool_with::< - Runtime, - xcm::v4::Location - >(&asset_id.0).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?; - if assets_in_pool_with_this_asset - .into_iter() - .map(|asset_id| asset_id.0) - .any(|location| location == native_asset) { - pallet_asset_conversion::Pallet::::quote_price_tokens_for_exact_tokens( - asset_id.clone().0, + // Try to get current price of `asset_id` in `native_asset`. + if let Ok(Some(swapped_in_native)) = assets_common::PoolAdapter::::quote_price_tokens_for_exact_tokens( + asset_id.0.clone(), native_asset, fee_in_native, true, // We include the fee. - ).ok_or(XcmPaymentApiError::AssetNotFound) + ) { + Ok(swapped_in_native) } else { log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) @@ -1556,7 +1558,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; @@ -1834,7 +1836,12 @@ impl_runtime_apis! { } fn alias_origin() -> Result<(Location, Location), BenchmarkError> { - Err(BenchmarkError::Skip) + // Any location can alias to an internal location. + // Here parachain 1001 aliases to an internal account. + Ok(( + Location::new(1, [Parachain(1001)]), + Location::new(1, [Parachain(1001), AccountId32 { id: [111u8; 32], network: None }]), + )) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index 51b6543bae82..8506125d4133 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `55b2c3410882`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=asset-hub-rococo-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=asset-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,14 +66,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 22_136_000 picoseconds. - Weight::from_parts(22_518_000, 0) + // Minimum execution time: 28_401_000 picoseconds. + Weight::from_parts(29_326_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -90,18 +94,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 92_277_000 picoseconds. - Weight::from_parts(94_843_000, 0) + // Minimum execution time: 109_686_000 picoseconds. + Weight::from_parts(114_057_000, 0) .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -111,25 +117,29 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `400` // Estimated: `6196` - // Minimum execution time: 120_110_000 picoseconds. - Weight::from_parts(122_968_000, 0) + // Minimum execution time: 137_693_000 picoseconds. + Weight::from_parts(142_244_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:2 w:2) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:0) + /// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -146,23 +156,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `496` + // Measured: `537` // Estimated: `6208` - // Minimum execution time: 143_116_000 picoseconds. - Weight::from_parts(147_355_000, 0) + // Minimum execution time: 178_291_000 picoseconds. + Weight::from_parts(185_648_000, 0) .saturating_add(Weight::from_parts(0, 6208)) - .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 14_014_000 picoseconds. + Weight::from_parts(14_522_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -170,8 +181,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_517_000 picoseconds. - Weight::from_parts(6_756_000, 0) + // Minimum execution time: 7_195_000 picoseconds. + Weight::from_parts(7_440_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -181,8 +192,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_894_000 picoseconds. - Weight::from_parts(2_024_000, 0) + // Minimum execution time: 2_278_000 picoseconds. + Weight::from_parts(2_488_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -208,8 +219,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_314_000 picoseconds. - Weight::from_parts(28_787_000, 0) + // Minimum execution time: 35_095_000 picoseconds. + Weight::from_parts(36_347_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -234,8 +245,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_840_000 picoseconds. - Weight::from_parts(30_589_000, 0) + // Minimum execution time: 38_106_000 picoseconds. + Weight::from_parts(38_959_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -246,45 +257,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_893_000 picoseconds. - Weight::from_parts(2_017_000, 0) + // Minimum execution time: 2_307_000 picoseconds. + Weight::from_parts(2_478_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `159` - // Estimated: `13524` - // Minimum execution time: 19_211_000 picoseconds. - Weight::from_parts(19_552_000, 0) - .saturating_add(Weight::from_parts(0, 13524)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15999` + // Minimum execution time: 25_238_000 picoseconds. + Weight::from_parts(25_910_000, 0) + .saturating_add(Weight::from_parts(0, 15999)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `163` - // Estimated: `13528` - // Minimum execution time: 19_177_000 picoseconds. - Weight::from_parts(19_704_000, 0) - .saturating_add(Weight::from_parts(0, 13528)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16003` + // Minimum execution time: 25_626_000 picoseconds. + Weight::from_parts(26_147_000, 0) + .saturating_add(Weight::from_parts(0, 16003)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `16013` - // Minimum execution time: 20_449_000 picoseconds. - Weight::from_parts(21_075_000, 0) - .saturating_add(Weight::from_parts(0, 16013)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18488` + // Minimum execution time: 28_528_000 picoseconds. + Weight::from_parts(28_882_000, 0) + .saturating_add(Weight::from_parts(0, 18488)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -304,36 +315,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_578_000 picoseconds. - Weight::from_parts(27_545_000, 0) + // Minimum execution time: 33_042_000 picoseconds. + Weight::from_parts(34_444_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `11096` - // Minimum execution time: 11_646_000 picoseconds. - Weight::from_parts(11_944_000, 0) - .saturating_add(Weight::from_parts(0, 11096)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `176` + // Estimated: `13541` + // Minimum execution time: 18_218_000 picoseconds. + Weight::from_parts(18_622_000, 0) + .saturating_add(Weight::from_parts(0, 13541)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `13535` - // Minimum execution time: 19_301_000 picoseconds. - Weight::from_parts(19_664_000, 0) - .saturating_add(Weight::from_parts(0, 13535)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16010` + // Minimum execution time: 25_838_000 picoseconds. + Weight::from_parts(26_276_000, 0) + .saturating_add(Weight::from_parts(0, 16010)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -350,11 +361,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `212` - // Estimated: `13577` - // Minimum execution time: 35_715_000 picoseconds. - Weight::from_parts(36_915_000, 0) - .saturating_add(Weight::from_parts(0, 13577)) - .saturating_add(T::DbWeight::get().reads(11)) + // Estimated: `16052` + // Minimum execution time: 46_196_000 picoseconds. + Weight::from_parts(47_859_000, 0) + .saturating_add(Weight::from_parts(0, 16052)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -365,8 +376,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_871_000 picoseconds. - Weight::from_parts(5_066_000, 0) + // Minimum execution time: 7_068_000 picoseconds. + Weight::from_parts(7_442_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -377,22 +388,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_150_000 picoseconds. - Weight::from_parts(26_119_000, 0) + // Minimum execution time: 31_497_000 picoseconds. + Weight::from_parts(31_975_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 38_248_000 picoseconds. - Weight::from_parts(39_122_000, 0) + // Minimum execution time: 44_534_000 picoseconds. + Weight::from_parts(46_175_000, 0) .saturating_add(Weight::from_parts(0, 3625)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 00ecf239428f..9a75428ada8b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,14 +52,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToWestendXcmRouter::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `153` + // Measured: `154` // Estimated: `5487` - // Minimum execution time: 12_993_000 picoseconds. - Weight::from_parts(13_428_000, 0) + // Minimum execution time: 13_884_000 picoseconds. + Weight::from_parts(14_312_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,9 +72,21 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `5487` - // Minimum execution time: 6_305_000 picoseconds. - Weight::from_parts(6_536_000, 0) + // Minimum execution time: 6_909_000 picoseconds. + Weight::from_parts(7_115_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } + /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `150` + // Estimated: `1502` + // Minimum execution time: 12_394_000 picoseconds. + Weight::from_parts(12_883_000, 0) + .saturating_add(Weight::from_parts(0, 1502)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs index 8c52ecd9f1b1..ccf473484cad 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs @@ -22,7 +22,11 @@ use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -83,7 +87,7 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -132,12 +136,35 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -150,6 +177,17 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -223,10 +261,12 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { XcmGeneric::::clear_topic() } fn alias_origin(_: &Location) -> Weight { - // XCM Executor does not currently support alias origin operations - Weight::MAX + XcmGeneric::::alias_origin() } fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 7478ba8893c1..a2169e2ea04b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 34_364_000 picoseconds. - Weight::from_parts(35_040_000, 3593) + // Minimum execution time: 33_878_000 picoseconds. + Weight::from_parts(34_766_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_755_000 picoseconds. - Weight::from_parts(43_650_000, 6196) + // Minimum execution time: 42_776_000 picoseconds. + Weight::from_parts(43_643_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 103_037_000 picoseconds. - Weight::from_parts(105_732_000, 8799) + // Minimum execution time: 104_654_000 picoseconds. + Weight::from_parts(106_518_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -99,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_095_000 picoseconds. - Weight::from_parts(1_220_000, 0) + // Minimum execution time: 1_183_000 picoseconds. + Weight::from_parts(1_309_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -122,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 108_117_000 picoseconds. - Weight::from_parts(110_416_000, 6196) + // Minimum execution time: 112_272_000 picoseconds. + Weight::from_parts(114_853_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -131,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_907_000 picoseconds. - Weight::from_parts(3_050_000, 0) + // Minimum execution time: 2_769_000 picoseconds. + Weight::from_parts(2_916_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -140,8 +140,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 24_965_000 picoseconds. - Weight::from_parts(25_687_000, 3593) + // Minimum execution time: 26_145_000 picoseconds. + Weight::from_parts(26_589_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,8 +165,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 83_312_000 picoseconds. - Weight::from_parts(85_463_000, 6196) + // Minimum execution time: 85_446_000 picoseconds. + Weight::from_parts(88_146_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -190,9 +190,34 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 49_874_000 picoseconds. - Weight::from_parts(51_165_000, 3610) + // Minimum execution time: 55_060_000 picoseconds. + Weight::from_parts(56_120_000, 3610) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `6196` + // Minimum execution time: 90_870_000 picoseconds. + Weight::from_parts(93_455_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index f6a883c03e9d..d48debef94c8 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 99_552_000 picoseconds. - Weight::from_parts(101_720_000, 6196) + // Minimum execution time: 103_506_000 picoseconds. + Weight::from_parts(106_039_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 659_000 picoseconds. - Weight::from_parts(706_000, 0) + // Minimum execution time: 668_000 picoseconds. + Weight::from_parts(743_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_803_000 picoseconds. + Weight::from_parts(5_983_000, 0) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 644_000 picoseconds. + Weight::from_parts(684_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +100,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 9_665_000 picoseconds. - Weight::from_parts(9_878_000, 3568) + // Minimum execution time: 9_957_000 picoseconds. + Weight::from_parts(10_163_000, 3568) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_959_000 picoseconds. - Weight::from_parts(7_111_000, 0) + // Minimum execution time: 6_663_000 picoseconds. + Weight::from_parts(7_134_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_682_000 picoseconds. - Weight::from_parts(2_799_000, 0) + // Minimum execution time: 3_067_000 picoseconds. + Weight::from_parts(3_175_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 656_000 picoseconds. - Weight::from_parts(683_000, 0) + // Minimum execution time: 650_000 picoseconds. + Weight::from_parts(691_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 687_000 picoseconds. - Weight::from_parts(719_000, 0) + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(703_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 588_000 picoseconds. - Weight::from_parts(653_000, 0) + // Minimum execution time: 649_000 picoseconds. + Weight::from_parts(691_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 690_000 picoseconds. - Weight::from_parts(714_000, 0) + Weight::from_parts(735_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 671_000 picoseconds. - Weight::from_parts(710_000, 0) + // Minimum execution time: 681_000 picoseconds. + Weight::from_parts(735_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +173,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 67_374_000 picoseconds. - Weight::from_parts(68_899_000, 6196) + // Minimum execution time: 68_877_000 picoseconds. + Weight::from_parts(69_996_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +184,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 12_896_000 picoseconds. - Weight::from_parts(13_191_000, 3625) + // Minimum execution time: 13_276_000 picoseconds. + Weight::from_parts(13_586_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +193,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 634_000 picoseconds. - Weight::from_parts(677_000, 0) + // Minimum execution time: 659_000 picoseconds. + Weight::from_parts(721_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +214,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 28_197_000 picoseconds. - Weight::from_parts(28_752_000, 3610) + // Minimum execution time: 28_656_000 picoseconds. + Weight::from_parts(29_175_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +225,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_678_000 picoseconds. - Weight::from_parts(2_803_000, 0) + // Minimum execution time: 2_608_000 picoseconds. + Weight::from_parts(2_876_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 22_806_000 picoseconds. - Weight::from_parts(23_217_000, 0) + // Minimum execution time: 24_035_000 picoseconds. + Weight::from_parts(24_315_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_221_000 picoseconds. - Weight::from_parts(6_347_000, 0) + // Minimum execution time: 6_558_000 picoseconds. + Weight::from_parts(6_711_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 653_000 picoseconds. - Weight::from_parts(676_000, 0) + // Minimum execution time: 645_000 picoseconds. + Weight::from_parts(700_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 621_000 picoseconds. - Weight::from_parts(678_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(696_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 770_000 picoseconds. - Weight::from_parts(829_000, 0) + // Minimum execution time: 787_000 picoseconds. + Weight::from_parts(866_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +284,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 71_654_000 picoseconds. - Weight::from_parts(73_329_000, 6196) + // Minimum execution time: 75_093_000 picoseconds. + Weight::from_parts(76_165_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +293,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_999_000 picoseconds. - Weight::from_parts(4_179_000, 0) + // Minimum execution time: 4_304_000 picoseconds. + Weight::from_parts(4_577_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +316,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 66_722_000 picoseconds. - Weight::from_parts(68_812_000, 6196) + // Minimum execution time: 68_809_000 picoseconds. + Weight::from_parts(70_037_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +325,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 718_000 picoseconds. - Weight::from_parts(745_000, 0) + // Minimum execution time: 715_000 picoseconds. + Weight::from_parts(766_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 623_000 picoseconds. - Weight::from_parts(682_000, 0) + // Minimum execution time: 639_000 picoseconds. + Weight::from_parts(688_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 664_000 picoseconds. - Weight::from_parts(696_000, 0) + // Minimum execution time: 638_000 picoseconds. + Weight::from_parts(712_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -334,22 +348,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 2_495_000 picoseconds. - Weight::from_parts(2_604_000, 1489) + // Minimum execution time: 2_521_000 picoseconds. + Weight::from_parts(2_715_000, 1489) .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 645_000 picoseconds. - Weight::from_parts(673_000, 0) + // Minimum execution time: 619_000 picoseconds. + Weight::from_parts(692_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 643_000 picoseconds. - Weight::from_parts(701_000, 0) + // Minimum execution time: 665_000 picoseconds. + Weight::from_parts(716_000, 0) + } + pub fn alias_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 668_000 picoseconds. + Weight::from_parts(726_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 637c5900f7da..08b2f520c4b9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -28,7 +28,7 @@ use frame_support::{ parameter_types, traits::{ tokens::imbalance::{ResolveAssetTo, ResolveTo}, - ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess, + ConstU32, Contains, Equals, Everything, PalletInfoAccess, }, }; use frame_system::EnsureRoot; @@ -42,31 +42,33 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; +use snowbridge_router_primitives::inbound::EthereumLocationsConverterFor; use sp_runtime::traits::{AccountIdConversion, ConvertInto, TryConvertInto}; use testnet_parachains_constants::rococo::snowbridge::{ EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX, }; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, - AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, - EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, - GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, - MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SingleAssetExchangeAdapter, SovereignPaidRemoteExporter, - SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithLatestLocationConverter, WithUniqueTopic, XcmFeeManagerFromComponents, + AccountId32Aliases, AliasChildLocation, AllowExplicitUnpaidExecutionFrom, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, + DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, + FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, + IsConcrete, LocalMint, MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking, + NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter, + SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithLatestLocationConverter, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const TokenLocation: Location = Location::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Rococo; + pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -104,7 +106,7 @@ pub type LocationToAccountId = ( GlobalConsensusParachainConvertsFor, // Ethereum contract sovereign account. // (Used to get convert ethereum contract locations to sovereign account) - GlobalConsensusEthereumConvertsFor, + EthereumLocationsConverterFor, ); /// Means for transacting the native currency on this chain. @@ -175,7 +177,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte StartsWithExplicitGlobalConsensus, ), Balance, - xcm::v4::Location, + xcm::v5::Location, >; /// Means for transacting foreign assets from different global consensus. @@ -314,6 +316,7 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, ); @@ -335,14 +338,14 @@ pub type PoolAssetsExchanger = SingleAssetExchangeAdapter< crate::AssetConversion, crate::NativeAndAssets, ( - TrustBackedAssetsAsLocation, + TrustBackedAssetsAsLocation, ForeignAssetsConvertedConcreteId, // `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here. MatchedConvertedConcreteId< - xcm::v4::Location, + xcm::v5::Location, Balance, Equals, - WithLatestLocationConverter, + WithLatestLocationConverter, TryConvertInto, >, ), @@ -389,7 +392,7 @@ impl xcm_executor::Config for XcmConfig { TrustBackedAssetsAsLocation< TrustBackedAssetsPalletLocation, Balance, - xcm::v4::Location, + xcm::v5::Location, >, ForeignAssetsConvertedConcreteId, ), @@ -440,7 +443,8 @@ impl xcm_executor::Config for XcmConfig { (bridging::to_westend::UniversalAliases, bridging::to_ethereum::UniversalAliases); type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + // We allow any origin to alias into a child sub-location (equivalent to DescendOrigin). + type Aliasers = AliasChildLocation; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -515,9 +519,9 @@ impl cumulus_pallet_xcm::Config for Runtime { /// Simple conversion of `u32` into an `AssetId` for use in benchmarking. pub struct XcmBenchmarkHelper; #[cfg(feature = "runtime-benchmarks")] -impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { - fn create_asset_id_parameter(id: u32) -> xcm::v4::Location { - xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(id)]) +impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> xcm::v5::Location { + xcm::v5::Location::new(1, [xcm::v5::Junction::Parachain(id)]) } } @@ -581,7 +585,7 @@ pub mod bridging { ] ); - pub const WestendNetwork: NetworkId = NetworkId::Westend; + pub const WestendNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH); pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; pub WestendEcosystem: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]); pub EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); @@ -652,7 +656,7 @@ pub mod bridging { /// `Option` represents static "base fee" which is used for total delivery fee calculation. pub BridgeTable: alloc::vec::Vec = alloc::vec![ NetworkExportTableItem::new( - EthereumNetwork::get(), + EthereumNetwork::get().into(), Some(alloc::vec![Junctions::Here]), SiblingBridgeHub::get(), Some(( @@ -665,7 +669,7 @@ pub mod bridging { /// Universal aliases pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter( alloc::vec![ - (SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get())), + (SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get().into())), ] ); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 814323135325..144934ecd4ab 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -24,10 +24,11 @@ use asset_hub_rococo_runtime::{ ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, TokenLocation, TrustBackedAssetsPalletLocation, XcmConfig, }, - AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, - ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, - MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - SessionKeys, TrustBackedAssetsInstance, XcmpQueue, + AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, Block, + CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, + MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, + RuntimeEvent, RuntimeOrigin, SessionKeys, ToWestendXcmRouterInstance, + TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -1078,6 +1079,7 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works( mod asset_hub_rococo_tests { use super::*; use asset_hub_rococo_runtime::PolkadotXcm; + use xcm::latest::WESTEND_GENESIS_HASH; use xcm_executor::traits::ConvertLocation; fn bridging_to_asset_hub_westend() -> TestBridgingConfig { @@ -1108,8 +1110,10 @@ mod asset_hub_rococo_tests { let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); let staking_pot = StakingPot::get(); - let foreign_asset_id_location = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + let foreign_asset_id_location = Location::new( + 2, + [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))], + ); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = @@ -1143,7 +1147,7 @@ mod asset_hub_rococo_tests { }, ( [PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)].into(), - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), [Parachain(1000)].into() ), || { @@ -1182,8 +1186,10 @@ mod asset_hub_rococo_tests { let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); let staking_pot = StakingPot::get(); - let foreign_asset_id_location = - Location::new(2, [Junction::GlobalConsensus(NetworkId::Westend)]); + let foreign_asset_id_location = Location::new( + 2, + [Junction::GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH))], + ); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = @@ -1210,7 +1216,7 @@ mod asset_hub_rococo_tests { bridging_to_asset_hub_westend, ( [PalletInstance(bp_bridge_hub_rococo::WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX)].into(), - GlobalConsensus(Westend), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), [Parachain(1000)].into() ), || { @@ -1237,6 +1243,58 @@ mod asset_hub_rococo_tests { ) } + #[test] + fn report_bridge_status_from_xcm_bridge_router_for_westend_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ToWestendXcmRouterInstance, + >( + collator_session_keys(), + bridging_to_asset_hub_westend, + || bp_asset_hub_rococo::build_congestion_message(Default::default(), true).into(), + || bp_asset_hub_rococo::build_congestion_message(Default::default(), false).into(), + ) + } + + #[test] + fn test_report_bridge_status_call_compatibility() { + // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding + assert_eq!( + RuntimeCall::ToWestendXcmRouter( + pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode(), + bp_asset_hub_rococo::Call::ToWestendXcmRouter( + bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + ); + } + + #[test] + fn check_sane_weight_report_bridge_status_for_westend() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); + } + #[test] fn reserve_transfer_native_asset_to_non_teleport_para_works() { asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< @@ -1466,3 +1524,19 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); + asset_test_utils::test_cases::xcm_payment_api_with_pools_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index d5eaa43ab834..7c31745d8f6e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Westend variant of Asset Hub parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -25,10 +27,10 @@ frame-system = { workspace = true } frame-system-benchmarking = { optional = true, workspace = true } frame-system-rpc-runtime-api = { workspace = true } frame-try-runtime = { optional = true, workspace = true } +pallet-asset-conversion = { workspace = true } pallet-asset-conversion-ops = { workspace = true } pallet-asset-conversion-tx-payment = { workspace = true } pallet-assets = { workspace = true } -pallet-asset-conversion = { workspace = true } pallet-assets-freezer = { workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } @@ -38,21 +40,21 @@ pallet-nft-fractionalization = { workspace = true } pallet-nfts = { workspace = true } pallet-nfts-runtime-api = { workspace = true } pallet-proxy = { workspace = true } +pallet-revive = { workspace = true } pallet-session = { workspace = true } pallet-state-trie-migration = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-uniques = { workspace = true } -pallet-revive = { workspace = true } pallet-utility = { workspace = true } sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -75,32 +77,33 @@ xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } # Cumulus +assets-common = { workspace = true } cumulus-pallet-aura-ext = { workspace = true } -pallet-message-queue = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-session-benchmarking = { workspace = true } cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } +pallet-message-queue = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["westend"], workspace = true } -assets-common = { workspace = true } # Bridges -pallet-xcm-bridge-hub-router = { workspace = true } bp-asset-hub-rococo = { workspace = true } bp-asset-hub-westend = { workspace = true } bp-bridge-hub-rococo = { workspace = true } bp-bridge-hub-westend = { workspace = true } +pallet-xcm-bridge-hub-router = { workspace = true } snowbridge-router-primitives = { workspace = true } [dev-dependencies] asset-test-utils = { workspace = true, default-features = true } +parachains-runtimes-test-utils = { workspace = true, default-features = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } @@ -147,6 +150,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs index 758ce3f40609..824544e3b687 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs @@ -18,6 +18,7 @@ use crate::*; use alloc::{vec, vec::Vec}; use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; use hex_literal::hex; use parachains_common::{AccountId, AuraId}; use sp_core::crypto::UncheckedInto; @@ -35,15 +36,14 @@ fn asset_hub_westend_genesis( endowment: Balance, id: ParaId, ) -> serde_json::Value { - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, endowment)).collect(), }, - parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + parachain_info: ParachainInfoConfig { parachain_id: id }, collator_selection: CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), candidacy_bond: ASSET_HUB_WESTEND_ED * 16, - ..Default::default() }, session: SessionConfig { keys: invulnerables @@ -56,16 +56,9 @@ fn asset_hub_westend_genesis( ) }) .collect(), - ..Default::default() }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, + }) } /// Encapsulates names of predefined presets. @@ -76,8 +69,8 @@ mod preset_names { /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { use preset_names::*; - let patch = match id.try_into() { - Ok(PRESET_GENESIS) => asset_hub_westend_genesis( + let patch = match id.as_ref() { + PRESET_GENESIS => asset_hub_westend_genesis( // initial collators. vec![ ( @@ -105,7 +98,7 @@ pub fn get_preset(id: &PresetId) -> Option> { ASSET_HUB_WESTEND_ED * 4096, 1000.into(), ), - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => asset_hub_westend_genesis( + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => asset_hub_westend_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), @@ -115,7 +108,7 @@ pub fn get_preset(id: &PresetId) -> Option> { WND * 1_000_000, 1000.into(), ), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => asset_hub_westend_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => asset_hub_westend_genesis( // initial collators. vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ 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 bbd686b5cf50..707d1c52f743 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -46,8 +46,8 @@ use frame_support::{ traits::{ fungible, fungibles, tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, InstanceFilter, - Nothing, TransformOrigin, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Equals, + InstanceFilter, Nothing, TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -59,15 +59,16 @@ use frame_system::{ use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_nfts::{DestroyWitness, PalletFeatures}; use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; +use pallet_xcm::EnsureXcm; use parachains_common::{ impls::DealWithFees, message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash, Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, NORMAL_DISPATCH_RATIO, }; use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160, U256}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{AccountIdConversion, BlakeTwo256, Block as BlockT, Saturating, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, Permill, RuntimeDebug, @@ -121,10 +122,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // Note: "westmint" is the legacy name for this chain. It has been renamed to // "asset-hub-westend". Many wallets/tools depend on the `spec_name`, so it remains "westmint" // for the time being. Wallets/tools should update to treat "asset-hub-westend" equally. - spec_name: create_runtime_str!("westmint"), - impl_name: create_runtime_str!("westmint"), + spec_name: alloc::borrow::Cow::Borrowed("westmint"), + impl_name: alloc::borrow::Cow::Borrowed("westmint"), authoring_version: 1, - spec_version: 1_016_004, + spec_version: 1_017_003, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -329,11 +330,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< Assets, ForeignAssets, LocalFromLeft< - AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssetsConvert, AssetIdForTrustBackedAssets, - xcm::v4::Location, + xcm::v5::Location, >, - xcm::v4::Location, + xcm::v5::Location, AccountId, >; @@ -341,21 +342,21 @@ pub type LocalAndForeignAssets = fungibles::UnionOf< pub type NativeAndAssets = fungible::UnionOf< Balances, LocalAndForeignAssets, - TargetFromLeft, - xcm::v4::Location, + TargetFromLeft, + xcm::v5::Location, AccountId, >; pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< AssetConversionPalletId, - (xcm::v4::Location, xcm::v4::Location), + (xcm::v5::Location, xcm::v5::Location), >; impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type AssetKind = xcm::v4::Location; + type AssetKind = xcm::v5::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = pallet_asset_conversion::WithFirstAsset< @@ -380,7 +381,7 @@ impl pallet_asset_conversion::Config for Runtime { WestendLocation, parachain_info::Pallet, xcm_config::TrustBackedAssetsPalletIndex, - xcm::v4::Location, + xcm::v5::Location, >; } @@ -414,18 +415,18 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2; impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = xcm::v4::Location; - type AssetIdParameter = xcm::v4::Location; + type AssetId = xcm::v5::Location; + type AssetIdParameter = xcm::v5::Location; type Currency = Balances; type CreateOrigin = ForeignCreators< ( - FromSiblingParachain, xcm::v4::Location>, - FromNetwork, + FromSiblingParachain, xcm::v5::Location>, + FromNetwork, xcm_config::bridging::to_rococo::RococoAssetFromAssetHubRococo, ), LocationToAccountId, AccountId, - xcm::v4::Location, + xcm::v5::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -466,6 +467,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = MaxSignatories; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -651,6 +653,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -807,7 +810,7 @@ parameter_types! { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type AssetId = xcm::v4::Location; + type AssetId = xcm::v5::Location; type OnChargeAssetTransaction = SwapAssetAdapter< WestendLocation, NativeAndAssets, @@ -912,6 +915,7 @@ impl pallet_nfts::Config for Runtime { type WeightInfo = weights::pallet_nfts::WeightInfo; #[cfg(feature = "runtime-benchmarks")] type Helper = (); + type BlockNumberProvider = frame_system::Pallet; } /// XCM router instance to BridgeHub with bridging capabilities for `Rococo` global @@ -927,6 +931,10 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; + type BridgeHubOrigin = frame_support::traits::EitherOfDiverse< + EnsureRoot, + EnsureXcm>, + >; type ToBridgeHubSender = XcmpQueue; type LocalXcmChannelManager = cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; @@ -1482,18 +1490,18 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - xcm::v4::Location, + xcm::v5::Location, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: xcm::v4::Location, asset2: xcm::v4::Location, amount: Balance, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: xcm::v5::Location, asset2: xcm::v5::Location, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: xcm::v4::Location, asset2: xcm::v4::Location) -> Option<(Balance, Balance)> { + fn get_reserves(asset1: xcm::v5::Location, asset2: xcm::v5::Location) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(asset1, asset2).ok() } } @@ -1525,38 +1533,31 @@ impl_runtime_apis! { // We accept the native token to pay fees. let mut acceptable_assets = vec![AssetId(native_token.clone())]; // We also accept all assets in a pool with the native token. - let assets_in_pool_with_native = assets_common::get_assets_in_pool_with::< - Runtime, - xcm::v4::Location - >(&native_token).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?.into_iter(); - acceptable_assets.extend(assets_in_pool_with_native); + acceptable_assets.extend( + assets_common::PoolAdapter::::get_assets_in_pool_with(native_token) + .map_err(|()| XcmPaymentApiError::VersionedConversionFailed)? + ); PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { let native_asset = xcm_config::WestendLocation::get(); let fee_in_native = WeightToFee::weight_to_fee(&weight); - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == native_asset => { // for native asset Ok(fee_in_native) }, Ok(asset_id) => { - // We recognize assets in a pool with the native one. - let assets_in_pool_with_this_asset: Vec<_> = assets_common::get_assets_in_pool_with::< - Runtime, - xcm::v4::Location - >(&asset_id.0).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?; - if assets_in_pool_with_this_asset - .into_iter() - .map(|asset_id| asset_id.0) - .any(|location| location == native_asset) { - pallet_asset_conversion::Pallet::::quote_price_tokens_for_exact_tokens( - asset_id.clone().0, + // Try to get current price of `asset_id` in `native_asset`. + if let Ok(Some(swapped_in_native)) = assets_common::PoolAdapter::::quote_price_tokens_for_exact_tokens( + asset_id.0.clone(), native_asset, fee_in_native, true, // We include the fee. - ).ok_or(XcmPaymentApiError::AssetNotFound) + ) { + Ok(swapped_in_native) } else { log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); Err(XcmPaymentApiError::AssetNotFound) @@ -1733,7 +1734,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; @@ -1997,7 +1998,7 @@ impl_runtime_apis! { fn fee_asset() -> Result { Ok(Asset { id: AssetId(WestendLocation::get()), - fun: Fungible(1_000_000 * UNITS), + fun: Fungible(1_000 * UNITS), }) } @@ -2011,7 +2012,12 @@ impl_runtime_apis! { } fn alias_origin() -> Result<(Location, Location), BenchmarkError> { - Err(BenchmarkError::Skip) + // Any location can alias to an internal location. + // Here parachain 1001 aliases to an internal account. + Ok(( + Location::new(1, [Parachain(1001)]), + Location::new(1, [Parachain(1001), AccountId32 { id: [111u8; 32], network: None }]), + )) } } @@ -2072,27 +2078,18 @@ impl_runtime_apis! { impl pallet_revive::ReviveApi for Runtime { - fn balance(address: H160) -> Balance { - let account = ::AddressMapper::to_account_id(&address); - Balances::usable_balance(account) + fn balance(address: H160) -> U256 { + Revive::evm_balance(&address) } fn nonce(address: H160) -> Nonce { let account = ::AddressMapper::to_account_id(&address); System::account_nonce(account) } - fn eth_transact( - from: H160, - dest: Option, - value: Balance, - input: Vec, - gas_limit: Option, - storage_deposit_limit: Option, - ) -> pallet_revive::EthContractResult + + fn eth_transact(tx: pallet_revive::evm::GenericTransaction) -> Result, pallet_revive::EthTransactError> { - use pallet_revive::AddressMapper; - let blockweights = ::BlockWeights::get(); - let origin = ::AddressMapper::to_account_id(&from); + let blockweights: BlockWeights = ::BlockWeights::get(); let encoded_size = |pallet_call| { let call = RuntimeCall::Revive(pallet_call); @@ -2101,15 +2098,9 @@ impl_runtime_apis! { }; Revive::bare_eth_transact( - origin, - dest, - value, - input, - gas_limit.unwrap_or(blockweights.max_block), - storage_deposit_limit.unwrap_or(u128::MAX), + tx, + blockweights.max_block, encoded_size, - pallet_revive::DebugInfo::UnsafeDebug, - pallet_revive::CollectEvents::UnsafeCollect, ) } @@ -2127,7 +2118,7 @@ impl_runtime_apis! { dest, value, gas_limit.unwrap_or(blockweights.max_block), - storage_deposit_limit.unwrap_or(u128::MAX), + pallet_revive::DepositLimit::Balance(storage_deposit_limit.unwrap_or(u128::MAX)), input_data, pallet_revive::DebugInfo::UnsafeDebug, pallet_revive::CollectEvents::UnsafeCollect, @@ -2149,7 +2140,7 @@ impl_runtime_apis! { RuntimeOrigin::signed(origin), value, gas_limit.unwrap_or(blockweights.max_block), - storage_deposit_limit.unwrap_or(u128::MAX), + pallet_revive::DepositLimit::Balance(storage_deposit_limit.unwrap_or(u128::MAX)), code, data, salt, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index be3d7661ab3c..93409463d4e5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-f3xfxtob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `c0a5c14955e4`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=asset-hub-westend-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=asset-hub-westend-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,14 +66,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_050_000 picoseconds. - Weight::from_parts(21_834_000, 0) + // Minimum execution time: 28_333_000 picoseconds. + Weight::from_parts(29_115_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -90,18 +94,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 92_497_000 picoseconds. - Weight::from_parts(95_473_000, 0) + // Minimum execution time: 111_150_000 picoseconds. + Weight::from_parts(113_250_000, 0) .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -111,25 +117,29 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `400` // Estimated: `6196` - // Minimum execution time: 120_059_000 picoseconds. - Weight::from_parts(122_894_000, 0) + // Minimum execution time: 135_730_000 picoseconds. + Weight::from_parts(140_479_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:2 w:2) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:0) + /// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -146,21 +156,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `496` + // Measured: `571` // Estimated: `6208` - // Minimum execution time: 141_977_000 picoseconds. - Weight::from_parts(145_981_000, 0) + // Minimum execution time: 174_654_000 picoseconds. + Weight::from_parts(182_260_000, 0) .saturating_add(Weight::from_parts(0, 6208)) - .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(7)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_426_000 picoseconds. - Weight::from_parts(7_791_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 12_750_000 picoseconds. + Weight::from_parts(13_124_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -168,8 +181,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_224_000 picoseconds. - Weight::from_parts(6_793_000, 0) + // Minimum execution time: 7_083_000 picoseconds. + Weight::from_parts(7_353_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +192,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_812_000 picoseconds. - Weight::from_parts(2_008_000, 0) + // Minimum execution time: 2_254_000 picoseconds. + Weight::from_parts(2_408_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -206,8 +219,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 26_586_000 picoseconds. - Weight::from_parts(27_181_000, 0) + // Minimum execution time: 34_983_000 picoseconds. + Weight::from_parts(35_949_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -232,8 +245,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 28_295_000 picoseconds. - Weight::from_parts(29_280_000, 0) + // Minimum execution time: 38_226_000 picoseconds. + Weight::from_parts(39_353_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -244,45 +257,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_803_000 picoseconds. - Weight::from_parts(1_876_000, 0) + // Minimum execution time: 2_254_000 picoseconds. + Weight::from_parts(2_432_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `159` - // Estimated: `13524` - // Minimum execution time: 18_946_000 picoseconds. - Weight::from_parts(19_456_000, 0) - .saturating_add(Weight::from_parts(0, 13524)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15999` + // Minimum execution time: 25_561_000 picoseconds. + Weight::from_parts(26_274_000, 0) + .saturating_add(Weight::from_parts(0, 15999)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `163` - // Estimated: `13528` - // Minimum execution time: 19_080_000 picoseconds. - Weight::from_parts(19_498_000, 0) - .saturating_add(Weight::from_parts(0, 13528)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16003` + // Minimum execution time: 25_950_000 picoseconds. + Weight::from_parts(26_532_000, 0) + .saturating_add(Weight::from_parts(0, 16003)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `16013` - // Minimum execution time: 20_637_000 picoseconds. - Weight::from_parts(21_388_000, 0) - .saturating_add(Weight::from_parts(0, 16013)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18488` + // Minimum execution time: 28_508_000 picoseconds. + Weight::from_parts(29_178_000, 0) + .saturating_add(Weight::from_parts(0, 18488)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -302,36 +315,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 25_701_000 picoseconds. - Weight::from_parts(26_269_000, 0) + // Minimum execution time: 33_244_000 picoseconds. + Weight::from_parts(33_946_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `11096` - // Minimum execution time: 11_949_000 picoseconds. - Weight::from_parts(12_249_000, 0) - .saturating_add(Weight::from_parts(0, 11096)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `176` + // Estimated: `13541` + // Minimum execution time: 18_071_000 picoseconds. + Weight::from_parts(18_677_000, 0) + .saturating_add(Weight::from_parts(0, 13541)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `13535` - // Minimum execution time: 19_278_000 picoseconds. - Weight::from_parts(19_538_000, 0) - .saturating_add(Weight::from_parts(0, 13535)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16010` + // Minimum execution time: 25_605_000 picoseconds. + Weight::from_parts(26_284_000, 0) + .saturating_add(Weight::from_parts(0, 16010)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -348,11 +361,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `212` - // Estimated: `13577` - // Minimum execution time: 35_098_000 picoseconds. - Weight::from_parts(35_871_000, 0) - .saturating_add(Weight::from_parts(0, 13577)) - .saturating_add(T::DbWeight::get().reads(11)) + // Estimated: `16052` + // Minimum execution time: 46_991_000 picoseconds. + Weight::from_parts(47_866_000, 0) + .saturating_add(Weight::from_parts(0, 16052)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -363,8 +376,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 3_862_000 picoseconds. - Weight::from_parts(4_082_000, 0) + // Minimum execution time: 5_685_000 picoseconds. + Weight::from_parts(5_816_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -375,22 +388,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_423_000 picoseconds. - Weight::from_parts(25_872_000, 0) + // Minimum execution time: 31_271_000 picoseconds. + Weight::from_parts(32_195_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 37_148_000 picoseconds. - Weight::from_parts(37_709_000, 0) + // Minimum execution time: 43_530_000 picoseconds. + Weight::from_parts(44_942_000, 0) .saturating_add(Weight::from_parts(0, 3625)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index c0898012e9f3..78aa839deacd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,14 +52,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToRococoXcmRouter::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `225` + // Measured: `259` // Estimated: `5487` - // Minimum execution time: 13_483_000 picoseconds. - Weight::from_parts(13_862_000, 0) + // Minimum execution time: 14_643_000 picoseconds. + Weight::from_parts(14_992_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -70,11 +70,23 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `111` + // Measured: `144` // Estimated: `5487` - // Minimum execution time: 5_078_000 picoseconds. - Weight::from_parts(5_233_000, 0) + // Minimum execution time: 5_367_000 picoseconds. + Weight::from_parts(5_604_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } + /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + fn report_bridge_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `150` + // Estimated: `1502` + // Minimum execution time: 12_562_000 picoseconds. + Weight::from_parts(12_991_000, 0) + .saturating_add(Weight::from_parts(0, 1502)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs index d39052c5c03b..a0e9705ff01d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs @@ -21,7 +21,11 @@ use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -82,7 +86,7 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -132,12 +136,35 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -150,6 +177,17 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -223,10 +261,12 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { XcmGeneric::::clear_topic() } fn alias_origin(_: &Location) -> Weight { - // XCM Executor does not currently support alias origin operations - Weight::MAX + XcmGeneric::::alias_origin() } fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 0aeae3184627..97e59c24dd89 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 32_651_000 picoseconds. - Weight::from_parts(33_225_000, 3593) + // Minimum execution time: 32_698_000 picoseconds. + Weight::from_parts(33_530_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 41_059_000 picoseconds. - Weight::from_parts(41_730_000, 6196) + // Minimum execution time: 41_485_000 picoseconds. + Weight::from_parts(41_963_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `8799` - // Minimum execution time: 102_780_000 picoseconds. - Weight::from_parts(105_302_000, 8799) + // Minimum execution time: 104_952_000 picoseconds. + Weight::from_parts(108_211_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -99,8 +99,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_124_000 picoseconds. - Weight::from_parts(1_201_000, 0) + // Minimum execution time: 1_154_000 picoseconds. + Weight::from_parts(1_238_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -122,8 +122,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 109_024_000 picoseconds. - Weight::from_parts(111_406_000, 6196) + // Minimum execution time: 111_509_000 picoseconds. + Weight::from_parts(114_476_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -131,8 +131,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_887_000 picoseconds. - Weight::from_parts(3_081_000, 0) + // Minimum execution time: 2_572_000 picoseconds. + Weight::from_parts(2_809_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -140,8 +140,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_234_000 picoseconds. - Weight::from_parts(25_561_000, 3593) + // Minimum execution time: 25_570_000 picoseconds. + Weight::from_parts(25_933_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,8 +165,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6196` - // Minimum execution time: 83_416_000 picoseconds. - Weight::from_parts(85_683_000, 6196) + // Minimum execution time: 86_148_000 picoseconds. + Weight::from_parts(88_170_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -190,9 +190,34 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 49_271_000 picoseconds. - Weight::from_parts(51_019_000, 3610) + // Minimum execution time: 55_051_000 picoseconds. + Weight::from_parts(56_324_000, 3610) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `6196` + // Minimum execution time: 90_155_000 picoseconds. + Weight::from_parts(91_699_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 98ecd7bd3092..0ec2741c0490 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("asset-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 100_823_000 picoseconds. - Weight::from_parts(103_071_000, 6196) + // Minimum execution time: 103_794_000 picoseconds. + Weight::from_parts(106_697_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 600_000 picoseconds. - Weight::from_parts(686_000, 0) + // Minimum execution time: 621_000 picoseconds. + Weight::from_parts(705_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_580_000 picoseconds. + Weight::from_parts(5_950_000, 0) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 598_000 picoseconds. + Weight::from_parts(700_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +100,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 8_226_000 picoseconds. - Weight::from_parts(8_650_000, 3568) + // Minimum execution time: 8_186_000 picoseconds. + Weight::from_parts(8_753_000, 3568) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_131_000 picoseconds. - Weight::from_parts(7_600_000, 0) + // Minimum execution time: 6_924_000 picoseconds. + Weight::from_parts(7_315_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_589_000 picoseconds. - Weight::from_parts(2_705_000, 0) + // Minimum execution time: 2_731_000 picoseconds. + Weight::from_parts(2_828_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 667_000 picoseconds. - Weight::from_parts(744_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(723_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 646_000 picoseconds. - Weight::from_parts(720_000, 0) + // Minimum execution time: 648_000 picoseconds. + Weight::from_parts(730_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 633_000 picoseconds. - Weight::from_parts(669_000, 0) + // Minimum execution time: 628_000 picoseconds. + Weight::from_parts(697_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 671_000 picoseconds. - Weight::from_parts(726_000, 0) + // Minimum execution time: 714_000 picoseconds. + Weight::from_parts(775_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 615_000 picoseconds. - Weight::from_parts(675_000, 0) + // Minimum execution time: 666_000 picoseconds. + Weight::from_parts(717_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +173,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 67_236_000 picoseconds. - Weight::from_parts(69_899_000, 6196) + // Minimum execution time: 70_263_000 picoseconds. + Weight::from_parts(71_266_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +184,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 12_976_000 picoseconds. - Weight::from_parts(13_357_000, 3625) + // Minimum execution time: 13_079_000 picoseconds. + Weight::from_parts(13_569_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +193,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 633_000 picoseconds. - Weight::from_parts(685_000, 0) + // Minimum execution time: 630_000 picoseconds. + Weight::from_parts(710_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +214,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 28_707_000 picoseconds. - Weight::from_parts(31_790_000, 3610) + // Minimum execution time: 29_042_000 picoseconds. + Weight::from_parts(29_633_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +225,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_670_000 picoseconds. - Weight::from_parts(2_833_000, 0) + // Minimum execution time: 2_601_000 picoseconds. + Weight::from_parts(2_855_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 23_459_000 picoseconds. - Weight::from_parts(23_817_000, 0) + // Minimum execution time: 23_696_000 picoseconds. + Weight::from_parts(24_427_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_197_000 picoseconds. - Weight::from_parts(6_338_000, 0) + // Minimum execution time: 6_687_000 picoseconds. + Weight::from_parts(6_820_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 671_000 picoseconds. - Weight::from_parts(715_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(728_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 655_000 picoseconds. - Weight::from_parts(694_000, 0) + // Minimum execution time: 668_000 picoseconds. + Weight::from_parts(721_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 810_000 picoseconds. - Weight::from_parts(858_000, 0) + // Minimum execution time: 832_000 picoseconds. + Weight::from_parts(900_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +284,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 73_136_000 picoseconds. - Weight::from_parts(75_314_000, 6196) + // Minimum execution time: 75_131_000 picoseconds. + Weight::from_parts(77_142_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +293,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_515_000 picoseconds. - Weight::from_parts(4_768_000, 0) + // Minimum execution time: 4_820_000 picoseconds. + Weight::from_parts(5_089_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +316,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 68_072_000 picoseconds. - Weight::from_parts(69_866_000, 6196) + // Minimum execution time: 70_079_000 picoseconds. + Weight::from_parts(71_762_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +325,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 696_000 picoseconds. - Weight::from_parts(736_000, 0) + // Minimum execution time: 722_000 picoseconds. + Weight::from_parts(784_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 618_000 picoseconds. - Weight::from_parts(681_000, 0) + // Minimum execution time: 613_000 picoseconds. + Weight::from_parts(674_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 647_000 picoseconds. - Weight::from_parts(672_000, 0) + // Minimum execution time: 608_000 picoseconds. + Weight::from_parts(683_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -334,22 +348,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 2_496_000 picoseconds. - Weight::from_parts(2_617_000, 1489) + // Minimum execution time: 2_466_000 picoseconds. + Weight::from_parts(2_705_000, 1489) .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 637_000 picoseconds. - Weight::from_parts(675_000, 0) + // Minimum execution time: 623_000 picoseconds. + Weight::from_parts(687_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 607_000 picoseconds. - Weight::from_parts(683_000, 0) + // Minimum execution time: 673_000 picoseconds. + Weight::from_parts(752_000, 0) + } + pub fn alias_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 638_000 picoseconds. + Weight::from_parts(708_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index b554d00508be..b4e938f1f8b5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -28,7 +28,7 @@ use frame_support::{ parameter_types, traits::{ tokens::imbalance::{ResolveAssetTo, ResolveTo}, - ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess, + ConstU32, Contains, Equals, Everything, PalletInfoAccess, }, }; use frame_system::EnsureRoot; @@ -42,28 +42,30 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; +use snowbridge_router_primitives::inbound::EthereumLocationsConverterFor; use sp_runtime::traits::{AccountIdConversion, ConvertInto, TryConvertInto}; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, - AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, - EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, - GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, - MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SingleAssetExchangeAdapter, SovereignPaidRemoteExporter, - SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithLatestLocationConverter, WithUniqueTopic, XcmFeeManagerFromComponents, + AccountId32Aliases, AliasChildLocation, AllowExplicitUnpaidExecutionFrom, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, + DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, + FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, + IsConcrete, LocalMint, MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking, + NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter, + SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithLatestLocationConverter, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const WestendLocation: Location = Location::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Westend); + pub const RelayNetwork: Option = Some(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -100,7 +102,7 @@ pub type LocationToAccountId = ( GlobalConsensusParachainConvertsFor, // Ethereum contract sovereign account. // (Used to get convert ethereum contract locations to sovereign account) - GlobalConsensusEthereumConvertsFor, + EthereumLocationsConverterFor, ); /// Means for transacting the native currency on this chain. @@ -171,7 +173,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte StartsWithExplicitGlobalConsensus, ), Balance, - xcm::v4::Location, + xcm::v5::Location, >; /// Means for transacting foreign assets from different global consensus. @@ -335,6 +337,7 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, FellowshipEntities, @@ -358,14 +361,14 @@ pub type PoolAssetsExchanger = SingleAssetExchangeAdapter< crate::AssetConversion, crate::NativeAndAssets, ( - TrustBackedAssetsAsLocation, + TrustBackedAssetsAsLocation, ForeignAssetsConvertedConcreteId, // `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here. MatchedConvertedConcreteId< - xcm::v4::Location, + xcm::v5::Location, Balance, Equals, - WithLatestLocationConverter, + WithLatestLocationConverter, TryConvertInto, >, ), @@ -411,7 +414,7 @@ impl xcm_executor::Config for XcmConfig { TrustBackedAssetsAsLocation< TrustBackedAssetsPalletLocation, Balance, - xcm::v4::Location, + xcm::v5::Location, >, ForeignAssetsConvertedConcreteId, ), @@ -462,7 +465,8 @@ impl xcm_executor::Config for XcmConfig { (bridging::to_rococo::UniversalAliases, bridging::to_ethereum::UniversalAliases); type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + // We allow any origin to alias into a child sub-location (equivalent to DescendOrigin). + type Aliasers = AliasChildLocation; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -538,9 +542,9 @@ impl cumulus_pallet_xcm::Config for Runtime { /// Simple conversion of `u32` into an `AssetId` for use in benchmarking. pub struct XcmBenchmarkHelper; #[cfg(feature = "runtime-benchmarks")] -impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { - fn create_asset_id_parameter(id: u32) -> xcm::v4::Location { - xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(id)]) +impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { + fn create_asset_id_parameter(id: u32) -> xcm::v5::Location { + xcm::v5::Location::new(1, [xcm::v5::Junction::Parachain(id)]) } } @@ -596,7 +600,7 @@ pub mod bridging { ] ); - pub const RococoNetwork: NetworkId = NetworkId::Rococo; + pub const RococoNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub RococoEcosystem: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]); pub RocLocation: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]); pub AssetHubRococo: Location = Location::new(2, [ @@ -667,7 +671,7 @@ pub mod bridging { /// `Option` represents static "base fee" which is used for total delivery fee calculation. pub BridgeTable: sp_std::vec::Vec = sp_std::vec![ NetworkExportTableItem::new( - EthereumNetwork::get(), + EthereumNetwork::get().into(), Some(sp_std::vec![Junctions::Here]), SiblingBridgeHub::get(), Some(( @@ -680,7 +684,7 @@ pub mod bridging { /// Universal aliases pub UniversalAliases: BTreeSet<(Location, Junction)> = BTreeSet::from_iter( sp_std::vec![ - (SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get())), + (SiblingBridgeHubWithEthereumInboundQueueInstance::get(), GlobalConsensus(EthereumNetwork::get().into())), ] ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 6a48b19ce946..24b6d83ffae4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -24,10 +24,10 @@ use asset_hub_westend_runtime::{ ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, TrustBackedAssetsPalletLocation, WestendLocation, XcmConfig, }, - AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, + AllPalletsWithoutSystem, Assets, Balances, Block, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - TrustBackedAssetsInstance, XcmpQueue, + ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; pub use asset_hub_westend_runtime::{AssetConversion, AssetDeposit, CollatorSelection, System}; use asset_test_utils::{ @@ -52,7 +52,10 @@ use sp_core::crypto::Ss58Codec; use sp_runtime::traits::MaybeEquivalence; use std::{convert::Into, ops::Mul}; use testnet_parachains_constants::westend::{consensus::*, currency::UNITS, fee::WeightToFee}; -use xcm::latest::prelude::{Assets as XcmAssets, *}; +use xcm::latest::{ + prelude::{Assets as XcmAssets, *}, + ROCOCO_GENESIS_HASH, +}; use xcm_builder::WithLatestLocationConverter; use xcm_executor::traits::{ConvertLocation, JustTry, WeightTrader}; use xcm_runtime_apis::conversions::LocationToAccountHelper; @@ -87,7 +90,7 @@ fn slot_durations() -> SlotDurations { fn setup_pool_for_paying_fees_with_foreign_assets( (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): ( AccountId, - xcm::v4::Location, + xcm::v5::Location, Balance, ), ) { @@ -95,7 +98,7 @@ fn setup_pool_for_paying_fees_with_foreign_assets( // setup a pool to pay fees with `foreign_asset_id_location` tokens let pool_owner: AccountId = [14u8; 32].into(); - let native_asset = xcm::v4::Location::parent(); + let native_asset = xcm::v5::Location::parent(); let pool_liquidity: Balance = existential_deposit.max(foreign_asset_id_minimum_balance).mul(100_000); @@ -220,10 +223,10 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { assert_ok!(AssetConversion::create_pool( RuntimeHelper::origin_of(bob.clone()), Box::new( - xcm::v4::Location::try_from(native_location.clone()).expect("conversion works") + xcm::v5::Location::try_from(native_location.clone()).expect("conversion works") ), Box::new( - xcm::v4::Location::try_from(asset_1_location.clone()) + xcm::v5::Location::try_from(asset_1_location.clone()) .expect("conversion works") ) )); @@ -231,10 +234,10 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { assert_ok!(AssetConversion::add_liquidity( RuntimeHelper::origin_of(bob.clone()), Box::new( - xcm::v4::Location::try_from(native_location.clone()).expect("conversion works") + xcm::v5::Location::try_from(native_location.clone()).expect("conversion works") ), Box::new( - xcm::v4::Location::try_from(asset_1_location.clone()) + xcm::v5::Location::try_from(asset_1_location.clone()) .expect("conversion works") ), pool_liquidity, @@ -272,8 +275,8 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { let refund_weight = Weight::from_parts(1_000_000_000, 0); let refund = WeightToFee::weight_to_fee(&refund_weight); let (reserve1, reserve2) = AssetConversion::get_reserves( - xcm::v4::Location::try_from(native_location).expect("conversion works"), - xcm::v4::Location::try_from(asset_1_location.clone()).expect("conversion works"), + xcm::v5::Location::try_from(native_location).expect("conversion works"), + xcm::v5::Location::try_from(asset_1_location.clone()).expect("conversion works"), ) .unwrap(); let asset_refund = @@ -311,12 +314,12 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { let bob: AccountId = SOME_ASSET_ADMIN.into(); let staking_pot = CollatorSelection::account_id(); let native_location = - xcm::v4::Location::try_from(WestendLocation::get()).expect("conversion works"); - let foreign_location = xcm::v4::Location { + xcm::v5::Location::try_from(WestendLocation::get()).expect("conversion works"); + let foreign_location = xcm::v5::Location { parents: 1, interior: ( - xcm::v4::Junction::Parachain(1234), - xcm::v4::Junction::GeneralIndex(12345), + xcm::v5::Junction::Parachain(1234), + xcm::v5::Junction::GeneralIndex(12345), ) .into(), }; @@ -498,11 +501,11 @@ fn test_foreign_asset_xcm_take_first_trader() { .execute_with(|| { // We need root origin to create a sufficient asset let minimum_asset_balance = 3333333_u128; - let foreign_location = xcm::v4::Location { + let foreign_location = xcm::v5::Location { parents: 1, interior: ( - xcm::v4::Junction::Parachain(1234), - xcm::v4::Junction::GeneralIndex(12345), + xcm::v5::Junction::Parachain(1234), + xcm::v5::Junction::GeneralIndex(12345), ) .into(), }; @@ -522,7 +525,7 @@ fn test_foreign_asset_xcm_take_first_trader() { minimum_asset_balance )); - let asset_location_v4: Location = foreign_location.clone().try_into().unwrap(); + let asset_location_v5: Location = foreign_location.clone().try_into().unwrap(); // Set Alice as block author, who will receive fees RuntimeHelper::run_to_block(2, AccountId::from(ALICE)); @@ -537,7 +540,7 @@ fn test_foreign_asset_xcm_take_first_trader() { // Lets pay with: asset_amount_needed + asset_amount_extra let asset_amount_extra = 100_u128; let asset: Asset = - (asset_location_v4.clone(), asset_amount_needed + asset_amount_extra).into(); + (asset_location_v5.clone(), asset_amount_needed + asset_amount_extra).into(); let mut trader = ::Trader::new(); let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None }; @@ -546,7 +549,7 @@ fn test_foreign_asset_xcm_take_first_trader() { let unused_assets = trader.buy_weight(bought, asset.into(), &ctx).expect("Expected Ok"); // Check whether a correct amount of unused assets is returned assert_ok!( - unused_assets.ensure_contains(&(asset_location_v4, asset_amount_extra).into()) + unused_assets.ensure_contains(&(asset_location_v5, asset_amount_extra).into()) ); // Drop trader @@ -834,11 +837,11 @@ fn test_assets_balances_api_works() { .build() .execute_with(|| { let local_asset_id = 1; - let foreign_asset_id_location = xcm::v4::Location { + let foreign_asset_id_location = xcm::v5::Location { parents: 1, interior: [ - xcm::v4::Junction::Parachain(1234), - xcm::v4::Junction::GeneralIndex(12345), + xcm::v5::Junction::Parachain(1234), + xcm::v5::Junction::GeneralIndex(12345), ] .into(), }; @@ -929,7 +932,7 @@ fn test_assets_balances_api_works() { .into()))); // check foreign asset assert!(result.inner().iter().any(|asset| asset.eq(&( - WithLatestLocationConverter::::convert_back( + WithLatestLocationConverter::::convert_back( &foreign_asset_id_location ) .unwrap(), @@ -1022,13 +1025,13 @@ asset_test_utils::include_asset_transactor_transfer_with_pallet_assets_instance_ Runtime, XcmConfig, ForeignAssetsInstance, - xcm::v4::Location, + xcm::v5::Location, JustTry, collator_session_keys(), ExistentialDeposit::get(), - xcm::v4::Location { + xcm::v5::Location { parents: 1, - interior: [xcm::v4::Junction::Parachain(1313), xcm::v4::Junction::GeneralIndex(12345)] + interior: [xcm::v5::Junction::Parachain(1313), xcm::v5::Junction::GeneralIndex(12345)] .into() }, Box::new(|| { @@ -1045,8 +1048,8 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p WeightToFee, LocationToAccountId, ForeignAssetsInstance, - xcm::v4::Location, - WithLatestLocationConverter, + xcm::v5::Location, + WithLatestLocationConverter, collator_session_keys(), ExistentialDeposit::get(), AssetDeposit::get(), @@ -1123,8 +1126,10 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); let staking_pot = StakingPot::get(); - let foreign_asset_id_location = - xcm::v4::Location::new(2, [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::Rococo)]); + let foreign_asset_id_location = xcm::v5::Location::new( + 2, + [xcm::v5::Junction::GlobalConsensus(xcm::v5::NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))], + ); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap(); @@ -1154,7 +1159,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_pool_s }, ( [PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)].into(), - GlobalConsensus(Rococo), + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), [Parachain(1000)].into() ), || { @@ -1192,8 +1197,10 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic let block_author_account = AccountId::from(BLOCK_AUTHOR_ACCOUNT); let staking_pot = StakingPot::get(); - let foreign_asset_id_location = - xcm::v4::Location::new(2, [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::Rococo)]); + let foreign_asset_id_location = xcm::v5::Location::new( + 2, + [xcm::v5::Junction::GlobalConsensus(xcm::v5::NetworkId::ByGenesis(ROCOCO_GENESIS_HASH))], + ); let foreign_asset_id_minimum_balance = 1_000_000_000; // sovereign account as foreign asset owner (can be whoever for this scenario) let foreign_asset_owner = LocationToAccountId::convert_location(&Location::parent()).unwrap(); @@ -1216,7 +1223,7 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic bridging_to_asset_hub_rococo, ( [PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)].into(), - GlobalConsensus(Rococo), + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), [Parachain(1000)].into() ), || { @@ -1243,6 +1250,56 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic ) } +#[test] +fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { + asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + LocationToAccountId, + ToRococoXcmRouterInstance, + >( + collator_session_keys(), + bridging_to_asset_hub_rococo, + || bp_asset_hub_westend::build_congestion_message(Default::default(), true).into(), + || bp_asset_hub_westend::build_congestion_message(Default::default(), false).into(), + ) +} + +#[test] +fn test_report_bridge_status_call_compatibility() { + // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding + assert_eq!( + RuntimeCall::ToRococoXcmRouter(pallet_xcm_bridge_hub_router::Call::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + }) + .encode(), + bp_asset_hub_westend::Call::ToRococoXcmRouter( + bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { + bridge_id: Default::default(), + is_congested: true, + } + ) + .encode() + ) +} + +#[test] +fn check_sane_weight_report_bridge_status() { + use pallet_xcm_bridge_hub_router::WeightInfo; + let actual = >::WeightInfo::report_bridge_status(); + let max_weight = bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(); + assert!( + actual.all_lte(max_weight), + "max_weight: {:?} should be adjusted to actual {:?}", + max_weight, + actual + ); +} + #[test] fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { asset_test_utils::test_cases::change_storage_constant_by_governance_works::< @@ -1439,3 +1496,19 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); + asset_test_utils::test_cases::xcm_payment_api_with_pools_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index fb66f0de2322..de74f59f43c0 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -5,22 +5,24 @@ authors.workspace = true edition.workspace = true description = "Assets common utilities" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } -log = { workspace = true } impl-trait-for-tuples = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } # Substrate frame-support = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-assets = { workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } -pallet-assets = { workspace = true } -pallet-asset-conversion = { workspace = true } # Polkadot pallet-xcm = { workspace = true } @@ -29,8 +31,8 @@ xcm-builder = { workspace = true } xcm-executor = { workspace = true } # Cumulus -parachains-common = { workspace = true } cumulus-primitives-core = { workspace = true } +parachains-common = { workspace = true } [build-dependencies] substrate-wasm-builder = { workspace = true, default-features = true } @@ -64,4 +66,5 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index 26046e5974b5..25c2df6b68d1 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -28,7 +28,7 @@ extern crate alloc; use crate::matching::{LocalLocationPattern, ParentLocation}; use alloc::vec::Vec; use codec::{Decode, EncodeLike}; -use core::cmp::PartialEq; +use core::{cmp::PartialEq, marker::PhantomData}; use frame_support::traits::{Equals, EverythingBut}; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId}; use sp_runtime::traits::TryConvertInto; @@ -137,24 +137,62 @@ pub type PoolAssetsConvertedConcreteId = TryConvertInto, >; -/// Returns an iterator of all assets in a pool with `asset`. -/// -/// Should only be used in runtime APIs since it iterates over the whole -/// `pallet_asset_conversion::Pools` map. -/// -/// It takes in any version of an XCM Location but always returns the latest one. -/// This is to allow some margin of migrating the pools when updating the XCM version. -/// -/// An error of type `()` is returned if the version conversion fails for XCM locations. -/// This error should be mapped by the caller to a more descriptive one. -pub fn get_assets_in_pool_with< - Runtime: pallet_asset_conversion::Config, - L: TryInto + Clone + Decode + EncodeLike + PartialEq, ->( - asset: &L, -) -> Result, ()> { - pallet_asset_conversion::Pools::::iter_keys() - .filter_map(|(asset_1, asset_2)| { +/// Adapter implementation for accessing pools (`pallet_asset_conversion`) that uses `AssetKind` as +/// a `xcm::v*` which could be different from the `xcm::latest`. +pub struct PoolAdapter(PhantomData); +impl< + Runtime: pallet_asset_conversion::Config, + L: TryFrom + TryInto + Clone + Decode + EncodeLike + PartialEq, + > PoolAdapter +{ + /// Returns a vector of all assets in a pool with `asset`. + /// + /// Should only be used in runtime APIs since it iterates over the whole + /// `pallet_asset_conversion::Pools` map. + /// + /// It takes in any version of an XCM Location but always returns the latest one. + /// This is to allow some margin of migrating the pools when updating the XCM version. + /// + /// An error of type `()` is returned if the version conversion fails for XCM locations. + /// This error should be mapped by the caller to a more descriptive one. + pub fn get_assets_in_pool_with(asset: Location) -> Result, ()> { + // convert latest to the `L` version. + let asset: L = asset.try_into().map_err(|_| ())?; + Self::iter_assets_in_pool_with(&asset) + .map(|location| { + // convert `L` to the latest `AssetId` + location.try_into().map_err(|_| ()).map(AssetId) + }) + .collect::, _>>() + } + + /// Provides a current prices. Wrapper over + /// `pallet_asset_conversion::Pallet::::quote_price_tokens_for_exact_tokens`. + /// + /// An error of type `()` is returned if the version conversion fails for XCM locations. + /// This error should be mapped by the caller to a more descriptive one. + pub fn quote_price_tokens_for_exact_tokens( + asset_1: Location, + asset_2: Location, + amount: Runtime::Balance, + include_fees: bool, + ) -> Result, ()> { + // Convert latest to the `L` version. + let asset_1: L = asset_1.try_into().map_err(|_| ())?; + let asset_2: L = asset_2.try_into().map_err(|_| ())?; + + // Quote swap price. + Ok(pallet_asset_conversion::Pallet::::quote_price_tokens_for_exact_tokens( + asset_1, + asset_2, + amount, + include_fees, + )) + } + + /// Helper function for filtering pool. + pub fn iter_assets_in_pool_with(asset: &L) -> impl Iterator + '_ { + pallet_asset_conversion::Pools::::iter_keys().filter_map(|(asset_1, asset_2)| { if asset_1 == *asset { Some(asset_2) } else if asset_2 == *asset { @@ -163,8 +201,7 @@ pub fn get_assets_in_pool_with< None } }) - .map(|location| location.try_into().map_err(|_| ()).map(AssetId)) - .collect::, _>>() + } } #[cfg(test)] @@ -293,15 +330,15 @@ mod tests { pub UniversalLocationNetworkId: NetworkId = NetworkId::ByGenesis([9; 32]); } - // set up a converter which uses `xcm::v3::Location` under the hood + // set up a converter which uses `xcm::v4::Location` under the hood type Convert = ForeignAssetsConvertedConcreteId< ( StartsWith, StartsWithExplicitGlobalConsensus, ), u128, - xcm::v3::Location, - WithLatestLocationConverter, + xcm::v4::Location, + WithLatestLocationConverter, >; let test_data = vec![ @@ -348,18 +385,18 @@ mod tests { // ok ( ma_1000(1, [Parachain(200)].into()), - Ok((xcm::v3::Location::new(1, [xcm::v3::Junction::Parachain(200)]), 1000)), + Ok((xcm::v4::Location::new(1, [xcm::v4::Junction::Parachain(200)]), 1000)), ), ( ma_1000(2, [Parachain(200)].into()), - Ok((xcm::v3::Location::new(2, [xcm::v3::Junction::Parachain(200)]), 1000)), + Ok((xcm::v4::Location::new(2, [xcm::v4::Junction::Parachain(200)]), 1000)), ), ( ma_1000(1, [Parachain(200), GeneralIndex(1234)].into()), Ok(( - xcm::v3::Location::new( + xcm::v4::Location::new( 1, - [xcm::v3::Junction::Parachain(200), xcm::v3::Junction::GeneralIndex(1234)], + [xcm::v4::Junction::Parachain(200), xcm::v4::Junction::GeneralIndex(1234)], ), 1000, )), @@ -367,9 +404,9 @@ mod tests { ( ma_1000(2, [Parachain(200), GeneralIndex(1234)].into()), Ok(( - xcm::v3::Location::new( + xcm::v4::Location::new( 2, - [xcm::v3::Junction::Parachain(200), xcm::v3::Junction::GeneralIndex(1234)], + [xcm::v4::Junction::Parachain(200), xcm::v4::Junction::GeneralIndex(1234)], ), 1000, )), @@ -377,9 +414,9 @@ mod tests { ( ma_1000(2, [GlobalConsensus(NetworkId::ByGenesis([7; 32]))].into()), Ok(( - xcm::v3::Location::new( + xcm::v4::Location::new( 2, - [xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::ByGenesis( + [xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::ByGenesis( [7; 32], ))], ), @@ -397,14 +434,14 @@ mod tests { .into(), ), Ok(( - xcm::v3::Location::new( + xcm::v4::Location::new( 2, [ - xcm::v3::Junction::GlobalConsensus(xcm::v3::NetworkId::ByGenesis( + xcm::v4::Junction::GlobalConsensus(xcm::v4::NetworkId::ByGenesis( [7; 32], )), - xcm::v3::Junction::Parachain(200), - xcm::v3::Junction::GeneralIndex(1234), + xcm::v4::Junction::Parachain(200), + xcm::v4::Junction::GeneralIndex(1234), ], ), 1000, @@ -414,7 +451,7 @@ mod tests { for (asset, expected_result) in test_data { assert_eq!( - >::matches_fungibles( + >::matches_fungibles( &asset.clone().try_into().unwrap() ), expected_result, diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index 9ac2056a67f4..aa9d7929cb93 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -146,10 +146,11 @@ impl, OriginLocation: Get> mod tests { use super::*; use frame_support::parameter_types; + use xcm::latest::{ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}; parameter_types! { - pub UniversalLocation: InteriorLocation = [GlobalConsensus(Rococo), Parachain(1000)].into(); - pub ExpectedNetworkId: NetworkId = Wococo; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000)].into(); + pub ExpectedNetworkId: NetworkId = ByGenesis(WESTEND_GENESIS_HASH); } #[test] @@ -158,26 +159,30 @@ mod tests { let asset: Location = ( Parent, Parent, - GlobalConsensus(Wococo), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000), PalletInstance(1), GeneralIndex(1), ) .into(); - let origin: Location = (Parent, Parent, GlobalConsensus(Wococo), Parachain(1000)).into(); + let origin: Location = + (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000)) + .into(); assert!(FromNetwork::::contains(&asset, &origin)); // asset and origin from local consensus fails let asset: Location = ( Parent, Parent, - GlobalConsensus(Rococo), + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000), PalletInstance(1), GeneralIndex(1), ) .into(); - let origin: Location = (Parent, Parent, GlobalConsensus(Rococo), Parachain(1000)).into(); + let origin: Location = + (Parent, Parent, GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(1000)) + .into(); assert!(!FromNetwork::::contains(&asset, &origin)); // asset and origin from here fails @@ -195,14 +200,16 @@ mod tests { GeneralIndex(1), ) .into(); - let origin: Location = (Parent, Parent, GlobalConsensus(Wococo), Parachain(1000)).into(); + let origin: Location = + (Parent, Parent, GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000)) + .into(); assert!(!FromNetwork::::contains(&asset, &origin)); // origin from different consensus fails let asset: Location = ( Parent, Parent, - GlobalConsensus(Wococo), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(1000), PalletInstance(1), GeneralIndex(1), diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 529d6460fc4e..cad8d10a7da3 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Test utils for Asset Hub runtimes." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -15,27 +17,29 @@ codec = { features = ["derive", "max-encoded-len"], workspace = true } # Substrate frame-support = { workspace = true } frame-system = { workspace = true } +pallet-asset-conversion = { workspace = true } pallet-assets = { workspace = true } pallet-balances = { workspace = true } -pallet-timestamp = { workspace = true } pallet-session = { workspace = true } +pallet-timestamp = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } # Cumulus cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } -pallet-collator-selection = { workspace = true } -parachains-common = { workspace = true } cumulus-primitives-core = { workspace = true } +pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } +parachains-common = { workspace = true } parachains-runtimes-test-utils = { workspace = true } # Polkadot +pallet-xcm = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } -pallet-xcm = { workspace = true } +xcm-runtime-apis = { workspace = true } # Bridges pallet-xcm-bridge-hub-router = { workspace = true } @@ -55,6 +59,7 @@ std = [ "cumulus-primitives-core/std", "frame-support/std", "frame-system/std", + "pallet-asset-conversion/std", "pallet-assets/std", "pallet-balances/std", "pallet-collator-selection/std", @@ -69,5 +74,6 @@ std = [ "sp-runtime/std", "xcm-builder/std", "xcm-executor/std", + "xcm-runtime-apis/std", "xcm/std", ] 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 c80222142304..b1577e0ca7f6 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -34,11 +34,14 @@ use parachains_runtimes_test_utils::{ CollatorSessionKeys, ExtBuilder, SlotDurations, ValidatorIdOf, XcmReceivedFrom, }; use sp_runtime::{ - traits::{MaybeEquivalence, StaticLookup, Zero}, + traits::{Block as BlockT, MaybeEquivalence, StaticLookup, Zero}, DispatchError, Saturating, }; use xcm::{latest::prelude::*, VersionedAssets}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +use xcm_runtime_apis::fees::{ + runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, Error as XcmPaymentApiError, +}; type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; @@ -367,9 +370,9 @@ pub fn teleports_for_foreign_assets_works< ::Balance: From + Into, SovereignAccountOf: ConvertLocation>, >::AssetId: - From + Into, + From + Into, >::AssetIdParameter: - From + Into, + From + Into, >::Balance: From + Into, ::AccountId: @@ -381,11 +384,11 @@ pub fn teleports_for_foreign_assets_works< { // foreign parachain with the same consensus currency as asset let foreign_para_id = 2222; - let foreign_asset_id_location = xcm::v4::Location { + let foreign_asset_id_location = xcm::v5::Location { parents: 1, interior: [ - xcm::v4::Junction::Parachain(foreign_para_id), - xcm::v4::Junction::GeneralIndex(1234567), + xcm::v5::Junction::Parachain(foreign_para_id), + xcm::v5::Junction::GeneralIndex(1234567), ] .into(), }; @@ -1204,18 +1207,18 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(40_000_000_000, 8000), call: foreign_asset_create.into(), + fallback_max_weight: None, }, Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_set_metadata.into(), + fallback_max_weight: None, }, Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_set_team.into(), + fallback_max_weight: None, }, ExpectTransactStatus(MaybeErrorCode::Success), ]); @@ -1323,8 +1326,8 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_create.into(), + fallback_max_weight: None, }, ExpectTransactStatus(MaybeErrorCode::from(DispatchError::BadOrigin.encode())), ]); @@ -1594,3 +1597,108 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< ); }) } + +pub fn xcm_payment_api_with_pools_works() +where + Runtime: XcmPaymentApiV1 + + frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + cumulus_pallet_xcmp_queue::Config + + pallet_timestamp::Config + + pallet_assets::Config< + pallet_assets::Instance1, + AssetId = u32, + Balance = ::Balance, + > + pallet_asset_conversion::Config< + AssetKind = xcm::v5::Location, + Balance = ::Balance, + >, + ValidatorIdOf: From>, + RuntimeOrigin: OriginTrait::AccountId>, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + Block: BlockT, +{ + use xcm::prelude::*; + + ExtBuilder::::default().build().execute_with(|| { + let test_account = AccountId::from([0u8; 32]); + let transfer_amount = 100u128; + let xcm_to_weigh = Xcm::::builder_unsafe() + .withdraw_asset((Here, transfer_amount)) + .buy_execution((Here, transfer_amount), Unlimited) + .deposit_asset(AllCounted(1), [1u8; 32]) + .build(); + let versioned_xcm_to_weigh = VersionedXcm::from(xcm_to_weigh.clone().into()); + + let xcm_weight = Runtime::query_xcm_weight(versioned_xcm_to_weigh); + assert!(xcm_weight.is_ok()); + let native_token: Location = Parent.into(); + let native_token_versioned = VersionedAssetId::from(AssetId(native_token.clone())); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), native_token_versioned); + assert!(execution_fees.is_ok()); + + // We need some balance to create an asset. + assert_ok!( + pallet_balances::Pallet::::mint_into(&test_account, 3_000_000_000_000,) + ); + + // Now we try to use an asset that's not in a pool. + let asset_id = 1984u32; // USDT. + let asset_not_in_pool: Location = + (PalletInstance(50), GeneralIndex(asset_id.into())).into(); + assert_ok!(pallet_assets::Pallet::::create( + RuntimeOrigin::signed(test_account.clone()), + asset_id.into(), + test_account.clone().into(), + 1000 + )); + let execution_fees = Runtime::query_weight_to_asset_fee( + xcm_weight.unwrap(), + asset_not_in_pool.clone().into(), + ); + assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound)); + + // We add it to a pool with native. + assert_ok!(pallet_asset_conversion::Pallet::::create_pool( + RuntimeOrigin::signed(test_account.clone()), + native_token.clone().try_into().unwrap(), + asset_not_in_pool.clone().try_into().unwrap() + )); + let execution_fees = Runtime::query_weight_to_asset_fee( + xcm_weight.unwrap(), + asset_not_in_pool.clone().into(), + ); + // Still not enough because it doesn't have any liquidity. + assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound)); + + // We mint some of the asset... + assert_ok!(pallet_assets::Pallet::::mint( + RuntimeOrigin::signed(test_account.clone()), + asset_id.into(), + test_account.clone().into(), + 3_000_000_000_000, + )); + // ...so we can add liquidity to the pool. + assert_ok!(pallet_asset_conversion::Pallet::::add_liquidity( + RuntimeOrigin::signed(test_account.clone()), + native_token.try_into().unwrap(), + asset_not_in_pool.clone().try_into().unwrap(), + 1_000_000_000_000, + 2_000_000_000_000, + 0, + 0, + test_account + )); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), asset_not_in_pool.into()); + // Now it works! + assert_ok!(execution_fees); + }); +} diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index d86761174740..9b05f2d46dfb 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -331,7 +331,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< block_author_account: AccountIdOf, (foreign_asset_owner, foreign_asset_id_location, foreign_asset_id_minimum_balance): ( AccountIdOf, - xcm::v4::Location, + xcm::v5::Location, u128, ), foreign_asset_id_amount_to_transfer: u128, @@ -357,9 +357,9 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< BalanceOf: From + Into, XcmConfig: xcm_executor::Config, >::AssetId: - From + Into, + From + Into, >::AssetIdParameter: - From + Into, + From + Into, >::Balance: From + Into + From, ::AccountId: Into<<::RuntimeOrigin as OriginTrait>::AccountId> @@ -551,10 +551,7 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< Weight::zero(), ); assert_ok!(outcome.ensure_complete()); - assert_eq!( - is_congested, - <>::LocalXcmChannelManager as pallet_xcm_bridge_hub_router::XcmChannelStatusProvider>::is_congested(&local_bridge_hub_location) - ); + assert_eq!(is_congested, pallet_xcm_bridge_hub_router::Pallet::::bridge().is_congested); }; report_bridge_status(true); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 4af8a9f43850..3fabea3b02f4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Rococo's BridgeHub parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -32,9 +34,9 @@ frame-try-runtime = { optional = true, workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } -pallet-session = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } +pallet-session = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } @@ -43,10 +45,10 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -56,11 +58,11 @@ sp-transaction-pool = { workspace = true } sp-version = { workspace = true } # Polkadot -rococo-runtime-constants = { workspace = true } pallet-xcm = { workspace = true } pallet-xcm-benchmarks = { optional = true, workspace = true } polkadot-parachain-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } +rococo-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } @@ -93,27 +95,28 @@ bp-parachains = { workspace = true } bp-polkadot-bulletin = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } -bp-runtime = { workspace = true } bp-rococo = { workspace = true } +bp-runtime = { workspace = true } bp-westend = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +bridge-runtime-common = { workspace = true } pallet-bridge-grandpa = { workspace = true } pallet-bridge-messages = { workspace = true } pallet-bridge-parachains = { workspace = true } pallet-bridge-relayers = { workspace = true } pallet-xcm-bridge-hub = { workspace = true } -bridge-runtime-common = { workspace = true } # Ethereum Bridge (Snowbridge) snowbridge-beacon-primitives = { workspace = true } -snowbridge-pallet-system = { workspace = true } -snowbridge-system-runtime-api = { workspace = true } snowbridge-core = { workspace = true } +snowbridge-outbound-queue-runtime-api = { workspace = true } snowbridge-pallet-ethereum-client = { workspace = true } snowbridge-pallet-inbound-queue = { workspace = true } snowbridge-pallet-outbound-queue = { workspace = true } -snowbridge-outbound-queue-runtime-api = { workspace = true } +snowbridge-pallet-system = { workspace = true } snowbridge-router-primitives = { workspace = true } snowbridge-runtime-common = { workspace = true } +snowbridge-system-runtime-api = { workspace = true } bridge-hub-common = { workspace = true } @@ -121,6 +124,7 @@ bridge-hub-common = { workspace = true } bridge-hub-test-utils = { workspace = true, default-features = true } bridge-runtime-common = { features = ["integrity-test"], workspace = true, default-features = true } pallet-bridge-relayers = { features = ["integrity-test"], workspace = true } +parachains-runtimes-test-utils = { workspace = true, default-features = true } snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] @@ -140,6 +144,7 @@ std = [ "bp-rococo/std", "bp-runtime/std", "bp-westend/std", + "bp-xcm-bridge-hub-router/std", "bridge-hub-common/std", "bridge-runtime-common/std", "codec/std", @@ -261,6 +266,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ 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 c226ed9c4fa0..1e733503f43b 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 @@ -22,14 +22,13 @@ use crate::{ bridge_common_config::RelayersForPermissionlessLanesInstance, weights, xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeRococoBulletinGrandpa, - BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeHoldReason, - XcmOverRococoBulletin, XcmRouter, + BridgeRococoBulletinMessages, Runtime, RuntimeEvent, RuntimeHoldReason, XcmOverRococoBulletin, + XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, HashedLaneId, + target_chain::FromBridgedChainMessagesProof, LegacyLaneId, }; -use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; use frame_support::{ parameter_types, @@ -46,6 +45,7 @@ use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, + AlwaysV5, }; use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; @@ -120,7 +120,7 @@ impl pallet_bridge_messages::Config for Runt type OutboundPayload = XcmAsPlainPayload; type InboundPayload = XcmAsPlainPayload; - type LaneId = HashedLaneId; + type LaneId = LegacyLaneId; type DeliveryPayments = (); type DeliveryConfirmationPayments = (); @@ -139,8 +139,7 @@ impl pallet_xcm_bridge_hub::Config for Runtime type BridgeMessagesPalletInstance = WithRococoBulletinMessagesInstance; type MessageExportPrice = (); - type DestinationVersion = - XcmVersionOfDestAndRemoteBridge; + type DestinationVersion = AlwaysV5; type ForceOrigin = EnsureRoot; // We don't want to allow creating bridges for this instance. @@ -201,7 +200,6 @@ mod tests { fn ensure_bridge_integrity() { assert_complete_bridge_types!( runtime: Runtime, - with_bridged_chain_grandpa_instance: BridgeGrandpaRococoBulletinInstance, with_bridged_chain_messages_instance: WithRococoBulletinMessagesInstance, this_chain: bp_bridge_hub_rococo::BridgeHubRococo, bridged_chain: bp_polkadot_bulletin::PolkadotBulletin, @@ -246,14 +244,15 @@ where { use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use sp_runtime::traits::Zero; - use xcm::VersionedInteriorLocation; + use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation}; // insert bridge metadata let lane_id = with; let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); - let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into(); + let universal_source = + [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into(); let universal_destination = - [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get()), Parachain(2075)].into(); + [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); let bridge_id = BridgeId::new(&universal_source, &universal_destination); // insert only bridge metadata, because the benchmarks create lanes @@ -279,29 +278,3 @@ where universal_source } - -/// Contains the migration for the PeopleRococo<>RococoBulletin bridge. -pub mod migration { - use super::*; - use frame_support::traits::ConstBool; - - parameter_types! { - 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. - pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< - Runtime, - XcmOverPolkadotBulletinInstance, - RococoPeopleToRococoBulletinMessagesLane, - ConstBool, - PeopleRococoLocation, - BulletinRococoLocation, - >; -} 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 29ea4e05f29e..a14101eb454b 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 @@ -24,14 +24,14 @@ use crate::{ weights, xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, - RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, + RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, XcmpQueue, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, LegacyLaneId, }; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; -use pallet_xcm_bridge_hub::XcmAsPlainPayload; +use pallet_xcm_bridge_hub::{BridgeId, XcmAsPlainPayload}; use frame_support::{parameter_types, traits::PalletInfoAccess}; use frame_system::{EnsureNever, EnsureRoot}; @@ -43,14 +43,14 @@ use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSyst use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ - latest::prelude::*, + latest::{prelude::*, WESTEND_GENESIS_HASH}, prelude::{InteriorLocation, NetworkId}, }; use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; parameter_types! { pub BridgeRococoToWestendMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); - pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; + pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH); pub WestendGlobalConsensusNetworkLocation: Location = Location::new( 2, [GlobalConsensus(WestendGlobalConsensusNetwork::get())] @@ -121,6 +121,7 @@ impl pallet_bridge_messages::Config for Ru type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubWestendMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, DeliveryRewardInBalance, >; @@ -156,11 +157,46 @@ impl pallet_xcm_bridge_hub::Config for Runtime type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 - type LocalXcmChannelManager = (); + type LocalXcmChannelManager = CongestionManager; type BlobDispatcher = FromWestendMessageBlobDispatcher; } +/// Implementation of `bp_xcm_bridge_hub::LocalXcmChannelManager` for congestion management. +pub struct CongestionManager; +impl pallet_xcm_bridge_hub::LocalXcmChannelManager for CongestionManager { + type Error = SendError; + + fn is_congested(with: &Location) -> bool { + // This is used to check the inbound bridge queue/messages to determine if they can be + // dispatched and sent to the sibling parachain. Therefore, checking outbound `XcmpQueue` + // is sufficient here. + use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::::is_congested( + with, + ) + } + + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_rococo::build_congestion_message(bridge.inner(), true).into(), + ) + .map(|_| ()) + } + + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_rococo::build_congestion_message(bridge.inner(), false).into(), + ) + .map(|_| ()) + } +} + #[cfg(feature = "runtime-benchmarks")] pub(crate) fn open_bridge_for_benchmarks( with: pallet_xcm_bridge_hub::LaneIdOf, @@ -175,13 +211,15 @@ where { use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use sp_runtime::traits::Zero; - use xcm::VersionedInteriorLocation; + use xcm::{latest::ROCOCO_GENESIS_HASH, VersionedInteriorLocation}; // insert bridge metadata let lane_id = with; let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); - let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into(); - let universal_destination = [GlobalConsensus(Westend), Parachain(2075)].into(); + let universal_source = + [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(sibling_para_id)].into(); + let universal_destination = + [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(2075)].into(); let bridge_id = BridgeId::new(&universal_source, &universal_destination); // insert only bridge metadata, because the benchmarks create lanes @@ -254,7 +292,6 @@ mod tests { fn ensure_bridge_integrity() { assert_complete_bridge_types!( runtime: Runtime, - with_bridged_chain_grandpa_instance: BridgeGrandpaWestendInstance, with_bridged_chain_messages_instance: WithBridgeHubWestendMessagesInstance, this_chain: bp_bridge_hub_rococo::BridgeHubRococo, bridged_chain: bp_bridge_hub_westend::BridgeHubWestend, @@ -264,7 +301,6 @@ mod tests { Runtime, BridgeGrandpaWestendInstance, WithBridgeHubWestendMessagesInstance, - bp_westend::Westend, >(AssertCompleteBridgeConstants { this_chain_constants: AssertChainConstants { block_length: bp_bridge_hub_rococo::BlockLength::get(), 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 d1b599967bf3..55fd499c2f54 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 @@ -18,10 +18,12 @@ use crate::*; use alloc::{vec, vec::Vec}; use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; use parachains_common::{AccountId, AuraId}; use sp_genesis_builder::PresetId; use sp_keyring::Sr25519Keyring; use testnet_parachains_constants::rococo::xcm_version::SAFE_XCM_VERSION; +use xcm::latest::WESTEND_GENESIS_HASH; const BRIDGE_HUB_ROCOCO_ED: Balance = ExistentialDeposit::get(); @@ -33,7 +35,7 @@ fn bridge_hub_rococo_genesis( asset_hub_para_id: ParaId, opened_bridges: Vec<(Location, InteriorLocation, Option)>, ) -> serde_json::Value { - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -41,11 +43,10 @@ fn bridge_hub_rococo_genesis( .map(|k| (k, 1u128 << 60)) .collect::>(), }, - parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + parachain_info: ParachainInfoConfig { parachain_id: id }, collator_selection: CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), candidacy_bond: BRIDGE_HUB_ROCOCO_ED * 16, - ..Default::default() }, session: SessionConfig { keys: invulnerables @@ -58,39 +59,31 @@ fn bridge_hub_rococo_genesis( ) }) .collect(), - ..Default::default() }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - bridge_westend_grandpa: BridgeWestendGrandpaConfig { + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, + bridge_polkadot_bulletin_grandpa: BridgePolkadotBulletinGrandpaConfig { owner: bridges_pallet_owner.clone(), - ..Default::default() }, + bridge_westend_grandpa: BridgeWestendGrandpaConfig { owner: bridges_pallet_owner.clone() }, bridge_westend_messages: BridgeWestendMessagesConfig { 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, - ..Default::default() + xcm_over_polkadot_bulletin: XcmOverPolkadotBulletinConfig { + opened_bridges: vec![( + Location::new(1, [Parachain(1004)]), + Junctions::from([GlobalConsensus(NetworkId::PolkadotBulletin).into()]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 0])), + )], }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + xcm_over_bridge_hub_westend: XcmOverBridgeHubWestendConfig { opened_bridges }, + ethereum_system: EthereumSystemConfig { para_id: id, asset_hub_para_id }, + }) } /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => bridge_hub_rococo_genesis( + let patch = match id.as_ref() { + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => bridge_hub_rococo_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), @@ -102,11 +95,11 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option bridge_hub_rococo_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => bridge_hub_rococo_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), 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 f63e1f8fcf65..492b731610ce 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 @@ -47,7 +47,7 @@ use pallet_bridge_messages::LaneIdOf; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::Block as BlockT, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -80,6 +80,9 @@ use bridge_hub_common::{ }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +#[cfg(feature = "runtime-benchmarks")] +use xcm::latest::WESTEND_GENESIS_HASH; use xcm::VersionedLocation; use xcm_config::{TreasuryAccount, XcmOriginToTransactDispatchOrigin, XcmRouter}; @@ -166,7 +169,6 @@ pub type Migrations = ( bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, >, bridge_to_westend_config::migration::StaticToDynamicLanes, - bridge_to_bulletin_config::migration::StaticToDynamicLanes, frame_support::migrations::RemoveStorage< BridgeWestendMessagesPalletName, OutboundLanesCongestedSignalsKey, @@ -235,10 +237,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("bridge-hub-rococo"), - impl_name: create_runtime_str!("bridge-hub-rococo"), + spec_name: alloc::borrow::Cow::Borrowed("bridge-hub-rococo"), + impl_name: alloc::borrow::Cow::Borrowed("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -534,6 +536,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -843,7 +846,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -1070,7 +1074,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; @@ -1270,7 +1274,7 @@ impl_runtime_apis! { ); // open bridge - let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(8765)].into(); + let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)), Parachain(8765)].into(); let locations = XcmOverBridgeHubWestend::bridge_locations( sibling_parachain_location.clone(), bridge_destination_universal_location.clone(), @@ -1292,7 +1296,7 @@ impl_runtime_apis! { Ok( ( sibling_parachain_location, - NetworkId::Westend, + NetworkId::ByGenesis(WESTEND_GENESIS_HASH), [Parachain(8765)].into() ) ) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index a732e1a57343..0a085b858251 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `902e7ad7764b`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=bridge-hub-rococo-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=bridge-hub-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,14 +66,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 18_513_000 picoseconds. - Weight::from_parts(19_156_000, 0) + // Minimum execution time: 25_273_000 picoseconds. + Weight::from_parts(25_810_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -90,10 +94,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 88_096_000 picoseconds. - Weight::from_parts(89_732_000, 0) + // Minimum execution time: 112_156_000 picoseconds. + Weight::from_parts(115_999_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -108,6 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -126,21 +132,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 88_239_000 picoseconds. - Weight::from_parts(89_729_000, 0) + // Minimum execution time: 110_987_000 picoseconds. + Weight::from_parts(114_735_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 12_068_000 picoseconds. + Weight::from_parts(12_565_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -148,8 +155,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_955_000 picoseconds. - Weight::from_parts(6_266_000, 0) + // Minimum execution time: 7_155_000 picoseconds. + Weight::from_parts(7_606_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +166,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(1_961_000, 0) + // Minimum execution time: 2_325_000 picoseconds. + Weight::from_parts(2_442_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 24_388_000 picoseconds. - Weight::from_parts(25_072_000, 0) + // Minimum execution time: 31_747_000 picoseconds. + Weight::from_parts(33_122_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +219,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_762_000 picoseconds. - Weight::from_parts(27_631_000, 0) + // Minimum execution time: 36_396_000 picoseconds. + Weight::from_parts(37_638_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,45 +231,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_856_000 picoseconds. - Weight::from_parts(2_033_000, 0) + // Minimum execution time: 2_470_000 picoseconds. + Weight::from_parts(2_594_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `89` - // Estimated: `13454` - // Minimum execution time: 17_718_000 picoseconds. - Weight::from_parts(18_208_000, 0) - .saturating_add(Weight::from_parts(0, 13454)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15929` + // Minimum execution time: 22_530_000 picoseconds. + Weight::from_parts(22_987_000, 0) + .saturating_add(Weight::from_parts(0, 15929)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `93` - // Estimated: `13458` - // Minimum execution time: 17_597_000 picoseconds. - Weight::from_parts(18_090_000, 0) - .saturating_add(Weight::from_parts(0, 13458)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15933` + // Minimum execution time: 23_016_000 picoseconds. + Weight::from_parts(23_461_000, 0) + .saturating_add(Weight::from_parts(0, 15933)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `15946` - // Minimum execution time: 19_533_000 picoseconds. - Weight::from_parts(20_164_000, 0) - .saturating_add(Weight::from_parts(0, 15946)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18421` + // Minimum execution time: 26_216_000 picoseconds. + Weight::from_parts(26_832_000, 0) + .saturating_add(Weight::from_parts(0, 18421)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -282,36 +289,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 24_958_000 picoseconds. - Weight::from_parts(25_628_000, 0) + // Minimum execution time: 31_060_000 picoseconds. + Weight::from_parts(32_513_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `11026` - // Minimum execution time: 12_209_000 picoseconds. - Weight::from_parts(12_612_000, 0) - .saturating_add(Weight::from_parts(0, 11026)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `109` + // Estimated: `13474` + // Minimum execution time: 17_334_000 picoseconds. + Weight::from_parts(17_747_000, 0) + .saturating_add(Weight::from_parts(0, 13474)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `100` - // Estimated: `13465` - // Minimum execution time: 17_844_000 picoseconds. - Weight::from_parts(18_266_000, 0) - .saturating_add(Weight::from_parts(0, 13465)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15940` + // Minimum execution time: 22_535_000 picoseconds. + Weight::from_parts(23_386_000, 0) + .saturating_add(Weight::from_parts(0, 15940)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -328,11 +335,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 34_131_000 picoseconds. - Weight::from_parts(34_766_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(11)) + // Estimated: `15946` + // Minimum execution time: 43_437_000 picoseconds. + Weight::from_parts(44_588_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -343,8 +350,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_525_000 picoseconds. - Weight::from_parts(3_724_000, 0) + // Minimum execution time: 4_941_000 picoseconds. + Weight::from_parts(5_088_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,22 +362,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_975_000 picoseconds. - Weight::from_parts(25_517_000, 0) + // Minimum execution time: 29_996_000 picoseconds. + Weight::from_parts(30_700_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 33_761_000 picoseconds. - Weight::from_parts(34_674_000, 0) + // Minimum execution time: 41_828_000 picoseconds. + Weight::from_parts(43_026_000, 0) .saturating_add(Weight::from_parts(0, 3555)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs index b40cbfeeb8f2..efc2798999bf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/mod.rs @@ -22,7 +22,11 @@ use codec::Encode; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -83,7 +87,7 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -133,12 +137,35 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -231,4 +258,18 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index f2cee0e3e807..4a5623fc8b93 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 30_988_000 picoseconds. - Weight::from_parts(31_496_000, 3593) + // Minimum execution time: 32_488_000 picoseconds. + Weight::from_parts(33_257_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 42_805_000 picoseconds. - Weight::from_parts(44_207_000, 6196) + // Minimum execution time: 46_250_000 picoseconds. + Weight::from_parts(46_856_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `8799` - // Minimum execution time: 103_376_000 picoseconds. - Weight::from_parts(104_770_000, 8799) + // Minimum execution time: 106_863_000 picoseconds. + Weight::from_parts(109_554_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -124,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 71_234_000 picoseconds. - Weight::from_parts(72_990_000, 6196) + // Minimum execution time: 74_835_000 picoseconds. + Weight::from_parts(75_993_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -133,8 +133,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_636_000 picoseconds. - Weight::from_parts(2_777_000, 0) + // Minimum execution time: 2_709_000 picoseconds. + Weight::from_parts(2_901_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,8 +142,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 23_839_000 picoseconds. - Weight::from_parts(24_568_000, 3593) + // Minimum execution time: 25_194_000 picoseconds. + Weight::from_parts(25_805_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -167,8 +167,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `6196` - // Minimum execution time: 78_345_000 picoseconds. - Weight::from_parts(80_558_000, 6196) + // Minimum execution time: 82_570_000 picoseconds. + Weight::from_parts(84_060_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -192,9 +192,34 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 46_614_000 picoseconds. - Weight::from_parts(47_354_000, 3593) + // Minimum execution time: 51_959_000 picoseconds. + Weight::from_parts(53_434_000, 3593) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `122` + // Estimated: `6196` + // Minimum execution time: 86_918_000 picoseconds. + Weight::from_parts(89_460_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 9a9137c18093..daf22190a42b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 70_133_000 picoseconds. - Weight::from_parts(71_765_000, 6196) + // Minimum execution time: 69_010_000 picoseconds. + Weight::from_parts(70_067_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 959_000 picoseconds. - Weight::from_parts(996_000, 0) + // Minimum execution time: 1_069_000 picoseconds. + Weight::from_parts(1_116_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_011_000 picoseconds. + Weight::from_parts(2_095_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +93,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_537_000 picoseconds. - Weight::from_parts(7_876_000, 3497) + // Minimum execution time: 7_630_000 picoseconds. + Weight::from_parts(7_992_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_774_000 picoseconds. - Weight::from_parts(7_895_000, 0) + // Minimum execution time: 7_909_000 picoseconds. + Weight::from_parts(8_100_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_577_000 picoseconds. - Weight::from_parts(1_622_000, 0) + // Minimum execution time: 1_749_000 picoseconds. + Weight::from_parts(1_841_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 973_000 picoseconds. - Weight::from_parts(1_008_000, 0) + // Minimum execution time: 1_109_000 picoseconds. + Weight::from_parts(1_156_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_027_000 picoseconds. - Weight::from_parts(1_052_000, 0) + // Minimum execution time: 1_073_000 picoseconds. + Weight::from_parts(1_143_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 953_000 picoseconds. - Weight::from_parts(992_000, 0) + // Minimum execution time: 1_050_000 picoseconds. + Weight::from_parts(1_084_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 949_000 picoseconds. - Weight::from_parts(1_020_000, 0) + // Minimum execution time: 1_060_000 picoseconds. + Weight::from_parts(1_114_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 979_000 picoseconds. - Weight::from_parts(1_032_000, 0) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_112_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +166,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 66_663_000 picoseconds. - Weight::from_parts(67_728_000, 6196) + // Minimum execution time: 65_538_000 picoseconds. + Weight::from_parts(66_943_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +177,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_074_000 picoseconds. - Weight::from_parts(11_439_000, 3555) + // Minimum execution time: 10_898_000 picoseconds. + Weight::from_parts(11_262_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +186,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 943_000 picoseconds. - Weight::from_parts(1_021_000, 0) + // Minimum execution time: 1_026_000 picoseconds. + Weight::from_parts(1_104_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +207,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_123_000 picoseconds. - Weight::from_parts(25_687_000, 3503) + // Minimum execution time: 25_133_000 picoseconds. + Weight::from_parts(25_526_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +218,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_868_000 picoseconds. - Weight::from_parts(3_124_000, 0) + // Minimum execution time: 2_946_000 picoseconds. + Weight::from_parts(3_074_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_378_000 picoseconds. - Weight::from_parts(1_458_000, 0) + // Minimum execution time: 1_428_000 picoseconds. + Weight::from_parts(1_490_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_036_000 picoseconds. - Weight::from_parts(1_105_000, 0) + // Minimum execution time: 1_158_000 picoseconds. + Weight::from_parts(1_222_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 945_000 picoseconds. - Weight::from_parts(1_021_000, 0) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_117_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 931_000 picoseconds. - Weight::from_parts(1_006_000, 0) + // Minimum execution time: 1_045_000 picoseconds. + Weight::from_parts(1_084_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_139_000 picoseconds. - Weight::from_parts(1_206_000, 0) + // Minimum execution time: 1_224_000 picoseconds. + Weight::from_parts(1_268_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 72_884_000 picoseconds. - Weight::from_parts(74_331_000, 6196) + // Minimum execution time: 70_789_000 picoseconds. + Weight::from_parts(72_321_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_432_000 picoseconds. - Weight::from_parts(4_542_000, 0) + // Minimum execution time: 4_521_000 picoseconds. + Weight::from_parts(4_649_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +309,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 67_102_000 picoseconds. - Weight::from_parts(68_630_000, 6196) + // Minimum execution time: 66_129_000 picoseconds. + Weight::from_parts(68_089_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +318,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 995_000 picoseconds. - Weight::from_parts(1_057_000, 0) + // Minimum execution time: 1_094_000 picoseconds. + Weight::from_parts(1_157_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 956_000 picoseconds. - Weight::from_parts(1_021_000, 0) + // Minimum execution time: 1_059_000 picoseconds. + Weight::from_parts(1_109_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 944_000 picoseconds. - Weight::from_parts(986_000, 0) + // Minimum execution time: 1_053_000 picoseconds. + Weight::from_parts(1_080_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -343,12 +350,12 @@ impl WeightInfo { /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `589` - // Estimated: `6529` - // Minimum execution time: 58_111_000 picoseconds. - Weight::from_parts(59_123_071, 6529) - // Standard Error: 167 - .saturating_add(Weight::from_parts(43_658, 0).saturating_mul(x.into())) + // Measured: `190` + // Estimated: `6130` + // Minimum execution time: 42_081_000 picoseconds. + Weight::from_parts(42_977_658, 6130) + // Standard Error: 77 + .saturating_add(Weight::from_parts(44_912, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +363,28 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 950_000 picoseconds. - Weight::from_parts(1_002_000, 0) + // Minimum execution time: 1_041_000 picoseconds. + Weight::from_parts(1_084_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 963_000 picoseconds. - Weight::from_parts(1_012_000, 0) + // Minimum execution time: 1_085_000 picoseconds. + Weight::from_parts(1_161_000, 0) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 707_000 picoseconds. + Weight::from_parts(749_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 2fb186703a88..b37945317f6c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -40,7 +40,7 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use snowbridge_runtime_common::XcmExportFeeToSibling; use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -57,9 +57,10 @@ use xcm_executor::{ }; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const TokenLocation: Location = Location::parent(); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub RelayNetwork: NetworkId = NetworkId::Rococo; + pub RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); pub const MaxInstructions: u32 = 100; @@ -164,6 +165,7 @@ pub type Barrier = TrailingSetTopicAsId< /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, ); @@ -296,7 +298,7 @@ impl, FeeHandler: HandleFee> FeeManager fn is_waived(origin: Option<&Location>, fee_reason: FeeReason) -> bool { let Some(loc) = origin else { return false }; if let Export { network, destination: Here } = fee_reason { - if network == EthereumNetwork::get() { + if network == EthereumNetwork::get().into() { return 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 8be2993c68f4..d5baa1c71dfd 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 @@ -29,7 +29,7 @@ use frame_support::parameter_types; use parachains_common::{AccountId, AuraId, Balance}; use snowbridge_pallet_ethereum_client::WeightInfo; use sp_core::H160; -use sp_keyring::AccountKeyring::Alice; +use sp_keyring::Sr25519Keyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, AccountId32, @@ -166,7 +166,7 @@ pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works() { } fn construct_extrinsic( - sender: sp_keyring::AccountKeyring, + sender: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); @@ -192,7 +192,7 @@ fn construct_extrinsic( } fn construct_and_apply_extrinsic( - origin: sp_keyring::AccountKeyring, + origin: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> sp_runtime::DispatchOutcome { let xt = construct_extrinsic(origin, call); 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 01674287fde1..8d74b221a609 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 @@ -20,9 +20,9 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ bridge_common_config, bridge_to_bulletin_config, bridge_to_westend_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, - AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - TransactionPayment, TxExtension, UncheckedExtrinsic, + AllPalletsWithoutSystem, Block, BridgeRejectObsoleteHeadersAndMessages, Executive, + ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeOrigin, SessionKeys, TransactionPayment, TxExtension, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; @@ -31,13 +31,13 @@ use parachains_common::{AccountId, AuraId, Balance}; use snowbridge_core::ChannelId; use sp_consensus_aura::SlotDuration; use sp_core::{crypto::Ss58Codec, H160}; -use sp_keyring::AccountKeyring::Alice; +use sp_keyring::Sr25519Keyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, AccountId32, Perbill, }; use testnet_parachains_constants::rococo::{consensus::*, fee::WeightToFee}; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_runtime_apis::conversions::LocationToAccountHelper; parameter_types! { @@ -45,7 +45,7 @@ parameter_types! { } fn construct_extrinsic( - sender: sp_keyring::AccountKeyring, + sender: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); @@ -72,7 +72,7 @@ fn construct_extrinsic( } fn construct_and_apply_extrinsic( - relayer_at_target: sp_keyring::AccountKeyring, + relayer_at_target: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> sp_runtime::DispatchOutcome { let xt = construct_extrinsic(relayer_at_target, call); @@ -324,11 +324,12 @@ mod bridge_hub_westend_tests { >( SiblingParachainLocation::get(), BridgedUniversalLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubWestendInstance - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, LegacyLaneId([0, 0, 0, 1])) } ).1 }, @@ -377,7 +378,7 @@ mod bridge_hub_westend_tests { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, SIBLING_PARACHAIN_ID, - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), || { // we need to create lane between sibling parachain and remote destination bridge_hub_test_utils::ensure_opened_bridge::< @@ -388,11 +389,12 @@ mod bridge_hub_westend_tests { >( SiblingParachainLocation::get(), BridgedUniversalLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubWestendInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, LegacyLaneId([0, 0, 0, 1])) }, ) .1 @@ -411,7 +413,7 @@ mod bridge_hub_westend_tests { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, SIBLING_PARACHAIN_ID, - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), || { // we need to create lane between sibling parachain and remote destination bridge_hub_test_utils::ensure_opened_bridge::< @@ -422,11 +424,12 @@ mod bridge_hub_westend_tests { >( SiblingParachainLocation::get(), BridgedUniversalLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubWestendInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, LegacyLaneId([0, 0, 0, 1])) }, ) .1 @@ -498,10 +501,10 @@ mod bridge_hub_westend_tests { mod bridge_hub_bulletin_tests { use super::*; - use bp_messages::{HashedLaneId, LaneIdType}; + use bp_messages::LegacyLaneId; use bridge_common_config::BridgeGrandpaRococoBulletinInstance; use bridge_hub_rococo_runtime::{ - bridge_common_config::RelayersForPermissionlessLanesInstance, + bridge_common_config::RelayersForLegacyLaneIdsMessagesInstance, xcm_config::LocationToAccountId, }; use bridge_hub_test_utils::test_cases::from_grandpa_chain; @@ -525,7 +528,7 @@ mod bridge_hub_bulletin_tests { AllPalletsWithoutSystem, BridgeGrandpaRococoBulletinInstance, WithRococoBulletinMessagesInstance, - RelayersForPermissionlessLanesInstance, + RelayersForLegacyLaneIdsMessagesInstance, >; #[test] @@ -591,11 +594,12 @@ mod bridge_hub_bulletin_tests { >( SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverPolkadotBulletinInstance - >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + >(locations, LegacyLaneId([0, 0, 0, 0])) } ).1 }, @@ -643,7 +647,7 @@ mod bridge_hub_bulletin_tests { slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PEOPLE_PARACHAIN_ID, - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), || { // we need to create lane between RococoPeople and RococoBulletin bridge_hub_test_utils::ensure_opened_bridge::< @@ -654,11 +658,12 @@ mod bridge_hub_bulletin_tests { >( SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverPolkadotBulletinInstance, - >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + >(locations, LegacyLaneId([0, 0, 0, 0])) }, ) .1 @@ -676,7 +681,7 @@ mod bridge_hub_bulletin_tests { slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PEOPLE_PARACHAIN_ID, - Rococo, + ByGenesis(ROCOCO_GENESIS_HASH), || { // we need to create lane between RococoPeople and RococoBulletin bridge_hub_test_utils::ensure_opened_bridge::< @@ -687,11 +692,12 @@ mod bridge_hub_bulletin_tests { >( SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverPolkadotBulletinInstance, - >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + >(locations, LegacyLaneId([0, 0, 0, 0])) }, ) .1 @@ -832,3 +838,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 637e7c710640..644aa72d1311 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Westend's BridgeHub parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -32,9 +34,9 @@ frame-try-runtime = { optional = true, workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } -pallet-session = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } +pallet-session = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } @@ -43,10 +45,10 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -56,11 +58,11 @@ sp-transaction-pool = { workspace = true } sp-version = { workspace = true } # Polkadot -westend-runtime-constants = { workspace = true } pallet-xcm = { workspace = true } pallet-xcm-benchmarks = { optional = true, workspace = true } polkadot-parachain-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } +westend-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } @@ -74,8 +76,8 @@ cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } @@ -92,34 +94,36 @@ bp-messages = { workspace = true } bp-parachains = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } -bp-runtime = { workspace = true } bp-rococo = { workspace = true } +bp-runtime = { workspace = true } bp-westend = { workspace = true } +bp-xcm-bridge-hub-router = { workspace = true } +bridge-hub-common = { workspace = true } +bridge-runtime-common = { workspace = true } pallet-bridge-grandpa = { workspace = true } pallet-bridge-messages = { workspace = true } pallet-bridge-parachains = { workspace = true } pallet-bridge-relayers = { workspace = true } pallet-xcm-bridge-hub = { workspace = true } -bridge-runtime-common = { workspace = true } -bridge-hub-common = { workspace = true } # Ethereum Bridge (Snowbridge) snowbridge-beacon-primitives = { workspace = true } -snowbridge-pallet-system = { workspace = true } -snowbridge-system-runtime-api = { workspace = true } snowbridge-core = { workspace = true } +snowbridge-outbound-queue-runtime-api = { workspace = true } snowbridge-pallet-ethereum-client = { workspace = true } snowbridge-pallet-inbound-queue = { workspace = true } snowbridge-pallet-outbound-queue = { workspace = true } -snowbridge-outbound-queue-runtime-api = { workspace = true } +snowbridge-pallet-system = { workspace = true } snowbridge-router-primitives = { workspace = true } snowbridge-runtime-common = { workspace = true } +snowbridge-system-runtime-api = { workspace = true } [dev-dependencies] bridge-hub-test-utils = { workspace = true, default-features = true } bridge-runtime-common = { features = ["integrity-test"], workspace = true, default-features = true } pallet-bridge-relayers = { features = ["integrity-test"], workspace = true } +parachains-runtimes-test-utils = { workspace = true, default-features = true } snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] @@ -137,6 +141,7 @@ std = [ "bp-rococo/std", "bp-runtime/std", "bp-westend/std", + "bp-xcm-bridge-hub-router/std", "bridge-hub-common/std", "bridge-runtime-common/std", "codec/std", @@ -258,6 +263,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index dbca4166a135..94921fd8af9a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -229,3 +229,48 @@ pub mod benchmark_helpers { } } } + +pub(crate) mod migrations { + use alloc::vec::Vec; + use frame_support::pallet_prelude::*; + use snowbridge_core::TokenId; + + #[frame_support::storage_alias] + pub type OldNativeToForeignId = StorageMap< + snowbridge_pallet_system::Pallet, + Blake2_128Concat, + xcm::v4::Location, + TokenId, + OptionQuery, + >; + + /// One shot migration for NetworkId::Westend to NetworkId::ByGenesis(WESTEND_GENESIS_HASH) + pub struct MigrationForXcmV5(core::marker::PhantomData); + impl frame_support::traits::OnRuntimeUpgrade + for MigrationForXcmV5 + { + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + let translate_westend = |pre: xcm::v4::Location| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(xcm::v5::Location::try_from(pre).expect("valid location")) + }; + snowbridge_pallet_system::ForeignToNativeId::::translate_values(translate_westend); + + let old_keys = OldNativeToForeignId::::iter_keys().collect::>(); + for old_key in old_keys { + if let Some(old_val) = OldNativeToForeignId::::get(&old_key) { + snowbridge_pallet_system::NativeToForeignId::::insert( + &xcm::v5::Location::try_from(old_key.clone()).expect("valid location"), + old_val, + ); + } + OldNativeToForeignId::::remove(old_key); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + + weight + } + } +} 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 aca51b320e9b..24e5482b7b09 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 @@ -21,7 +21,7 @@ use crate::{ weights, xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, - RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, + RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, XcmpQueue, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, @@ -29,7 +29,7 @@ use bp_messages::{ }; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; -use pallet_xcm_bridge_hub::XcmAsPlainPayload; +use pallet_xcm_bridge_hub::{BridgeId, XcmAsPlainPayload}; use frame_support::{ parameter_types, @@ -44,7 +44,7 @@ use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSyst use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::westend::currency::UNITS as WND; use xcm::{ - latest::prelude::*, + latest::{prelude::*, ROCOCO_GENESIS_HASH}, prelude::{InteriorLocation, NetworkId}, }; use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; @@ -57,7 +57,7 @@ parameter_types! { pub const MaxRococoParaHeadDataSize: u32 = bp_rococo::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; pub BridgeWestendToRococoMessagesPalletInstance: InteriorLocation = [PalletInstance(::index() as u8)].into(); - pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; + pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub RococoGlobalConsensusNetworkLocation: Location = Location::new( 2, [GlobalConsensus(RococoGlobalConsensusNetwork::get())] @@ -152,6 +152,7 @@ impl pallet_bridge_messages::Config for Run type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubRococoMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, DeliveryRewardInBalance, >; @@ -185,11 +186,46 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type AllowWithoutBridgeDeposit = RelayOrOtherSystemParachains; - // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 - type LocalXcmChannelManager = (); + type LocalXcmChannelManager = CongestionManager; type BlobDispatcher = FromRococoMessageBlobDispatcher; } +/// Implementation of `bp_xcm_bridge_hub::LocalXcmChannelManager` for congestion management. +pub struct CongestionManager; +impl pallet_xcm_bridge_hub::LocalXcmChannelManager for CongestionManager { + type Error = SendError; + + fn is_congested(with: &Location) -> bool { + // This is used to check the inbound bridge queue/messages to determine if they can be + // dispatched and sent to the sibling parachain. Therefore, checking outbound `XcmpQueue` + // is sufficient here. + use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; + cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider::::is_congested( + with, + ) + } + + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_westend::build_congestion_message(bridge.inner(), true).into(), + ) + .map(|_| ()) + } + + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error> { + // This bridge is intended for AH<>AH communication with a hard-coded/static lane, + // so `local_origin` is expected to represent only the local AH. + send_xcm::( + local_origin.clone(), + bp_asset_hub_westend::build_congestion_message(bridge.inner(), false).into(), + ) + .map(|_| ()) + } +} + #[cfg(feature = "runtime-benchmarks")] pub(crate) fn open_bridge_for_benchmarks( with: pallet_xcm_bridge_hub::LaneIdOf, @@ -204,13 +240,15 @@ where { use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use sp_runtime::traits::Zero; - use xcm::VersionedInteriorLocation; + use xcm::{latest::WESTEND_GENESIS_HASH, VersionedInteriorLocation}; // insert bridge metadata let lane_id = with; let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); - let universal_source = [GlobalConsensus(Westend), Parachain(sibling_para_id)].into(); - let universal_destination = [GlobalConsensus(Rococo), Parachain(2075)].into(); + let universal_source = + [GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), Parachain(sibling_para_id)].into(); + let universal_destination = + [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(2075)].into(); let bridge_id = BridgeId::new(&universal_source, &universal_destination); // insert only bridge metadata, because the benchmarks create lanes @@ -282,7 +320,6 @@ mod tests { fn ensure_bridge_integrity() { assert_complete_bridge_types!( runtime: Runtime, - with_bridged_chain_grandpa_instance: BridgeGrandpaRococoInstance, with_bridged_chain_messages_instance: WithBridgeHubRococoMessagesInstance, this_chain: bp_bridge_hub_westend::BridgeHubWestend, bridged_chain: bp_bridge_hub_rococo::BridgeHubRococo, @@ -292,7 +329,6 @@ mod tests { Runtime, BridgeGrandpaRococoInstance, WithBridgeHubRococoMessagesInstance, - bp_rococo::Rococo, >(AssertCompleteBridgeConstants { this_chain_constants: AssertChainConstants { block_length: bp_bridge_hub_westend::BlockLength::get(), @@ -332,7 +368,6 @@ mod tests { pub mod migration { use super::*; use bp_messages::LegacyLaneId; - use frame_support::traits::ConstBool; parameter_types! { pub AssetHubWestendToAssetHubRococoMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]); @@ -340,18 +375,6 @@ pub mod migration { pub AssetHubRococoUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)].into(); } - /// Ensure that the existing lanes for the AHW<>AHR bridge are correctly configured. - pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< - Runtime, - XcmOverBridgeHubRococoInstance, - AssetHubWestendToAssetHubRococoMessagesLane, - // the lanes are already created for AHR<>AHW, but we need to link them to the bridge - // structs - ConstBool, - AssetHubWestendLocation, - AssetHubRococoUniversalLocation, - >; - mod v1_wrong { use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer}; use bp_runtime::AccountIdOf; 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 2949ae01fdcc..69ba9ca9ece7 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 @@ -18,10 +18,12 @@ use crate::*; use alloc::{vec, vec::Vec}; use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; use parachains_common::{AccountId, AuraId}; use sp_genesis_builder::PresetId; use sp_keyring::Sr25519Keyring; use testnet_parachains_constants::westend::xcm_version::SAFE_XCM_VERSION; +use xcm::latest::ROCOCO_GENESIS_HASH; const BRIDGE_HUB_WESTEND_ED: Balance = ExistentialDeposit::get(); @@ -33,7 +35,7 @@ fn bridge_hub_westend_genesis( asset_hub_para_id: ParaId, opened_bridges: Vec<(Location, InteriorLocation, Option)>, ) -> serde_json::Value { - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -41,11 +43,10 @@ fn bridge_hub_westend_genesis( .map(|k| (k, 1u128 << 60)) .collect::>(), }, - parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + parachain_info: ParachainInfoConfig { parachain_id: id }, collator_selection: CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), candidacy_bond: BRIDGE_HUB_WESTEND_ED * 16, - ..Default::default() }, session: SessionConfig { keys: invulnerables @@ -58,39 +59,19 @@ fn bridge_hub_westend_genesis( ) }) .collect(), - ..Default::default() }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - bridge_rococo_grandpa: BridgeRococoGrandpaConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() - }, - bridge_rococo_messages: BridgeRococoMessagesConfig { - 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, - ..Default::default() - }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, + bridge_rococo_grandpa: BridgeRococoGrandpaConfig { owner: bridges_pallet_owner.clone() }, + bridge_rococo_messages: BridgeRococoMessagesConfig { owner: bridges_pallet_owner.clone() }, + xcm_over_bridge_hub_rococo: XcmOverBridgeHubRococoConfig { opened_bridges }, + ethereum_system: EthereumSystemConfig { para_id: id, asset_hub_para_id }, + }) } /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => bridge_hub_westend_genesis( + let patch = match id.as_ref() { + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => bridge_hub_westend_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), @@ -102,11 +83,14 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option bridge_hub_westend_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => bridge_hub_westend_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), 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 1d7cd5de40eb..edf79ea0c315 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 @@ -45,7 +45,7 @@ use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector, ParaId}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::Block as BlockT, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -87,6 +87,9 @@ use pallet_bridge_messages::LaneIdOf; pub use sp_runtime::BuildStorage; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; + +#[cfg(feature = "runtime-benchmarks")] +use xcm::latest::ROCOCO_GENESIS_HASH; use xcm::prelude::*; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -152,20 +155,20 @@ pub type Migrations = ( 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< Runtime, ConstU32, ConstU32, >, + bridge_to_ethereum_config::migrations::MigrationForXcmV5, + // permanent + pallet_xcm::migration::MigrateToLatestXcmVersion, ); parameter_types! { @@ -220,10 +223,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("bridge-hub-westend"), - impl_name: create_runtime_str!("bridge-hub-westend"), + spec_name: alloc::borrow::Cow::Borrowed("bridge-hub-westend"), + impl_name: alloc::borrow::Cow::Borrowed("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -510,6 +513,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -775,7 +779,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::WestendLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -955,7 +960,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; @@ -1155,7 +1160,7 @@ impl_runtime_apis! { ); // open bridge - let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Rococo), Parachain(8765)].into(); + let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), Parachain(8765)].into(); let locations = XcmOverBridgeHubRococo::bridge_locations( sibling_parachain_location.clone(), bridge_destination_universal_location.clone(), @@ -1177,7 +1182,7 @@ impl_runtime_apis! { Ok( ( sibling_parachain_location, - NetworkId::Rococo, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), [Parachain(8765)].into() ) ) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index a78ff2355efa..fdae0c9a1522 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `27f89d982f9b`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=bridge-hub-westend-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=bridge-hub-westend-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,14 +66,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 19_527_000 picoseconds. - Weight::from_parts(19_839_000, 0) + // Minimum execution time: 24_819_000 picoseconds. + Weight::from_parts(25_795_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -90,10 +94,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 90_938_000 picoseconds. - Weight::from_parts(92_822_000, 0) + // Minimum execution time: 110_536_000 picoseconds. + Weight::from_parts(115_459_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -108,6 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -126,21 +132,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 90_133_000 picoseconds. - Weight::from_parts(92_308_000, 0) + // Minimum execution time: 109_742_000 picoseconds. + Weight::from_parts(114_362_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 12_252_000 picoseconds. + Weight::from_parts(12_681_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -148,8 +155,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_205_000 picoseconds. - Weight::from_parts(6_595_000, 0) + // Minimum execution time: 6_988_000 picoseconds. + Weight::from_parts(7_161_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +166,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_927_000 picoseconds. - Weight::from_parts(2_062_000, 0) + // Minimum execution time: 2_249_000 picoseconds. + Weight::from_parts(2_479_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_078_000 picoseconds. - Weight::from_parts(25_782_000, 0) + // Minimum execution time: 31_668_000 picoseconds. + Weight::from_parts(32_129_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +219,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 28_188_000 picoseconds. - Weight::from_parts(28_826_000, 0) + // Minimum execution time: 36_002_000 picoseconds. + Weight::from_parts(37_341_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,45 +231,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_886_000 picoseconds. - Weight::from_parts(1_991_000, 0) + // Minimum execution time: 2_349_000 picoseconds. + Weight::from_parts(2_511_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `89` - // Estimated: `13454` - // Minimum execution time: 17_443_000 picoseconds. - Weight::from_parts(17_964_000, 0) - .saturating_add(Weight::from_parts(0, 13454)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15929` + // Minimum execution time: 22_283_000 picoseconds. + Weight::from_parts(22_654_000, 0) + .saturating_add(Weight::from_parts(0, 15929)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `93` - // Estimated: `13458` - // Minimum execution time: 17_357_000 picoseconds. - Weight::from_parts(18_006_000, 0) - .saturating_add(Weight::from_parts(0, 13458)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15933` + // Minimum execution time: 22_717_000 picoseconds. + Weight::from_parts(23_256_000, 0) + .saturating_add(Weight::from_parts(0, 15933)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `15946` - // Minimum execution time: 18_838_000 picoseconds. - Weight::from_parts(19_688_000, 0) - .saturating_add(Weight::from_parts(0, 15946)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18421` + // Minimum execution time: 25_988_000 picoseconds. + Weight::from_parts(26_794_000, 0) + .saturating_add(Weight::from_parts(0, 18421)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -282,36 +289,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 25_517_000 picoseconds. - Weight::from_parts(26_131_000, 0) + // Minimum execution time: 31_112_000 picoseconds. + Weight::from_parts(32_395_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `11026` - // Minimum execution time: 11_587_000 picoseconds. - Weight::from_parts(11_963_000, 0) - .saturating_add(Weight::from_parts(0, 11026)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `109` + // Estimated: `13474` + // Minimum execution time: 17_401_000 picoseconds. + Weight::from_parts(17_782_000, 0) + .saturating_add(Weight::from_parts(0, 13474)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `100` - // Estimated: `13465` - // Minimum execution time: 17_490_000 picoseconds. - Weight::from_parts(18_160_000, 0) - .saturating_add(Weight::from_parts(0, 13465)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15940` + // Minimum execution time: 22_772_000 picoseconds. + Weight::from_parts(23_194_000, 0) + .saturating_add(Weight::from_parts(0, 15940)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -328,11 +335,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 34_088_000 picoseconds. - Weight::from_parts(34_598_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(11)) + // Estimated: `15946` + // Minimum execution time: 43_571_000 picoseconds. + Weight::from_parts(44_891_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -343,8 +350,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_566_000 picoseconds. - Weight::from_parts(3_754_000, 0) + // Minimum execution time: 4_896_000 picoseconds. + Weight::from_parts(5_112_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,22 +362,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_078_000 picoseconds. - Weight::from_parts(25_477_000, 0) + // Minimum execution time: 30_117_000 picoseconds. + Weight::from_parts(31_027_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_661_000 picoseconds. - Weight::from_parts(35_411_000, 0) + // Minimum execution time: 41_870_000 picoseconds. + Weight::from_parts(42_750_000, 0) .saturating_add(Weight::from_parts(0, 3555)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs index 3961cc6d5cdd..15a1dae09d9b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/mod.rs @@ -23,7 +23,11 @@ use codec::Encode; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -84,7 +88,7 @@ impl XcmWeightInfo for BridgeHubWestendXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -134,12 +138,35 @@ impl XcmWeightInfo for BridgeHubWestendXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -152,6 +179,17 @@ impl XcmWeightInfo for BridgeHubWestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -232,4 +270,7 @@ impl XcmWeightInfo for BridgeHubWestendXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 5bd1d1680aa1..555303d30b61 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 30_218_000 picoseconds. - Weight::from_parts(30_783_000, 3593) + // Minimum execution time: 31_340_000 picoseconds. + Weight::from_parts(32_044_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 42_631_000 picoseconds. - Weight::from_parts(43_127_000, 6196) + // Minimum execution time: 44_483_000 picoseconds. + Weight::from_parts(45_215_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +90,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `260` // Estimated: `8799` - // Minimum execution time: 100_978_000 picoseconds. - Weight::from_parts(102_819_000, 8799) + // Minimum execution time: 106_531_000 picoseconds. + Weight::from_parts(109_012_000, 8799) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -124,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 71_533_000 picoseconds. - Weight::from_parts(72_922_000, 6196) + // Minimum execution time: 75_043_000 picoseconds. + Weight::from_parts(77_425_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -133,8 +133,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_863_000 picoseconds. - Weight::from_parts(2_997_000, 0) + // Minimum execution time: 2_739_000 picoseconds. + Weight::from_parts(2_855_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,8 +142,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 23_763_000 picoseconds. - Weight::from_parts(24_438_000, 3593) + // Minimum execution time: 25_043_000 picoseconds. + Weight::from_parts(25_297_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -167,8 +167,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `6196` - // Minimum execution time: 78_182_000 picoseconds. - Weight::from_parts(79_575_000, 6196) + // Minimum execution time: 82_421_000 picoseconds. + Weight::from_parts(84_128_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -192,9 +192,34 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 46_767_000 picoseconds. - Weight::from_parts(47_823_000, 3593) + // Minimum execution time: 52_465_000 picoseconds. + Weight::from_parts(53_568_000, 3593) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } + // Storage: `System::Account` (r:2 w:2) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + // Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `159` + // Estimated: `6196` + // Minimum execution time: 87_253_000 picoseconds. + Weight::from_parts(88_932_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 16c483a21817..03cbaa866ad8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 70_715_000 picoseconds. - Weight::from_parts(72_211_000, 6196) + // Minimum execution time: 70_353_000 picoseconds. + Weight::from_parts(72_257_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 968_000 picoseconds. - Weight::from_parts(1_022_000, 0) + // Minimum execution time: 996_000 picoseconds. + Weight::from_parts(1_027_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_926_000 picoseconds. + Weight::from_parts(2_033_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +93,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_718_000 picoseconds. - Weight::from_parts(7_894_000, 3497) + // Minimum execution time: 7_961_000 picoseconds. + Weight::from_parts(8_256_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_662_000 picoseconds. - Weight::from_parts(7_937_000, 0) + // Minimum execution time: 7_589_000 picoseconds. + Weight::from_parts(7_867_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_699_000 picoseconds. - Weight::from_parts(1_783_000, 0) + // Minimum execution time: 1_602_000 picoseconds. + Weight::from_parts(1_660_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 977_000 picoseconds. - Weight::from_parts(1_045_000, 0) + // Minimum execution time: 1_056_000 picoseconds. + Weight::from_parts(1_096_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 971_000 picoseconds. - Weight::from_parts(1_030_000, 0) + // Minimum execution time: 1_014_000 picoseconds. + Weight::from_parts(1_075_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 958_000 picoseconds. - Weight::from_parts(996_000, 0) + // Minimum execution time: 986_000 picoseconds. + Weight::from_parts(1_031_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 992_000 picoseconds. - Weight::from_parts(1_056_000, 0) + // Minimum execution time: 1_015_000 picoseconds. + Weight::from_parts(1_069_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 975_000 picoseconds. - Weight::from_parts(1_026_000, 0) + // Minimum execution time: 993_000 picoseconds. + Weight::from_parts(1_063_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +166,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 67_236_000 picoseconds. - Weight::from_parts(68_712_000, 6196) + // Minimum execution time: 66_350_000 picoseconds. + Weight::from_parts(68_248_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +177,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 10_890_000 picoseconds. - Weight::from_parts(11_223_000, 3555) + // Minimum execution time: 11_247_000 picoseconds. + Weight::from_parts(11_468_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +186,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 959_000 picoseconds. - Weight::from_parts(1_018_000, 0) + // Minimum execution time: 1_060_000 picoseconds. + Weight::from_parts(1_103_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +207,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_162_000 picoseconds. - Weight::from_parts(25_621_000, 3503) + // Minimum execution time: 25_599_000 picoseconds. + Weight::from_parts(26_336_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +218,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_949_000 picoseconds. - Weight::from_parts(3_119_000, 0) + // Minimum execution time: 2_863_000 picoseconds. + Weight::from_parts(3_090_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_329_000 picoseconds. - Weight::from_parts(1_410_000, 0) + // Minimum execution time: 1_385_000 picoseconds. + Weight::from_parts(1_468_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_063_000 picoseconds. - Weight::from_parts(1_101_000, 0) + // Minimum execution time: 1_087_000 picoseconds. + Weight::from_parts(1_164_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 991_000 picoseconds. - Weight::from_parts(1_041_000, 0) + // Minimum execution time: 1_022_000 picoseconds. + Weight::from_parts(1_066_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 944_000 picoseconds. - Weight::from_parts(998_000, 0) + // Minimum execution time: 1_015_000 picoseconds. + Weight::from_parts(1_070_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_100_000 picoseconds. - Weight::from_parts(1_180_000, 0) + // Minimum execution time: 1_203_000 picoseconds. + Weight::from_parts(1_241_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 71_203_000 picoseconds. - Weight::from_parts(73_644_000, 6196) + // Minimum execution time: 70_773_000 picoseconds. + Weight::from_parts(72_730_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_018_000 picoseconds. - Weight::from_parts(4_267_000, 0) + // Minimum execution time: 4_173_000 picoseconds. + Weight::from_parts(4_445_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +309,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 67_893_000 picoseconds. - Weight::from_parts(69_220_000, 6196) + // Minimum execution time: 66_471_000 picoseconds. + Weight::from_parts(68_362_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +318,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 980_000 picoseconds. - Weight::from_parts(1_043_000, 0) + // Minimum execution time: 1_067_000 picoseconds. + Weight::from_parts(1_108_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 944_000 picoseconds. - Weight::from_parts(981_000, 0) + // Minimum execution time: 997_000 picoseconds. + Weight::from_parts(1_043_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 930_000 picoseconds. - Weight::from_parts(962_000, 0) + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_056_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -343,12 +350,12 @@ impl WeightInfo { /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `552` - // Estimated: `6492` - // Minimum execution time: 56_762_000 picoseconds. - Weight::from_parts(58_320_046, 6492) - // Standard Error: 162 - .saturating_add(Weight::from_parts(51_730, 0).saturating_mul(x.into())) + // Measured: `225` + // Estimated: `6165` + // Minimum execution time: 43_316_000 picoseconds. + Weight::from_parts(45_220_843, 6165) + // Standard Error: 169 + .saturating_add(Weight::from_parts(44_459, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +363,28 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 971_000 picoseconds. - Weight::from_parts(1_018_000, 0) + // Minimum execution time: 998_000 picoseconds. + Weight::from_parts(1_054_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 979_000 picoseconds. - Weight::from_parts(1_026_000, 0) + // Minimum execution time: 995_000 picoseconds. + Weight::from_parts(1_060_000, 0) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 707_000 picoseconds. + Weight::from_parts(749_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index ae31ca4cedf2..befb63ef9709 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -39,7 +39,7 @@ use snowbridge_runtime_common::XcmExportFeeToSibling; use sp_runtime::traits::AccountIdConversion; use sp_std::marker::PhantomData; use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -56,8 +56,9 @@ use xcm_executor::{ }; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const WestendLocation: Location = Location::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Westend; + pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -161,6 +162,7 @@ pub type Barrier = TrailingSetTopicAsId< /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, ); @@ -290,7 +292,7 @@ impl, FeeHandler: HandleFee> FeeManager fn is_waived(origin: Option<&Location>, fee_reason: FeeReason) -> bool { let Some(loc) = origin else { return false }; if let Export { network, destination: Here } = fee_reason { - if network == EthereumNetwork::get() { + if network == EthereumNetwork::get().into() { return false } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs index 1a1ce2a28ea3..d71400fa71b6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/snowbridge.rs @@ -30,7 +30,7 @@ use frame_support::parameter_types; use parachains_common::{AccountId, AuraId, Balance}; use snowbridge_pallet_ethereum_client::WeightInfo; use sp_core::H160; -use sp_keyring::AccountKeyring::Alice; +use sp_keyring::Sr25519Keyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, AccountId32, @@ -167,7 +167,7 @@ pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works() { } fn construct_extrinsic( - sender: sp_keyring::AccountKeyring, + sender: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); @@ -193,7 +193,7 @@ fn construct_extrinsic( } fn construct_and_apply_extrinsic( - origin: sp_keyring::AccountKeyring, + origin: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> sp_runtime::DispatchOutcome { let xt = construct_extrinsic(origin, call); 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 e5b67353c0f3..9d32f28f4fc6 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 @@ -27,9 +27,9 @@ use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, bridge_to_rococo_config::RococoGlobalConsensusNetwork, xcm_config::{LocationToAccountId, RelayNetwork, WestendLocation, XcmConfig}, - AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - TransactionPayment, TxExtension, UncheckedExtrinsic, + AllPalletsWithoutSystem, Block, BridgeRejectObsoleteHeadersAndMessages, Executive, + ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeOrigin, SessionKeys, TransactionPayment, TxExtension, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ BridgeGrandpaRococoInstance, BridgeHubRococoLocation, BridgeParachainRococoInstance, @@ -40,13 +40,13 @@ use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8} use parachains_common::{AccountId, AuraId, Balance}; use sp_consensus_aura::SlotDuration; use sp_core::crypto::Ss58Codec; -use sp_keyring::AccountKeyring::Alice; +use sp_keyring::Sr25519Keyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, AccountId32, Perbill, }; use testnet_parachains_constants::westend::{consensus::*, fee::WeightToFee}; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_runtime_apis::conversions::LocationToAccountHelper; // Random para id of sibling chain used in tests. @@ -77,7 +77,7 @@ parameter_types! { } fn construct_extrinsic( - sender: sp_keyring::AccountKeyring, + sender: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); @@ -104,7 +104,7 @@ fn construct_extrinsic( } fn construct_and_apply_extrinsic( - relayer_at_target: sp_keyring::AccountKeyring, + relayer_at_target: sp_keyring::Sr25519Keyring, call: RuntimeCall, ) -> sp_runtime::DispatchOutcome { let xt = construct_extrinsic(relayer_at_target, call); @@ -246,10 +246,11 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { >( SiblingParachainLocation::get(), BridgedUniversalLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubRococoInstance - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, LegacyLaneId([0, 0, 0, 1])) } ).1 }, @@ -296,7 +297,7 @@ fn relayed_incoming_message_works() { bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, - Westend, + ByGenesis(WESTEND_GENESIS_HASH), || { // we need to create lane between sibling parachain and remote destination bridge_hub_test_utils::ensure_opened_bridge::< @@ -307,11 +308,12 @@ fn relayed_incoming_message_works() { >( SiblingParachainLocation::get(), BridgedUniversalLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubRococoInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, LegacyLaneId([0, 0, 0, 1])) }, ) .1 @@ -330,7 +332,7 @@ fn free_relay_extrinsic_works() { bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, SIBLING_PARACHAIN_ID, - Westend, + ByGenesis(WESTEND_GENESIS_HASH), || { // we need to create lane between sibling parachain and remote destination bridge_hub_test_utils::ensure_opened_bridge::< @@ -341,11 +343,12 @@ fn free_relay_extrinsic_works() { >( SiblingParachainLocation::get(), BridgedUniversalLocation::get(), - |locations, fee| { + false, + |locations, _fee| { bridge_hub_test_utils::open_bridge_with_storage::< Runtime, XcmOverBridgeHubRococoInstance, - >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + >(locations, LegacyLaneId([0, 0, 0, 1])) }, ) .1 @@ -522,3 +525,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index 9cb24a2b2820..2fbb96d75163 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -5,18 +5,20 @@ authors.workspace = true edition.workspace = true description = "Bridge hub common utilities" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } +cumulus-primitives-core = { workspace = true } frame-support = { workspace = true } +pallet-message-queue = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +snowbridge-core = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -cumulus-primitives-core = { workspace = true } xcm = { workspace = true } -pallet-message-queue = { workspace = true } -snowbridge-core = { workspace = true } [features] default = ["std"] @@ -39,4 +41,5 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "snowbridge-core/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs index 5f91897262f4..2f5aa76fbdd7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/message_queue.rs @@ -23,7 +23,7 @@ use frame_support::{ use pallet_message_queue::OnQueueChanged; use scale_info::TypeInfo; use snowbridge_core::ChannelId; -use xcm::v4::{Junction, Location}; +use xcm::latest::prelude::{Junction, Location}; /// The aggregate origin of an inbound message. /// This is specialized for BridgeHub, as the snowbridge-outbound-queue-pallet is also using @@ -53,7 +53,7 @@ impl From for Location { Here => Location::here(), Parent => Location::parent(), Sibling(id) => Location::new(1, Junction::Parachain(id.into())), - // NOTE: We don't need this conversion for Snowbridge. However we have to + // NOTE: We don't need this conversion for Snowbridge. However, we have to // implement it anyway as xcm_builder::ProcessXcmMessage requires it. Snowbridge(_) => Location::default(), } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 915b3090092f..ace23e71c4d1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Utils for BridgeHub testing" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,14 +19,14 @@ log = { workspace = true } # Substrate frame-support = { workspace = true } frame-system = { workspace = true } +pallet-balances = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-utility = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-keyring = { workspace = true, default-features = true } sp-runtime = { workspace = true } sp-tracing = { workspace = true, default-features = true } -pallet-balances = { workspace = true } -pallet-utility = { workspace = true } -pallet-timestamp = { workspace = true } # Cumulus asset-test-utils = { workspace = true, default-features = true } @@ -34,10 +36,10 @@ parachains-common = { workspace = true } parachains-runtimes-test-utils = { workspace = true } # Polkadot +pallet-xcm = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } -pallet-xcm = { workspace = true } # Bridges bp-header-chain = { workspace = true } @@ -48,12 +50,12 @@ bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-test-utils = { workspace = true } bp-xcm-bridge-hub = { workspace = true } +bridge-runtime-common = { workspace = true } pallet-bridge-grandpa = { workspace = true } -pallet-bridge-parachains = { workspace = true } pallet-bridge-messages = { features = ["test-helpers"], workspace = true } +pallet-bridge-parachains = { workspace = true } pallet-bridge-relayers = { workspace = true } pallet-xcm-bridge-hub = { workspace = true } -bridge-runtime-common = { workspace = true } [features] default = ["std"] 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 320f3030b60a..358c184c815d 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 @@ -34,7 +34,7 @@ use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; use sp_core::Get; -use sp_keyring::AccountKeyring::*; +use sp_keyring::Sr25519Keyring::*; use sp_runtime::{traits::Header as HeaderT, AccountId32}; use xcm::latest::prelude::*; @@ -103,7 +103,7 @@ pub fn relayed_incoming_message_works( local_relay_chain_id: NetworkId, prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, expect_rewards: bool, @@ -210,7 +210,7 @@ pub fn free_relay_extrinsic_works( local_relay_chain_id: NetworkId, prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, expect_rewards: bool, @@ -344,7 +344,7 @@ pub fn complex_relay_extrinsic_works( local_relay_chain_id: NetworkId, prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, ) where 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 1da901e0bcdf..d8fff55b4b50 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 @@ -36,7 +36,7 @@ use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; use sp_core::Get; -use sp_keyring::AccountKeyring::*; +use sp_keyring::Sr25519Keyring::*; use sp_runtime::{traits::Header as HeaderT, AccountId32}; use xcm::latest::prelude::*; @@ -112,7 +112,7 @@ pub fn relayed_incoming_message_works( local_relay_chain_id: NetworkId, prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, expect_rewards: bool, @@ -246,7 +246,7 @@ pub fn free_relay_extrinsic_works( local_relay_chain_id: NetworkId, prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, expect_rewards: bool, @@ -414,7 +414,7 @@ pub fn complex_relay_extrinsic_works( local_relay_chain_id: NetworkId, prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, ) where 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 aac60bba0b53..a99bda5bfdf4 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 @@ -29,7 +29,7 @@ use core::marker::PhantomData; use frame_support::{ assert_ok, dispatch::GetDispatchInfo, - traits::{fungible::Mutate, OnFinalize, OnInitialize, PalletInfoAccess}, + traits::{fungible::Mutate, Contains, OnFinalize, OnInitialize, PalletInfoAccess}, }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader}; @@ -39,7 +39,7 @@ use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; use sp_core::Get; -use sp_keyring::AccountKeyring::*; +use sp_keyring::Sr25519Keyring::*; use sp_runtime::{traits::TrailingZeroInput, AccountId32}; use xcm::latest::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -264,7 +264,7 @@ pub fn relayed_incoming_message_works( sibling_parachain_id: u32, local_relay_chain_id: NetworkId, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, prepare_message_proof_import: impl FnOnce( @@ -374,9 +374,9 @@ pub fn relayed_incoming_message_works( /// Execute every call and verify its outcome. fn execute_and_verify_calls( - submitter: sp_keyring::AccountKeyring, + submitter: sp_keyring::Sr25519Keyring, construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, calls_and_verifiers: CallsAndVerifiers, @@ -395,7 +395,7 @@ pub fn ensure_opened_bridge< XcmOverBridgePalletInstance, LocationToAccountId, TokenLocation> -(source: Location, destination: InteriorLocation, bridge_opener: impl Fn(BridgeLocations, Asset)) -> (BridgeLocations, pallet_xcm_bridge_hub::LaneIdOf) +(source: Location, destination: InteriorLocation, is_paid_xcm_execution: bool, bridge_opener: impl Fn(BridgeLocations, Option)) -> (BridgeLocations, pallet_xcm_bridge_hub::LaneIdOf) where Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, XcmOverBridgePalletInstance: 'static, @@ -416,24 +416,37 @@ TokenLocation: Get{ ) .is_none()); - // required balance: ED + fee + BridgeDeposit - let bridge_deposit = - >::BridgeDeposit::get( - ); - // random high enough value for `BuyExecution` fees - let buy_execution_fee_amount = 5_000_000_000_000_u128; - let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); - let balance_needed = ::ExistentialDeposit::get() + - buy_execution_fee_amount.into() + - bridge_deposit.into(); - // SA of source location needs to have some required balance - let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); - let _ = >::mint_into(&source_account_id, balance_needed) - .expect("mint_into passes"); + if !>::AllowWithoutBridgeDeposit::contains(&source) { + // required balance: ED + fee + BridgeDeposit + let bridge_deposit = + >::BridgeDeposit::get( + ); + let balance_needed = ::ExistentialDeposit::get() + bridge_deposit.into(); + + let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + }; + + let maybe_paid_execution = if is_paid_xcm_execution { + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 5_000_000_000_000_u128; + let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); + + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into(); + let source_account_id = + LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + Some(buy_execution_fee) + } else { + None + }; // call the bridge opener - bridge_opener(*locations.clone(), buy_execution_fee); + bridge_opener(*locations.clone(), maybe_paid_execution); // check opened bridge let bridge = pallet_xcm_bridge_hub::Bridges::::get( @@ -452,8 +465,9 @@ TokenLocation: Get{ /// Utility for opening bridge with dedicated `pallet_xcm_bridge_hub`'s extrinsic. pub fn open_bridge_with_extrinsic( - locations: BridgeLocations, - buy_execution_fee: Asset, + (origin, origin_kind): (Location, OriginKind), + bridge_destination_universal_location: InteriorLocation, + maybe_paid_execution: Option, ) where Runtime: frame_system::Config + pallet_xcm_bridge_hub::Config @@ -469,15 +483,15 @@ pub fn open_bridge_with_extrinsic( XcmOverBridgePalletInstance, >::open_bridge { bridge_destination_universal_location: Box::new( - locations.bridge_destination_universal_location().clone().into(), + 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(), + assert_ok!(RuntimeHelper::::execute_as_origin( + (origin, origin_kind), open_bridge_call, - buy_execution_fee + maybe_paid_execution ) .ensure_complete()); } @@ -486,7 +500,6 @@ pub fn open_bridge_with_extrinsic( /// 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, @@ -503,8 +516,12 @@ pub fn open_bridge_with_storage( } /// Helper function to close the bridge/lane for `source` and `destination`. -pub fn close_bridge(source: Location, destination: InteriorLocation) -where +pub fn close_bridge( + expected_source: Location, + bridge_destination_universal_location: InteriorLocation, + (origin, origin_kind): (Location, OriginKind), + is_paid_xcm_execution: bool +) where Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, XcmOverBridgePalletInstance: 'static, ::RuntimeCall: GetDispatchInfo + From>, @@ -515,8 +532,8 @@ TokenLocation: Get{ // construct expected bridge configuration let locations = pallet_xcm_bridge_hub::Pallet::::bridge_locations( - source.clone().into(), - destination.clone().into(), + expected_source.clone().into(), + bridge_destination_universal_location.clone().into(), ) .expect("valid bridge locations"); assert!(pallet_xcm_bridge_hub::Bridges::::get( @@ -525,35 +542,38 @@ TokenLocation: Get{ .is_some()); // required balance: ED + fee + BridgeDeposit - let bridge_deposit = - >::BridgeDeposit::get( - ); - // random high enough value for `BuyExecution` fees - let buy_execution_fee_amount = 2_500_000_000_000_u128; - let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); - let balance_needed = ::ExistentialDeposit::get() + - buy_execution_fee_amount.into() + - bridge_deposit.into(); - - // SA of source location needs to have some required balance - let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); - let _ = >::mint_into(&source_account_id, balance_needed) - .expect("mint_into passes"); + let maybe_paid_execution = if is_paid_xcm_execution { + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 2_500_000_000_000_u128; + let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); + + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into(); + let source_account_id = + LocationToAccountId::convert_location(&expected_source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + Some(buy_execution_fee) + } else { + None + }; // close bridge with `Transact` call let close_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< Runtime, XcmOverBridgePalletInstance, >::close_bridge { - bridge_destination_universal_location: Box::new(destination.into()), + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.into(), + ), may_prune_messages: 16, }); // execute XCM as source origin would do with `Transact -> Origin::Xcm` - assert_ok!(RuntimeHelper::::execute_as_origin_xcm( - source.clone(), + assert_ok!(RuntimeHelper::::execute_as_origin( + (origin, origin_kind), close_bridge_call, - buy_execution_fee + maybe_paid_execution ) .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 24372f57ae7d..f96d0bf405b9 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 @@ -129,11 +129,8 @@ pub fn initialize_bridge_by_governance_works( }); // execute XCM with Transacts to `initialize bridge` as governance does - assert_ok!(RuntimeHelper::::execute_as_governance( - initialize_call.encode(), - initialize_call.get_dispatch_info().call_weight, - ) - .ensure_complete()); + assert_ok!(RuntimeHelper::::execute_as_governance(initialize_call.encode(),) + .ensure_complete()); // check mode after assert_eq!( @@ -172,7 +169,6 @@ pub fn change_bridge_grandpa_pallet_mode_by_governance_works::execute_as_governance( set_operating_mode_call.encode(), - set_operating_mode_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -225,7 +221,6 @@ pub fn change_bridge_parachains_pallet_mode_by_governance_works::execute_as_governance( set_operating_mode_call.encode(), - set_operating_mode_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -278,7 +273,6 @@ pub fn change_bridge_messages_pallet_mode_by_governance_works::execute_as_governance( set_operating_mode_call.encode(), - set_operating_mode_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -660,8 +654,10 @@ where pub fn open_and_close_bridge_works( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, - source: Location, + expected_source: Location, destination: InteriorLocation, + origin_with_origin_kind: (Location, OriginKind), + is_paid_xcm_execution: bool, ) where Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, XcmOverBridgePalletInstance: 'static, @@ -675,7 +671,7 @@ pub fn open_and_close_bridge_works(collator_session_key, runtime_para_id, vec![], || { // construct expected bridge configuration let locations = pallet_xcm_bridge_hub::Pallet::::bridge_locations( - source.clone().into(), + expected_source.clone().into(), destination.clone().into(), ).expect("valid bridge locations"); let expected_lane_id = @@ -710,7 +706,7 @@ pub fn open_and_close_bridge_works( - source.clone(), + expected_source.clone(), destination.clone(), - open_bridge_with_extrinsic:: + is_paid_xcm_execution, + |locations, maybe_paid_execution| open_bridge_with_extrinsic::< + Runtime, + XcmOverBridgePalletInstance, + >( + origin_with_origin_kind.clone(), + locations.bridge_destination_universal_location().clone(), + maybe_paid_execution + ) ) .0 .bridge_id(), @@ -733,7 +737,7 @@ pub fn open_and_close_bridge_works(source.clone(), destination); + >(expected_source, destination, origin_with_origin_kind, is_paid_xcm_execution); // check bridge/lane DOES not exist assert_eq!( diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index e03fc934ceaf..9c70b65060dd 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Westend Collectives Parachain Runtime" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -24,15 +26,19 @@ frame-system = { workspace = true } frame-system-benchmarking = { optional = true, workspace = true } frame-system-rpc-runtime-api = { workspace = true } frame-try-runtime = { optional = true, workspace = true } -pallet-asset-rate = { workspace = true } pallet-alliance = { workspace = true } +pallet-asset-rate = { workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-collective = { workspace = true } +pallet-core-fellowship = { workspace = true } pallet-multisig = { workspace = true } pallet-preimage = { workspace = true } pallet-proxy = { workspace = true } +pallet-ranked-collective = { workspace = true } +pallet-referenda = { workspace = true } +pallet-salary = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true } pallet-state-trie-migration = { workspace = true } @@ -41,18 +47,14 @@ pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-treasury = { workspace = true } pallet-utility = { workspace = true } -pallet-referenda = { workspace = true } -pallet-ranked-collective = { workspace = true } -pallet-core-fellowship = { workspace = true } -pallet-salary = { workspace = true } sp-api = { workspace = true } sp-arithmetic = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -65,23 +67,23 @@ sp-version = { workspace = true } pallet-xcm = { workspace = true } polkadot-parachain-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } +westend-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } -westend-runtime-constants = { workspace = true } xcm-runtime-apis = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } -pallet-message-queue = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-session-benchmarking = { workspace = true } cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } +pallet-message-queue = { workspace = true } pallet-collator-selection = { workspace = true } pallet-collective-content = { workspace = true } @@ -93,6 +95,7 @@ testnet-parachains-constants = { features = ["westend"], workspace = true } substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dev-dependencies] +parachains-runtimes-test-utils = { workspace = true, default-features = true } sp-io = { features = ["std"], workspace = true, default-features = true } [features] @@ -135,6 +138,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs index aec8e96cedc0..007ff6164a74 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs @@ -18,6 +18,7 @@ use crate::*; use alloc::{vec, vec::Vec}; use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; use parachains_common::{AccountId, AuraId}; use sp_genesis_builder::PresetId; use sp_keyring::Sr25519Keyring; @@ -30,7 +31,7 @@ fn collectives_westend_genesis( endowed_accounts: Vec, id: ParaId, ) -> serde_json::Value { - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -38,11 +39,10 @@ fn collectives_westend_genesis( .map(|k| (k, COLLECTIVES_WESTEND_ED * 4096)) .collect::>(), }, - parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + parachain_info: ParachainInfoConfig { parachain_id: id }, collator_selection: CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), candidacy_bond: COLLECTIVES_WESTEND_ED * 16, - ..Default::default() }, session: SessionConfig { keys: invulnerables @@ -55,22 +55,15 @@ fn collectives_westend_genesis( ) }) .collect(), - ..Default::default() }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, + }) } /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => collectives_westend_genesis( + let patch = match id.as_ref() { + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => collectives_westend_genesis( // initial collators. vec![ (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), @@ -79,7 +72,7 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option collectives_westend_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => collectives_westend_genesis( // initial collators. vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 8cb2e42cb31b..5c2ba2e24c22 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -56,7 +56,7 @@ use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{AccountIdConversion, BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, @@ -123,10 +123,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("collectives-westend"), - impl_name: create_runtime_str!("collectives-westend"), + spec_name: alloc::borrow::Cow::Borrowed("collectives-westend"), + impl_name: alloc::borrow::Cow::Borrowed("collectives-westend"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -258,6 +258,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -382,6 +383,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -961,7 +963,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::WndLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -1061,7 +1064,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 5d427d850046..ccf88873c2cd 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `47a5bbdc8de3`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=collectives-westend-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=collectives-westend-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,6 +50,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -62,16 +66,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 21_813_000 picoseconds. - Weight::from_parts(22_332_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `214` + // Estimated: `3679` + // Minimum execution time: 32_779_000 picoseconds. + Weight::from_parts(33_417_000, 0) + .saturating_add(Weight::from_parts(0, 3679)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -90,10 +96,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 93_243_000 picoseconds. - Weight::from_parts(95_650_000, 0) + // Minimum execution time: 116_031_000 picoseconds. + Weight::from_parts(118_863_000, 0) .saturating_add(Weight::from_parts(0, 3679)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -108,6 +114,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -126,21 +134,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 96_199_000 picoseconds. - Weight::from_parts(98_620_000, 0) + // Minimum execution time: 116_267_000 picoseconds. + Weight::from_parts(119_519_000, 0) .saturating_add(Weight::from_parts(0, 3679)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `103` + // Estimated: `1588` + // Minimum execution time: 12_718_000 picoseconds. + Weight::from_parts(13_572_000, 0) + .saturating_add(Weight::from_parts(0, 1588)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -148,8 +157,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_442_000 picoseconds. - Weight::from_parts(6_682_000, 0) + // Minimum execution time: 7_568_000 picoseconds. + Weight::from_parts(7_913_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +168,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_833_000 picoseconds. - Weight::from_parts(1_973_000, 0) + // Minimum execution time: 2_225_000 picoseconds. + Weight::from_parts(2_473_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_318_000 picoseconds. - Weight::from_parts(28_224_000, 0) + // Minimum execution time: 35_869_000 picoseconds. + Weight::from_parts(37_848_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +221,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_070_000 picoseconds. - Weight::from_parts(30_205_000, 0) + // Minimum execution time: 38_649_000 picoseconds. + Weight::from_parts(39_842_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,45 +233,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_904_000 picoseconds. - Weight::from_parts(2_033_000, 0) + // Minimum execution time: 2_223_000 picoseconds. + Weight::from_parts(2_483_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `159` - // Estimated: `13524` - // Minimum execution time: 18_348_000 picoseconds. - Weight::from_parts(18_853_000, 0) - .saturating_add(Weight::from_parts(0, 13524)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15999` + // Minimum execution time: 24_164_000 picoseconds. + Weight::from_parts(24_972_000, 0) + .saturating_add(Weight::from_parts(0, 15999)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `163` - // Estimated: `13528` - // Minimum execution time: 17_964_000 picoseconds. - Weight::from_parts(18_548_000, 0) - .saturating_add(Weight::from_parts(0, 13528)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16003` + // Minimum execution time: 24_604_000 picoseconds. + Weight::from_parts(25_047_000, 0) + .saturating_add(Weight::from_parts(0, 16003)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `173` - // Estimated: `16013` - // Minimum execution time: 19_708_000 picoseconds. - Weight::from_parts(20_157_000, 0) - .saturating_add(Weight::from_parts(0, 16013)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18488` + // Minimum execution time: 28_088_000 picoseconds. + Weight::from_parts(28_431_000, 0) + .saturating_add(Weight::from_parts(0, 18488)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -282,36 +291,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_632_000 picoseconds. - Weight::from_parts(27_314_000, 0) + // Minimum execution time: 33_814_000 picoseconds. + Weight::from_parts(34_741_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `11096` - // Minimum execution time: 11_929_000 picoseconds. - Weight::from_parts(12_304_000, 0) - .saturating_add(Weight::from_parts(0, 11096)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `176` + // Estimated: `13541` + // Minimum execution time: 18_242_000 picoseconds. + Weight::from_parts(18_636_000, 0) + .saturating_add(Weight::from_parts(0, 13541)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `170` - // Estimated: `13535` - // Minimum execution time: 18_599_000 picoseconds. - Weight::from_parts(19_195_000, 0) - .saturating_add(Weight::from_parts(0, 13535)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `16010` + // Minimum execution time: 24_249_000 picoseconds. + Weight::from_parts(24_768_000, 0) + .saturating_add(Weight::from_parts(0, 16010)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -328,11 +337,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `212` - // Estimated: `13577` - // Minimum execution time: 35_524_000 picoseconds. - Weight::from_parts(36_272_000, 0) - .saturating_add(Weight::from_parts(0, 13577)) - .saturating_add(T::DbWeight::get().reads(11)) + // Estimated: `16052` + // Minimum execution time: 47_602_000 picoseconds. + Weight::from_parts(48_378_000, 0) + .saturating_add(Weight::from_parts(0, 16052)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -343,8 +352,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_044_000 picoseconds. - Weight::from_parts(4_238_000, 0) + // Minimum execution time: 5_566_000 picoseconds. + Weight::from_parts(5_768_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,22 +364,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_741_000 picoseconds. - Weight::from_parts(26_301_000, 0) + // Minimum execution time: 30_821_000 picoseconds. + Weight::from_parts(31_250_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 35_925_000 picoseconds. - Weight::from_parts(36_978_000, 0) + // Minimum execution time: 43_463_000 picoseconds. + Weight::from_parts(44_960_000, 0) .saturating_add(Weight::from_parts(0, 3625)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index f8e03303c32e..9eb9b85a3918 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -33,9 +33,10 @@ use parachains_common::xcm_config::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use westend_runtime_constants::xcm as xcm_constants; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AccountId32Aliases, AliasChildLocation, AliasOriginRootUsingFilter, + AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, @@ -50,7 +51,7 @@ use xcm_executor::XcmExecutor; parameter_types! { pub const RootLocation: Location = Location::here(); pub const WndLocation: Location = Location::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Westend); + pub const RelayNetwork: Option = Some(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -191,6 +192,10 @@ pub type WaivedLocations = ( /// - DOT with the parent Relay Chain and sibling parachains. pub type TrustedTeleporters = ConcreteAssetFromSystem; +/// We allow locations to alias into their own child locations, as well as +/// AssetHub to alias into anything. +pub type Aliasers = (AliasChildLocation, AliasOriginRootUsingFilter); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -227,7 +232,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + type Aliasers = Aliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/tests/tests.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/tests/tests.rs index 7add10559d84..c9191eba49f6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/tests/tests.rs @@ -16,7 +16,9 @@ #![cfg(test)] -use collectives_westend_runtime::xcm_config::LocationToAccountId; +use collectives_westend_runtime::{ + xcm_config::LocationToAccountId, Block, Runtime, RuntimeCall, RuntimeOrigin, +}; use parachains_common::AccountId; use sp_core::crypto::Ss58Codec; use xcm::latest::prelude::*; @@ -132,3 +134,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/constants/Cargo.toml b/cumulus/parachains/runtimes/constants/Cargo.toml index d54f1e7db6c1..01b023e0fb89 100644 --- a/cumulus/parachains/runtimes/constants/Cargo.toml +++ b/cumulus/parachains/runtimes/constants/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Common constants for Testnet Parachains runtimes" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index c98ca7ba3e74..cb0655d70cf2 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -5,6 +5,8 @@ description = "Parachain testnet runtime for FRAME Contracts pallet." authors.workspace = true edition.workspace = true license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -22,37 +24,37 @@ log = { workspace = true } scale-info = { features = ["derive"], workspace = true } # Substrate -sp-api = { workspace = true } -sp-block-builder = { workspace = true } -sp-consensus-aura = { workspace = true } -sp-core = { workspace = true } -sp-genesis-builder = { workspace = true } -sp-inherents = { workspace = true } -sp-offchain = { workspace = true } -sp-runtime = { workspace = true } -sp-session = { workspace = true } -sp-storage = { workspace = true } -sp-transaction-pool = { workspace = true } -sp-version = { workspace = true } frame-benchmarking = { optional = true, workspace = true } -frame-try-runtime = { optional = true, workspace = true } frame-executive = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } frame-system-benchmarking = { optional = true, workspace = true } frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { optional = true, workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } -pallet-insecure-randomness-collective-flip = { workspace = true } pallet-balances = { workspace = true } +pallet-contracts = { workspace = true } +pallet-insecure-randomness-collective-flip = { workspace = true } pallet-multisig = { workspace = true } pallet-session = { workspace = true } +pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-utility = { workspace = true } -pallet-sudo = { workspace = true } -pallet-contracts = { workspace = true } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-storage = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } # Polkadot pallet-xcm = { workspace = true } @@ -66,15 +68,15 @@ xcm-runtime-apis = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } -pallet-message-queue = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-session-benchmarking = { workspace = true } cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } +pallet-message-queue = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } @@ -171,6 +173,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 2fc3fe4f3141..594c9b26f57e 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -37,7 +37,7 @@ use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSele use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::Block as BlockT, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, @@ -141,10 +141,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("contracts-rococo"), - impl_name: create_runtime_str!("contracts-rococo"), + spec_name: alloc::borrow::Cow::Borrowed("contracts-rococo"), + impl_name: alloc::borrow::Cow::Borrowed("contracts-rococo"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 7, @@ -268,6 +268,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = pallet_multisig::weights::SubstrateWeight; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -772,7 +773,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index 39fdd30a0498..532ad4ff4ce0 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -36,7 +36,7 @@ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::currency::CENTS; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -51,8 +51,9 @@ use xcm_builder::{ use xcm_executor::XcmExecutor; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const RelayLocation: Location = Location::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Rococo; + pub const RelayNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); pub const ExecutiveBody: BodyId = BodyId::Executive; @@ -166,6 +167,7 @@ pub type Barrier = TrailingSetTopicAsId< /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, ); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index a38b7400cfa3..2b5fab329293 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Rococo's Coretime parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -31,8 +33,8 @@ frame-try-runtime = { optional = true, workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } -pallet-message-queue = { workspace = true } pallet-broker = { workspace = true } +pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } pallet-session = { workspace = true } @@ -45,8 +47,8 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-inherents = { workspace = true } sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -73,13 +75,16 @@ cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["rococo"], workspace = true } +[dev-dependencies] +parachains-runtimes-test-utils = { workspace = true } + [features] default = ["std"] std = [ @@ -120,6 +125,7 @@ std = [ "pallet-xcm/std", "parachain-info/std", "parachains-common/std", + "parachains-runtimes-test-utils/std", "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "rococo-runtime-constants/std", @@ -174,6 +180,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs index 3910a747e9bb..35c3dd8836a8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs @@ -134,8 +134,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1000000000, 200000), call: request_core_count_call.encode().into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)), }, ]); @@ -164,8 +164,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1000000000, 200000), call: request_revenue_info_at_call.encode().into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)), }, ]); @@ -193,8 +193,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1000000000, 200000), call: credit_account_call.encode().into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)), }, ]); @@ -258,8 +258,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1_000_000_000, 200000), call: assign_core_call.encode().into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)), }, ]); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index f2ccb9c552e3..e8f6e6659e13 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -67,8 +67,8 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT}, + generic, impl_opaque_keys, + traits::{BlakeTwo256, Block as BlockT, BlockNumberProvider}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, RuntimeDebug, }; @@ -124,6 +124,7 @@ pub type Migrations = ( pallet_broker::migration::MigrateV0ToV1, pallet_broker::migration::MigrateV1ToV2, pallet_broker::migration::MigrateV2ToV3, + pallet_broker::migration::MigrateV3ToV4, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -146,10 +147,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("coretime-rococo"), - impl_name: create_runtime_str!("coretime-rococo"), + spec_name: alloc::borrow::Cow::Borrowed("coretime-rococo"), + impl_name: alloc::borrow::Cow::Borrowed("coretime-rococo"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, @@ -444,6 +445,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } /// The type used to represent the kinds of proxying allowed. @@ -576,6 +578,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -591,6 +594,25 @@ impl pallet_sudo::Config for Runtime { type WeightInfo = pallet_sudo::weights::SubstrateWeight; } +pub struct BrokerMigrationV4BlockConversion; + +impl pallet_broker::migration::v4::BlockToRelayHeightConversion + for BrokerMigrationV4BlockConversion +{ + fn convert_block_number_to_relay_height(input_block_number: u32) -> u32 { + let relay_height = pallet_broker::RCBlockNumberProviderOf::< + ::Coretime, + >::current_block_number(); + let parachain_block_number = frame_system::Pallet::::block_number(); + let offset = relay_height - parachain_block_number * 2; + offset + input_block_number * 2 + } + + fn convert_block_length_to_relay_length(input_block_length: u32) -> u32 { + input_block_length * 2 + } +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -813,7 +835,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::RocRelayLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -918,7 +941,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs index 35708f22de20..3e4bbf379c3f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-06-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-x5tnzzy-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_024_000 picoseconds. - Weight::from_parts(2_121_000, 0) + // Minimum execution time: 2_250_000 picoseconds. + Weight::from_parts(2_419_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `10888` // Estimated: `13506` - // Minimum execution time: 21_654_000 picoseconds. - Weight::from_parts(22_591_000, 0) + // Minimum execution time: 25_785_000 picoseconds. + Weight::from_parts(26_335_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,8 +77,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12090` // Estimated: `13506` - // Minimum execution time: 20_769_000 picoseconds. - Weight::from_parts(21_328_000, 0) + // Minimum execution time: 24_549_000 picoseconds. + Weight::from_parts(25_010_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -93,8 +93,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `466` // Estimated: `1951` - // Minimum execution time: 10_404_000 picoseconds. - Weight::from_parts(10_941_000, 0) + // Minimum execution time: 14_135_000 picoseconds. + Weight::from_parts(14_603_000, 0) .saturating_add(Weight::from_parts(0, 1951)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -121,6 +121,8 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(1002), added: 1497, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:0 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::Status` (r:0 w:1) @@ -132,31 +134,33 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12599` // Estimated: `15065 + n * (1 ±0)` - // Minimum execution time: 44_085_000 picoseconds. - Weight::from_parts(127_668_002, 0) + // Minimum execution time: 54_087_000 picoseconds. + Weight::from_parts(145_466_213, 0) .saturating_add(Weight::from_parts(0, 15065)) - // Standard Error: 2_231 - .saturating_add(Weight::from_parts(20_604, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(59)) + // Standard Error: 2_407 + .saturating_add(Weight::from_parts(20_971, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(60)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:0 w:1) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `332` + // Measured: `437` // Estimated: `3593` - // Minimum execution time: 45_100_000 picoseconds. - Weight::from_parts(46_263_000, 0) + // Minimum execution time: 58_341_000 picoseconds. + Weight::from_parts(59_505_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Broker::Configuration` (r:1 w:0) @@ -169,16 +173,18 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `553` + // Measured: `658` // Estimated: `4698` - // Minimum execution time: 65_944_000 picoseconds. - Weight::from_parts(68_666_000, 0) + // Minimum execution time: 92_983_000 picoseconds. + Weight::from_parts(99_237_000, 0) .saturating_add(Weight::from_parts(0, 4698)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Broker::Regions` (r:1 w:1) @@ -187,8 +193,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3551` - // Minimum execution time: 13_794_000 picoseconds. - Weight::from_parts(14_450_000, 0) + // Minimum execution time: 17_512_000 picoseconds. + Weight::from_parts(18_099_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -199,8 +205,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3551` - // Minimum execution time: 15_316_000 picoseconds. - Weight::from_parts(15_787_000, 0) + // Minimum execution time: 18_715_000 picoseconds. + Weight::from_parts(19_768_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -211,8 +217,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3551` - // Minimum execution time: 16_375_000 picoseconds. - Weight::from_parts(17_113_000, 0) + // Minimum execution time: 20_349_000 picoseconds. + Weight::from_parts(21_050_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) @@ -229,8 +235,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `937` // Estimated: `4681` - // Minimum execution time: 25_952_000 picoseconds. - Weight::from_parts(27_198_000, 0) + // Minimum execution time: 31_876_000 picoseconds. + Weight::from_parts(33_536_000, 0) .saturating_add(Weight::from_parts(0, 4681)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -249,8 +255,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1003` // Estimated: `5996` - // Minimum execution time: 31_790_000 picoseconds. - Weight::from_parts(32_920_000, 0) + // Minimum execution time: 39_500_000 picoseconds. + Weight::from_parts(40_666_000, 0) .saturating_add(Weight::from_parts(0, 5996)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) @@ -264,13 +270,13 @@ impl pallet_broker::WeightInfo for WeightInfo { /// The range of component `m` is `[1, 3]`. fn claim_revenue(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `652` + // Measured: `671` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 56_286_000 picoseconds. - Weight::from_parts(56_946_240, 0) + // Minimum execution time: 65_843_000 picoseconds. + Weight::from_parts(65_768_512, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 44_472 - .saturating_add(Weight::from_parts(1_684_838, 0).saturating_mul(m.into())) + // Standard Error: 40_994 + .saturating_add(Weight::from_parts(2_084_877, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5)) @@ -290,11 +296,11 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn purchase_credit() -> Weight { // Proof Size summary in bytes: - // Measured: `322` - // Estimated: `3787` - // Minimum execution time: 64_967_000 picoseconds. - Weight::from_parts(66_504_000, 0) - .saturating_add(Weight::from_parts(0, 3787)) + // Measured: `323` + // Estimated: `3788` + // Minimum execution time: 73_250_000 picoseconds. + Weight::from_parts(75_059_000, 0) + .saturating_add(Weight::from_parts(0, 3788)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -306,8 +312,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `466` // Estimated: `3551` - // Minimum execution time: 37_552_000 picoseconds. - Weight::from_parts(46_263_000, 0) + // Minimum execution time: 55_088_000 picoseconds. + Weight::from_parts(65_329_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -322,8 +328,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `463` // Estimated: `3533` - // Minimum execution time: 79_625_000 picoseconds. - Weight::from_parts(86_227_000, 0) + // Minimum execution time: 102_280_000 picoseconds. + Weight::from_parts(130_319_000, 0) .saturating_add(Weight::from_parts(0, 3533)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -338,10 +344,10 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `857` + // Measured: `979` // Estimated: `3593` - // Minimum execution time: 88_005_000 picoseconds. - Weight::from_parts(92_984_000, 0) + // Minimum execution time: 78_195_000 picoseconds. + Weight::from_parts(105_946_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -354,8 +360,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `957` // Estimated: `4698` - // Minimum execution time: 38_877_000 picoseconds. - Weight::from_parts(40_408_000, 0) + // Minimum execution time: 41_642_000 picoseconds. + Weight::from_parts(48_286_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -371,15 +377,13 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(n: u32, ) -> Weight { + fn request_core_count(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 20_581_000 picoseconds. - Weight::from_parts(21_610_297, 0) + // Minimum execution time: 23_727_000 picoseconds. + Weight::from_parts(25_029_439, 0) .saturating_add(Weight::from_parts(0, 3539)) - // Standard Error: 119 - .saturating_add(Weight::from_parts(144, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -390,11 +394,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `266` // Estimated: `1487` - // Minimum execution time: 6_079_000 picoseconds. - Weight::from_parts(6_540_110, 0) + // Minimum execution time: 7_887_000 picoseconds. + Weight::from_parts(8_477_863, 0) .saturating_add(Weight::from_parts(0, 1487)) - // Standard Error: 14 - .saturating_add(Weight::from_parts(10, 0).saturating_mul(n.into())) + // Standard Error: 18 + .saturating_add(Weight::from_parts(76, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -406,36 +410,50 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `442` + // Measured: `461` // Estimated: `6196` - // Minimum execution time: 42_947_000 picoseconds. - Weight::from_parts(43_767_000, 0) + // Minimum execution time: 52_505_000 picoseconds. + Weight::from_parts(53_392_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `Broker::Reservations` (r:1 w:0) /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(1002), added: 1497, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::PotentialRenewals` (r:100 w:200) + /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:101 w:101) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:0 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) - /// Storage: `Broker::Workplan` (r:0 w:60) + /// Storage: `Broker::Workplan` (r:0 w:1000) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn rotate_sale(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12514` - // Estimated: `13506` - // Minimum execution time: 93_426_000 picoseconds. - Weight::from_parts(96_185_447, 0) - .saturating_add(Weight::from_parts(0, 13506)) - // Standard Error: 116 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(65)) + // Measured: `32497` + // Estimated: `233641 + n * (198 ±9)` + // Minimum execution time: 28_834_000 picoseconds. + Weight::from_parts(2_467_159_777, 0) + .saturating_add(Weight::from_parts(0, 233641)) + // Standard Error: 149_483 + .saturating_add(Weight::from_parts(4_045_956, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(126)) + .saturating_add(T::DbWeight::get().writes(181)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 198).saturating_mul(n.into())) } /// Storage: `Broker::InstaPoolIo` (r:1 w:0) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -445,8 +463,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3493` - // Minimum execution time: 5_842_000 picoseconds. - Weight::from_parts(6_077_000, 0) + // Minimum execution time: 7_689_000 picoseconds. + Weight::from_parts(7_988_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -469,8 +487,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `4786` - // Minimum execution time: 33_278_000 picoseconds. - Weight::from_parts(34_076_000, 0) + // Minimum execution time: 37_394_000 picoseconds. + Weight::from_parts(38_379_000, 0) .saturating_add(Weight::from_parts(0, 4786)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -489,8 +507,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 15_779_000 picoseconds. - Weight::from_parts(16_213_000, 0) + // Minimum execution time: 19_203_000 picoseconds. + Weight::from_parts(19_797_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -501,8 +519,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_774_000 picoseconds. - Weight::from_parts(1_873_000, 0) + // Minimum execution time: 2_129_000 picoseconds. + Weight::from_parts(2_266_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -512,8 +530,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_858_000 picoseconds. - Weight::from_parts(1_991_000, 0) + // Minimum execution time: 2_233_000 picoseconds. + Weight::from_parts(2_351_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -531,20 +549,38 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `408` // Estimated: `1893` - // Minimum execution time: 10_874_000 picoseconds. - Weight::from_parts(11_265_000, 0) + // Minimum execution time: 15_716_000 picoseconds. + Weight::from_parts(16_160_000, 0) .saturating_add(Weight::from_parts(0, 1893)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Broker::SaleInfo` (r:1 w:0) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:1) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:2) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn force_reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `11125` + // Estimated: `13506` + // Minimum execution time: 32_286_000 picoseconds. + Weight::from_parts(33_830_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`) fn swap_leases() -> Weight { // Proof Size summary in bytes: // Measured: `470` // Estimated: `1886` - // Minimum execution time: 6_525_000 picoseconds. - Weight::from_parts(6_769_000, 0) + // Minimum execution time: 8_887_000 picoseconds. + Weight::from_parts(9_178_000, 0) .saturating_add(Weight::from_parts(0, 1886)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -557,36 +593,36 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::AutoRenewals` (r:1 w:1) - /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(1002), added: 1497, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn enable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `914` - // Estimated: `4698` - // Minimum execution time: 51_938_000 picoseconds. - Weight::from_parts(55_025_000, 4698) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `2829` + // Estimated: `6196` + // Minimum execution time: 130_799_000 picoseconds. + Weight::from_parts(139_893_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Broker::AutoRenewals` (r:1 w:1) - /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(1002), added: 1497, mode: `MaxEncodedLen`) fn disable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `480` - // Estimated: `1516` - // Minimum execution time: 9_628_000 picoseconds. - Weight::from_parts(10_400_000, 1516) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } + // Measured: `1307` + // Estimated: `2487` + // Minimum execution time: 22_945_000 picoseconds. + Weight::from_parts(24_855_000, 0) + .saturating_add(Weight::from_parts(0, 2487)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) @@ -601,11 +637,11 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_new_timeslice() -> Weight { // Proof Size summary in bytes: - // Measured: `322` - // Estimated: `3787` - // Minimum execution time: 45_561_000 picoseconds. - Weight::from_parts(47_306_000, 0) - .saturating_add(Weight::from_parts(0, 3787)) + // Measured: `323` + // Estimated: `3788` + // Minimum execution time: 56_864_000 picoseconds. + Weight::from_parts(59_119_000, 0) + .saturating_add(Weight::from_parts(0, 3788)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index 7fb492173dad..b2b8cd6e5349 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `902e7ad7764b`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=coretime-rococo-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=coretime-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,14 +64,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 19_121_000 picoseconds. - Weight::from_parts(19_582_000, 0) + // Minimum execution time: 23_660_000 picoseconds. + Weight::from_parts(24_537_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -84,18 +88,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 61_722_000 picoseconds. - Weight::from_parts(63_616_000, 0) + // Minimum execution time: 74_005_000 picoseconds. + Weight::from_parts(75_355_000, 0) .saturating_add(Weight::from_parts(0, 3571)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Regions` (r:1 w:1) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -107,17 +113,17 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `377` // Estimated: `3842` - // Minimum execution time: 97_823_000 picoseconds. - Weight::from_parts(102_022_000, 0) + // Minimum execution time: 116_231_000 picoseconds. + Weight::from_parts(121_254_000, 0) .saturating_add(Weight::from_parts(0, 3842)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -130,13 +136,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_397_000 picoseconds. - Weight::from_parts(8_773_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 11_498_000 picoseconds. + Weight::from_parts(11_867_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -144,8 +153,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_806_000 picoseconds. - Weight::from_parts(6_106_000, 0) + // Minimum execution time: 7_163_000 picoseconds. + Weight::from_parts(7_501_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -155,8 +164,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_802_000 picoseconds. - Weight::from_parts(1_939_000, 0) + // Minimum execution time: 2_188_000 picoseconds. + Weight::from_parts(2_356_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -180,8 +189,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 24_300_000 picoseconds. - Weight::from_parts(25_359_000, 0) + // Minimum execution time: 30_503_000 picoseconds. + Weight::from_parts(31_361_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -204,8 +213,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 27_579_000 picoseconds. - Weight::from_parts(28_414_000, 0) + // Minimum execution time: 35_562_000 picoseconds. + Weight::from_parts(36_710_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -216,45 +225,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_762_000 picoseconds. - Weight::from_parts(1_884_000, 0) + // Minimum execution time: 2_223_000 picoseconds. + Weight::from_parts(2_432_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `89` - // Estimated: `13454` - // Minimum execution time: 16_512_000 picoseconds. - Weight::from_parts(16_818_000, 0) - .saturating_add(Weight::from_parts(0, 13454)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15929` + // Minimum execution time: 21_863_000 picoseconds. + Weight::from_parts(22_213_000, 0) + .saturating_add(Weight::from_parts(0, 15929)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `93` - // Estimated: `13458` - // Minimum execution time: 16_368_000 picoseconds. - Weight::from_parts(16_887_000, 0) - .saturating_add(Weight::from_parts(0, 13458)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15933` + // Minimum execution time: 22_044_000 picoseconds. + Weight::from_parts(22_548_000, 0) + .saturating_add(Weight::from_parts(0, 15933)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `15946` - // Minimum execution time: 17_661_000 picoseconds. - Weight::from_parts(17_963_000, 0) - .saturating_add(Weight::from_parts(0, 15946)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18421` + // Minimum execution time: 24_336_000 picoseconds. + Weight::from_parts(25_075_000, 0) + .saturating_add(Weight::from_parts(0, 18421)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -272,36 +281,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 24_498_000 picoseconds. - Weight::from_parts(25_339_000, 0) + // Minimum execution time: 30_160_000 picoseconds. + Weight::from_parts(30_807_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `11026` - // Minimum execution time: 10_675_000 picoseconds. - Weight::from_parts(11_106_000, 0) - .saturating_add(Weight::from_parts(0, 11026)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `109` + // Estimated: `13474` + // Minimum execution time: 16_129_000 picoseconds. + Weight::from_parts(16_686_000, 0) + .saturating_add(Weight::from_parts(0, 13474)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `100` - // Estimated: `13465` - // Minimum execution time: 16_520_000 picoseconds. - Weight::from_parts(16_915_000, 0) - .saturating_add(Weight::from_parts(0, 13465)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15940` + // Minimum execution time: 21_844_000 picoseconds. + Weight::from_parts(22_452_000, 0) + .saturating_add(Weight::from_parts(0, 15940)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -316,11 +325,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `13507` - // Minimum execution time: 32_851_000 picoseconds. - Weight::from_parts(33_772_000, 0) - .saturating_add(Weight::from_parts(0, 13507)) - .saturating_add(T::DbWeight::get().reads(10)) + // Estimated: `15982` + // Minimum execution time: 42_336_000 picoseconds. + Weight::from_parts(43_502_000, 0) + .saturating_add(Weight::from_parts(0, 15982)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -331,8 +340,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_373_000 picoseconds. - Weight::from_parts(3_534_000, 0) + // Minimum execution time: 4_682_000 picoseconds. + Weight::from_parts(4_902_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -343,22 +352,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 26_027_000 picoseconds. - Weight::from_parts(26_467_000, 0) + // Minimum execution time: 27_848_000 picoseconds. + Weight::from_parts(28_267_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 35_692_000 picoseconds. - Weight::from_parts(36_136_000, 0) + // Minimum execution time: 41_653_000 picoseconds. + Weight::from_parts(42_316_000, 0) .saturating_add(Weight::from_parts(0, 3555)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs index b8db473f1066..dc21e2ea117f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/mod.rs @@ -22,7 +22,11 @@ use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -83,7 +87,7 @@ impl XcmWeightInfo for CoretimeRococoXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -132,12 +136,35 @@ impl XcmWeightInfo for CoretimeRococoXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -229,4 +256,18 @@ impl XcmWeightInfo for CoretimeRococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index c8dbdadf7b15..0a2d74de0cb8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 29_812_000 picoseconds. - Weight::from_parts(30_526_000, 3593) + // Minimum execution time: 31_260_000 picoseconds. + Weight::from_parts(31_771_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 39_430_000 picoseconds. - Weight::from_parts(39_968_000, 6196) + // Minimum execution time: 42_231_000 picoseconds. + Weight::from_parts(42_718_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `207` // Estimated: `6196` - // Minimum execution time: 65_555_000 picoseconds. - Weight::from_parts(67_161_000, 6196) + // Minimum execution time: 68_764_000 picoseconds. + Weight::from_parts(70_505_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -118,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 30_491_000 picoseconds. - Weight::from_parts(31_991_000, 3571) + // Minimum execution time: 31_390_000 picoseconds. + Weight::from_parts(32_057_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -127,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_568_000 picoseconds. - Weight::from_parts(2_703_000, 0) + // Minimum execution time: 2_288_000 picoseconds. + Weight::from_parts(2_477_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 22_159_000 picoseconds. - Weight::from_parts(22_517_000, 3593) + // Minimum execution time: 22_946_000 picoseconds. + Weight::from_parts(23_462_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3593` - // Minimum execution time: 57_126_000 picoseconds. - Weight::from_parts(58_830_000, 3593) + // Minimum execution time: 59_017_000 picoseconds. + Weight::from_parts(60_338_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,9 +180,32 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 26_589_000 picoseconds. - Weight::from_parts(27_285_000, 3571) + // Minimum execution time: 29_953_000 picoseconds. + Weight::from_parts(30_704_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3593` + // Minimum execution time: 65_118_000 picoseconds. + Weight::from_parts(66_096_000, 3593) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 676048f92ad9..cdcba6134bf8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 23_760_000 picoseconds. - Weight::from_parts(24_411_000, 3571) + // Minimum execution time: 29_263_000 picoseconds. + Weight::from_parts(30_387_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -73,8 +73,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 522_000 picoseconds. - Weight::from_parts(546_000, 0) + // Minimum execution time: 603_000 picoseconds. + Weight::from_parts(664_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_530_000 picoseconds. + Weight::from_parts(1_662_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -82,58 +89,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 5_830_000 picoseconds. - Weight::from_parts(6_069_000, 3497) + // Minimum execution time: 7_290_000 picoseconds. + Weight::from_parts(7_493_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_508_000 picoseconds. - Weight::from_parts(5_801_000, 0) + // Minimum execution time: 6_785_000 picoseconds. + Weight::from_parts(7_012_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_130_000 picoseconds. - Weight::from_parts(1_239_000, 0) + // Minimum execution time: 1_299_000 picoseconds. + Weight::from_parts(1_380_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 541_000 picoseconds. - Weight::from_parts(567_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(681_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 560_000 picoseconds. - Weight::from_parts(591_000, 0) + // Minimum execution time: 625_000 picoseconds. + Weight::from_parts(669_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 505_000 picoseconds. - Weight::from_parts(547_000, 0) + // Minimum execution time: 607_000 picoseconds. + Weight::from_parts(650_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 538_000 picoseconds. - Weight::from_parts(565_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(688_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 514_000 picoseconds. - Weight::from_parts(541_000, 0) + // Minimum execution time: 602_000 picoseconds. + Weight::from_parts(650_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -151,8 +158,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 20_920_000 picoseconds. - Weight::from_parts(21_437_000, 3571) + // Minimum execution time: 26_176_000 picoseconds. + Weight::from_parts(26_870_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -162,8 +169,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 8_549_000 picoseconds. - Weight::from_parts(8_821_000, 3555) + // Minimum execution time: 10_674_000 picoseconds. + Weight::from_parts(10_918_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -171,8 +178,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 525_000 picoseconds. - Weight::from_parts(544_000, 0) + // Minimum execution time: 601_000 picoseconds. + Weight::from_parts(639_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -190,8 +197,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 19_645_000 picoseconds. - Weight::from_parts(20_104_000, 3539) + // Minimum execution time: 24_220_000 picoseconds. + Weight::from_parts(24_910_000, 3539) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -201,44 +208,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_232_000 picoseconds. - Weight::from_parts(2_334_000, 0) + // Minimum execution time: 2_464_000 picoseconds. + Weight::from_parts(2_618_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 883_000 picoseconds. - Weight::from_parts(945_000, 0) + // Minimum execution time: 984_000 picoseconds. + Weight::from_parts(1_041_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 600_000 picoseconds. - Weight::from_parts(645_000, 0) + // Minimum execution time: 730_000 picoseconds. + Weight::from_parts(769_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 527_000 picoseconds. - Weight::from_parts(552_000, 0) + // Minimum execution time: 615_000 picoseconds. + Weight::from_parts(658_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 527_000 picoseconds. - Weight::from_parts(550_000, 0) + // Minimum execution time: 607_000 picoseconds. + Weight::from_parts(637_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 657_000 picoseconds. - Weight::from_parts(703_000, 0) + // Minimum execution time: 791_000 picoseconds. + Weight::from_parts(838_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -256,8 +263,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 24_999_000 picoseconds. - Weight::from_parts(25_671_000, 3571) + // Minimum execution time: 30_210_000 picoseconds. + Weight::from_parts(30_973_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,8 +272,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_159_000 picoseconds. - Weight::from_parts(3_296_000, 0) + // Minimum execution time: 3_097_000 picoseconds. + Weight::from_parts(3_277_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -284,8 +291,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 21_052_000 picoseconds. - Weight::from_parts(22_153_000, 3571) + // Minimum execution time: 26_487_000 picoseconds. + Weight::from_parts(27_445_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -293,35 +300,49 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 547_000 picoseconds. - Weight::from_parts(584_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(689_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 506_000 picoseconds. - Weight::from_parts(551_000, 0) + // Minimum execution time: 627_000 picoseconds. + Weight::from_parts(659_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 508_000 picoseconds. - Weight::from_parts(527_000, 0) + // Minimum execution time: 603_000 picoseconds. + Weight::from_parts(650_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 527_000 picoseconds. - Weight::from_parts(558_000, 0) + // Minimum execution time: 594_000 picoseconds. + Weight::from_parts(645_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 514_000 picoseconds. - Weight::from_parts(553_000, 0) + // Minimum execution time: 650_000 picoseconds. + Weight::from_parts(673_000, 0) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 707_000 picoseconds. + Weight::from_parts(749_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 2eae13de2fd4..33ad172962a1 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -37,7 +37,7 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -52,8 +52,9 @@ use xcm_builder::{ use xcm_executor::XcmExecutor; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const RocRelayLocation: Location = Location::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Rococo); + pub const RelayNetwork: Option = Some(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH)); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -177,6 +178,7 @@ parameter_types! { /// Locations that will not be charged fees in the executor, neither for execution nor delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, ); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/tests/tests.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/tests/tests.rs index 2cabce567b6e..89a593ab0f57 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/tests/tests.rs @@ -16,7 +16,9 @@ #![cfg(test)] -use coretime_rococo_runtime::xcm_config::LocationToAccountId; +use coretime_rococo_runtime::{ + xcm_config::LocationToAccountId, Block, Runtime, RuntimeCall, RuntimeOrigin, +}; use parachains_common::AccountId; use sp_core::crypto::Ss58Codec; use xcm::latest::prelude::*; @@ -132,3 +134,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 149fa5d0b045..03df782bc266 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Westend's Coretime parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -31,8 +33,8 @@ frame-try-runtime = { optional = true, workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } -pallet-message-queue = { workspace = true } pallet-broker = { workspace = true } +pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } pallet-session = { workspace = true } @@ -44,8 +46,8 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } -sp-inherents = { workspace = true } sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -72,14 +74,17 @@ cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["westend"], workspace = true } +[dev-dependencies] +parachains-runtimes-test-utils = { workspace = true, default-features = true } + [features] default = ["std"] std = [ @@ -172,6 +177,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs index 86769cb2da11..985e64fb76f9 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs @@ -140,8 +140,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: call_weight, call: request_core_count_call.encode().into(), + fallback_max_weight: Some(call_weight), }, ]); @@ -170,8 +170,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1000000000, 200000), call: request_revenue_info_at_call.encode().into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)), }, ]); @@ -199,8 +199,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(1000000000, 200000), call: credit_account_call.encode().into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)), }, ]); @@ -270,8 +270,8 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: call_weight, call: assign_core_call.encode().into(), + fallback_max_weight: Some(call_weight), }, ]); diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 2f944e79fe00..ce965f0ad1ba 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -67,8 +67,8 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT}, + generic, impl_opaque_keys, + traits::{BlakeTwo256, Block as BlockT, BlockNumberProvider}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, RuntimeDebug, }; @@ -124,6 +124,7 @@ pub type Migrations = ( pallet_broker::migration::MigrateV0ToV1, pallet_broker::migration::MigrateV1ToV2, pallet_broker::migration::MigrateV2ToV3, + pallet_broker::migration::MigrateV3ToV4, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -146,10 +147,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("coretime-westend"), - impl_name: create_runtime_str!("coretime-westend"), + spec_name: alloc::borrow::Cow::Borrowed("coretime-westend"), + impl_name: alloc::borrow::Cow::Borrowed("coretime-westend"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, @@ -445,6 +446,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } /// The type used to represent the kinds of proxying allowed. @@ -577,6 +579,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -586,6 +589,25 @@ impl pallet_utility::Config for Runtime { type WeightInfo = weights::pallet_utility::WeightInfo; } +pub struct BrokerMigrationV4BlockConversion; + +impl pallet_broker::migration::v4::BlockToRelayHeightConversion + for BrokerMigrationV4BlockConversion +{ + fn convert_block_number_to_relay_height(input_block_number: u32) -> u32 { + let relay_height = pallet_broker::RCBlockNumberProviderOf::< + ::Coretime, + >::current_block_number(); + let parachain_block_number = frame_system::Pallet::::block_number(); + let offset = relay_height - parachain_block_number * 2; + offset + input_block_number * 2 + } + + fn convert_block_length_to_relay_length(input_block_length: u32) -> u32 { + input_block_length * 2 + } +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -805,7 +827,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::TokenRelayLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -910,7 +933,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; @@ -1103,7 +1126,9 @@ impl_runtime_apis! { } fn alias_origin() -> Result<(Location, Location), BenchmarkError> { - Err(BenchmarkError::Skip) + let origin = Location::new(1, [Parachain(1000)]); + let target = Location::new(1, [Parachain(1000), AccountId32 { id: [128u8; 32], network: None }]); + Ok((origin, target)) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs index 74b1c4e47029..a0eee2d99efa 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-06-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-x5tnzzy-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_899_000 picoseconds. - Weight::from_parts(2_051_000, 0) + // Minimum execution time: 2_274_000 picoseconds. + Weight::from_parts(2_421_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `10888` // Estimated: `13506` - // Minimum execution time: 21_965_000 picoseconds. - Weight::from_parts(22_774_000, 0) + // Minimum execution time: 26_257_000 picoseconds. + Weight::from_parts(26_802_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -77,8 +77,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12090` // Estimated: `13506` - // Minimum execution time: 20_748_000 picoseconds. - Weight::from_parts(21_464_000, 0) + // Minimum execution time: 24_692_000 picoseconds. + Weight::from_parts(25_275_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -93,8 +93,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `146` // Estimated: `1631` - // Minimum execution time: 10_269_000 picoseconds. - Weight::from_parts(10_508_000, 0) + // Minimum execution time: 13_872_000 picoseconds. + Weight::from_parts(14_509_000, 0) .saturating_add(Weight::from_parts(0, 1631)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -121,6 +121,8 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(201), added: 696, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:0 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::Status` (r:0 w:1) @@ -132,32 +134,34 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12279` // Estimated: `14805 + n * (1 ±0)` - // Minimum execution time: 41_900_000 picoseconds. - Weight::from_parts(80_392_728, 0) + // Minimum execution time: 52_916_000 picoseconds. + Weight::from_parts(96_122_236, 0) .saturating_add(Weight::from_parts(0, 14805)) - // Standard Error: 870 - .saturating_add(Weight::from_parts(4_361, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(26)) + // Standard Error: 969 + .saturating_add(Weight::from_parts(5_732, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(27)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::Regions` (r:0 w:1) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `332` + // Measured: `437` // Estimated: `3593` - // Minimum execution time: 40_911_000 picoseconds. - Weight::from_parts(43_102_000, 0) + // Minimum execution time: 56_955_000 picoseconds. + Weight::from_parts(59_005_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -169,16 +173,18 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `450` + // Measured: `658` // Estimated: `4698` - // Minimum execution time: 70_257_000 picoseconds. - Weight::from_parts(73_889_000, 0) + // Minimum execution time: 108_853_000 picoseconds. + Weight::from_parts(117_467_000, 0) .saturating_add(Weight::from_parts(0, 4698)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Broker::Regions` (r:1 w:1) @@ -187,8 +193,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3551` - // Minimum execution time: 13_302_000 picoseconds. - Weight::from_parts(13_852_000, 0) + // Minimum execution time: 16_922_000 picoseconds. + Weight::from_parts(17_544_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -199,8 +205,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3551` - // Minimum execution time: 14_927_000 picoseconds. - Weight::from_parts(15_553_000, 0) + // Minimum execution time: 18_762_000 picoseconds. + Weight::from_parts(19_162_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -211,8 +217,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3551` - // Minimum execution time: 16_237_000 picoseconds. - Weight::from_parts(16_995_000, 0) + // Minimum execution time: 20_297_000 picoseconds. + Weight::from_parts(20_767_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) @@ -229,8 +235,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `736` // Estimated: `4681` - // Minimum execution time: 24_621_000 picoseconds. - Weight::from_parts(25_165_000, 0) + // Minimum execution time: 31_347_000 picoseconds. + Weight::from_parts(32_259_000, 0) .saturating_add(Weight::from_parts(0, 4681)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -249,8 +255,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `802` // Estimated: `5996` - // Minimum execution time: 29_832_000 picoseconds. - Weight::from_parts(30_894_000, 0) + // Minimum execution time: 38_310_000 picoseconds. + Weight::from_parts(39_777_000, 0) .saturating_add(Weight::from_parts(0, 5996)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) @@ -264,13 +270,13 @@ impl pallet_broker::WeightInfo for WeightInfo { /// The range of component `m` is `[1, 3]`. fn claim_revenue(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `652` + // Measured: `671` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 55_390_000 picoseconds. - Weight::from_parts(56_124_789, 0) + // Minimum execution time: 65_960_000 picoseconds. + Weight::from_parts(66_194_985, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 41_724 - .saturating_add(Weight::from_parts(1_551_266, 0).saturating_mul(m.into())) + // Standard Error: 42_455 + .saturating_add(Weight::from_parts(1_808_497, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5)) @@ -290,11 +296,11 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn purchase_credit() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `3785` - // Minimum execution time: 59_759_000 picoseconds. - Weight::from_parts(61_310_000, 0) - .saturating_add(Weight::from_parts(0, 3785)) + // Measured: `321` + // Estimated: `3786` + // Minimum execution time: 69_918_000 picoseconds. + Weight::from_parts(72_853_000, 0) + .saturating_add(Weight::from_parts(0, 3786)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -306,8 +312,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `466` // Estimated: `3551` - // Minimum execution time: 37_007_000 picoseconds. - Weight::from_parts(51_927_000, 0) + // Minimum execution time: 44_775_000 picoseconds. + Weight::from_parts(58_978_000, 0) .saturating_add(Weight::from_parts(0, 3551)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -322,8 +328,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `463` // Estimated: `3533` - // Minimum execution time: 86_563_000 picoseconds. - Weight::from_parts(91_274_000, 0) + // Minimum execution time: 67_098_000 picoseconds. + Weight::from_parts(93_626_000, 0) .saturating_add(Weight::from_parts(0, 3533)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -338,10 +344,10 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `857` + // Measured: `979` // Estimated: `3593` - // Minimum execution time: 93_655_000 picoseconds. - Weight::from_parts(98_160_000, 0) + // Minimum execution time: 89_463_000 picoseconds. + Weight::from_parts(113_286_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -354,8 +360,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `556` // Estimated: `4698` - // Minimum execution time: 33_985_000 picoseconds. - Weight::from_parts(43_618_000, 0) + // Minimum execution time: 42_073_000 picoseconds. + Weight::from_parts(52_211_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -371,30 +377,26 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(n: u32, ) -> Weight { + fn request_core_count(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 18_778_000 picoseconds. - Weight::from_parts(19_543_425, 0) + // Minimum execution time: 22_937_000 picoseconds. + Weight::from_parts(23_898_154, 0) .saturating_add(Weight::from_parts(0, 3539)) - // Standard Error: 41 - .saturating_add(Weight::from_parts(33, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Broker::CoreCountInbox` (r:1 w:1) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn process_core_count(n: u32, ) -> Weight { + fn process_core_count(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `266` // Estimated: `1487` - // Minimum execution time: 5_505_000 picoseconds. - Weight::from_parts(5_982_015, 0) + // Minimum execution time: 7_650_000 picoseconds. + Weight::from_parts(8_166_809, 0) .saturating_add(Weight::from_parts(0, 1487)) - // Standard Error: 13 - .saturating_add(Weight::from_parts(44, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -402,40 +404,54 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:1) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `442` + // Measured: `461` // Estimated: `6196` - // Minimum execution time: 38_128_000 picoseconds. - Weight::from_parts(40_979_000, 0) + // Minimum execution time: 53_023_000 picoseconds. + Weight::from_parts(54_564_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::InstaPoolIo` (r:3 w:3) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `Broker::Reservations` (r:1 w:0) /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(201), added: 696, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::PotentialRenewals` (r:20 w:40) + /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:21 w:20) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:0 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) - /// Storage: `Broker::Workplan` (r:0 w:20) + /// Storage: `Broker::Workplan` (r:0 w:1000) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn rotate_sale(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `12194` - // Estimated: `13506` - // Minimum execution time: 49_041_000 picoseconds. - Weight::from_parts(50_522_788, 0) - .saturating_add(Weight::from_parts(0, 13506)) - // Standard Error: 72 - .saturating_add(Weight::from_parts(78, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(25)) + // Measured: `16480` + // Estimated: `69404 + n * (8 ±1)` + // Minimum execution time: 29_313_000 picoseconds. + Weight::from_parts(746_062_644, 0) + .saturating_add(Weight::from_parts(0, 69404)) + // Standard Error: 22_496 + .saturating_add(Weight::from_parts(1_545_204, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(44)) + .saturating_add(T::DbWeight::get().writes(57)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(n.into())) } /// Storage: `Broker::InstaPoolIo` (r:1 w:0) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -445,8 +461,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3493` - // Minimum execution time: 5_903_000 picoseconds. - Weight::from_parts(6_202_000, 0) + // Minimum execution time: 7_625_000 picoseconds. + Weight::from_parts(7_910_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -469,8 +485,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `4786` - // Minimum execution time: 31_412_000 picoseconds. - Weight::from_parts(31_964_000, 0) + // Minimum execution time: 36_572_000 picoseconds. + Weight::from_parts(37_316_000, 0) .saturating_add(Weight::from_parts(0, 4786)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -489,8 +505,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 14_098_000 picoseconds. - Weight::from_parts(14_554_000, 0) + // Minimum execution time: 18_362_000 picoseconds. + Weight::from_parts(18_653_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -501,8 +517,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_723_000 picoseconds. - Weight::from_parts(1_822_000, 0) + // Minimum execution time: 2_193_000 picoseconds. + Weight::from_parts(2_393_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -512,8 +528,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_865_000 picoseconds. - Weight::from_parts(1_983_000, 0) + // Minimum execution time: 2_344_000 picoseconds. + Weight::from_parts(2_486_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -531,20 +547,38 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `408` // Estimated: `1893` - // Minimum execution time: 10_387_000 picoseconds. - Weight::from_parts(10_819_000, 0) + // Minimum execution time: 15_443_000 picoseconds. + Weight::from_parts(15_753_000, 0) .saturating_add(Weight::from_parts(0, 1893)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Broker::SaleInfo` (r:1 w:0) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:1) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(12021), added: 12516, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:2) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn force_reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `11125` + // Estimated: `13506` + // Minimum execution time: 31_464_000 picoseconds. + Weight::from_parts(32_798_000, 0) + .saturating_add(Weight::from_parts(0, 13506)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) fn swap_leases() -> Weight { // Proof Size summary in bytes: // Measured: `150` // Estimated: `1566` - // Minimum execution time: 5_996_000 picoseconds. - Weight::from_parts(6_278_000, 0) + // Minimum execution time: 8_637_000 picoseconds. + Weight::from_parts(8_883_000, 0) .saturating_add(Weight::from_parts(0, 1566)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -557,44 +591,44 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) /// Storage: `Broker::Status` (r:1 w:0) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `System::Account` (r:2 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::AutoRenewals` (r:1 w:1) - /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(201), added: 696, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn enable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `914` - // Estimated: `4698` - // Minimum execution time: 51_938_000 picoseconds. - Weight::from_parts(55_025_000, 4698) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `1451` + // Estimated: `6196` + // Minimum execution time: 120_585_000 picoseconds. + Weight::from_parts(148_755_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `Broker::AutoRenewals` (r:1 w:1) - /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(201), added: 696, mode: `MaxEncodedLen`) fn disable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `480` - // Estimated: `1516` - // Minimum execution time: 9_628_000 picoseconds. - Weight::from_parts(10_400_000, 1516) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } + // Measured: `506` + // Estimated: `1686` + // Minimum execution time: 18_235_000 picoseconds. + Weight::from_parts(19_113_000, 0) + .saturating_add(Weight::from_parts(0, 1686)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn on_new_timeslice() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `103` // Estimated: `3593` - // Minimum execution time: 2_187_000 picoseconds. - Weight::from_parts(2_372_000, 0) + // Minimum execution time: 4_863_000 picoseconds. + Weight::from_parts(5_045_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index fa588e982f09..7659b8a1ac7e 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `eded932c29e2`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=coretime-westend-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=coretime-westend-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,14 +64,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 18_707_000 picoseconds. - Weight::from_parts(19_391_000, 0) + // Minimum execution time: 23_956_000 picoseconds. + Weight::from_parts(24_860_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -84,18 +88,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 61_874_000 picoseconds. - Weight::from_parts(63_862_000, 0) + // Minimum execution time: 74_020_000 picoseconds. + Weight::from_parts(76_288_000, 0) .saturating_add(Weight::from_parts(0, 3571)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Regions` (r:1 w:1) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -107,17 +113,17 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `377` // Estimated: `3842` - // Minimum execution time: 98_657_000 picoseconds. - Weight::from_parts(101_260_000, 0) + // Minimum execution time: 118_691_000 picoseconds. + Weight::from_parts(128_472_000, 0) .saturating_add(Weight::from_parts(0, 3842)) - .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -130,13 +136,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_455_000 picoseconds. - Weight::from_parts(8_842_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 11_608_000 picoseconds. + Weight::from_parts(12_117_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -144,8 +153,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_850_000 picoseconds. - Weight::from_parts(6_044_000, 0) + // Minimum execution time: 7_574_000 picoseconds. + Weight::from_parts(8_305_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -155,8 +164,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_754_000 picoseconds. - Weight::from_parts(1_832_000, 0) + // Minimum execution time: 2_438_000 picoseconds. + Weight::from_parts(2_663_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -180,8 +189,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 24_886_000 picoseconds. - Weight::from_parts(25_403_000, 0) + // Minimum execution time: 31_482_000 picoseconds. + Weight::from_parts(33_926_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -204,8 +213,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 28_114_000 picoseconds. - Weight::from_parts(28_414_000, 0) + // Minimum execution time: 35_869_000 picoseconds. + Weight::from_parts(37_030_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -216,45 +225,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_713_000 picoseconds. - Weight::from_parts(1_810_000, 0) + // Minimum execution time: 2_385_000 picoseconds. + Weight::from_parts(2_588_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `89` - // Estimated: `13454` - // Minimum execution time: 15_910_000 picoseconds. - Weight::from_parts(16_256_000, 0) - .saturating_add(Weight::from_parts(0, 13454)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15929` + // Minimum execution time: 21_919_000 picoseconds. + Weight::from_parts(22_926_000, 0) + .saturating_add(Weight::from_parts(0, 15929)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `93` - // Estimated: `13458` - // Minimum execution time: 15_801_000 picoseconds. - Weight::from_parts(16_298_000, 0) - .saturating_add(Weight::from_parts(0, 13458)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15933` + // Minimum execution time: 22_588_000 picoseconds. + Weight::from_parts(23_144_000, 0) + .saturating_add(Weight::from_parts(0, 15933)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `15946` - // Minimum execution time: 17_976_000 picoseconds. - Weight::from_parts(18_390_000, 0) - .saturating_add(Weight::from_parts(0, 15946)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18421` + // Minimum execution time: 25_527_000 picoseconds. + Weight::from_parts(26_002_000, 0) + .saturating_add(Weight::from_parts(0, 18421)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -272,36 +281,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 24_723_000 picoseconds. - Weight::from_parts(25_531_000, 0) + // Minimum execution time: 30_751_000 picoseconds. + Weight::from_parts(31_977_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `11026` - // Minimum execution time: 10_954_000 picoseconds. - Weight::from_parts(11_199_000, 0) - .saturating_add(Weight::from_parts(0, 11026)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `109` + // Estimated: `13474` + // Minimum execution time: 16_496_000 picoseconds. + Weight::from_parts(16_800_000, 0) + .saturating_add(Weight::from_parts(0, 13474)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `100` - // Estimated: `13465` - // Minimum execution time: 16_561_000 picoseconds. - Weight::from_parts(16_908_000, 0) - .saturating_add(Weight::from_parts(0, 13465)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15940` + // Minimum execution time: 22_667_000 picoseconds. + Weight::from_parts(23_049_000, 0) + .saturating_add(Weight::from_parts(0, 15940)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -316,11 +325,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `13507` - // Minimum execution time: 33_279_000 picoseconds. - Weight::from_parts(33_869_000, 0) - .saturating_add(Weight::from_parts(0, 13507)) - .saturating_add(T::DbWeight::get().reads(10)) + // Estimated: `15982` + // Minimum execution time: 43_208_000 picoseconds. + Weight::from_parts(44_012_000, 0) + .saturating_add(Weight::from_parts(0, 15982)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -331,8 +340,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_405_000 picoseconds. - Weight::from_parts(3_489_000, 0) + // Minimum execution time: 4_726_000 picoseconds. + Weight::from_parts(4_989_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -343,22 +352,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_387_000 picoseconds. - Weight::from_parts(25_143_000, 0) + // Minimum execution time: 28_064_000 picoseconds. + Weight::from_parts(28_676_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 35_229_000 picoseconds. - Weight::from_parts(36_035_000, 0) + // Minimum execution time: 41_106_000 picoseconds. + Weight::from_parts(41_949_000, 0) .saturating_add(Weight::from_parts(0, 3555)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs index f35f7bfc188d..2f7529481543 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/mod.rs @@ -21,7 +21,11 @@ use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -82,7 +86,7 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -132,12 +136,35 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -150,6 +177,17 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -223,10 +261,12 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { XcmGeneric::::clear_topic() } fn alias_origin(_: &Location) -> Weight { - // XCM Executor does not currently support alias origin operations - Weight::MAX + XcmGeneric::::alias_origin() } fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 935636651eb9..227f3617da00 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 29_866_000 picoseconds. - Weight::from_parts(30_363_000, 3593) + // Minimum execution time: 30_623_000 picoseconds. + Weight::from_parts(31_009_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 39_434_000 picoseconds. - Weight::from_parts(40_274_000, 6196) + // Minimum execution time: 40_553_000 picoseconds. + Weight::from_parts(41_309_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `207` // Estimated: `6196` - // Minimum execution time: 66_303_000 picoseconds. - Weight::from_parts(68_294_000, 6196) + // Minimum execution time: 66_837_000 picoseconds. + Weight::from_parts(68_463_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -118,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 30_523_000 picoseconds. - Weight::from_parts(31_289_000, 3571) + // Minimum execution time: 30_020_000 picoseconds. + Weight::from_parts(31_409_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -127,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_517_000 picoseconds. - Weight::from_parts(2_634_000, 0) + // Minimum execution time: 2_355_000 picoseconds. + Weight::from_parts(2_464_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 22_151_000 picoseconds. - Weight::from_parts(22_907_000, 3593) + // Minimum execution time: 22_702_000 picoseconds. + Weight::from_parts(23_422_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3593` - // Minimum execution time: 57_763_000 picoseconds. - Weight::from_parts(58_941_000, 3593) + // Minimum execution time: 58_610_000 picoseconds. + Weight::from_parts(59_659_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,9 +180,32 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 26_322_000 picoseconds. - Weight::from_parts(27_197_000, 3571) + // Minimum execution time: 29_178_000 picoseconds. + Weight::from_parts(29_860_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3593` + // Minimum execution time: 63_658_000 picoseconds. + Weight::from_parts(64_869_000, 3593) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 7390f35e3974..2d10ac16ea26 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `9340d096ec0f`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("coretime-westend-dev"), DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=coretime-westend-dev +// --pallet=pallet_xcm_benchmarks::generic +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm_benchmarks::generic -// --chain=coretime-westend-dev -// --header=./cumulus/file_header.txt -// --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/ +// --template=cumulus/templates/xcm-bench-template.hbs +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,8 +66,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 23_688_000 picoseconds. - Weight::from_parts(24_845_000, 3571) + // Minimum execution time: 30_717_000 picoseconds. + Weight::from_parts(31_651_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -73,8 +75,26 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 569_000 picoseconds. - Weight::from_parts(619_000, 0) + // Minimum execution time: 618_000 picoseconds. + Weight::from_parts(659_000, 0) + } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 3_504_000 picoseconds. + Weight::from_parts(3_757_000, 3593) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 643_000 picoseconds. + Weight::from_parts(702_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -82,58 +102,65 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 5_851_000 picoseconds. - Weight::from_parts(6_061_000, 3497) + // Minimum execution time: 7_799_000 picoseconds. + Weight::from_parts(8_037_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_770_000 picoseconds. - Weight::from_parts(5_916_000, 0) + // Minimum execution time: 6_910_000 picoseconds. + Weight::from_parts(7_086_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_155_000 picoseconds. - Weight::from_parts(1_270_000, 0) + // Minimum execution time: 1_257_000 picoseconds. + Weight::from_parts(1_384_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 558_000 picoseconds. - Weight::from_parts(628_000, 0) + // Minimum execution time: 634_000 picoseconds. + Weight::from_parts(687_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 603_000 picoseconds. - Weight::from_parts(630_000, 0) + // Minimum execution time: 604_000 picoseconds. + Weight::from_parts(672_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 533_000 picoseconds. - Weight::from_parts(563_000, 0) + // Minimum execution time: 593_000 picoseconds. + Weight::from_parts(643_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 597_000 picoseconds. - Weight::from_parts(644_000, 0) + // Minimum execution time: 630_000 picoseconds. + Weight::from_parts(694_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 706_000 picoseconds. + Weight::from_parts(764_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 536_000 picoseconds. - Weight::from_parts(588_000, 0) + // Minimum execution time: 606_000 picoseconds. + Weight::from_parts(705_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -151,8 +178,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 21_146_000 picoseconds. - Weight::from_parts(21_771_000, 3571) + // Minimum execution time: 27_188_000 picoseconds. + Weight::from_parts(27_847_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -162,8 +189,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 8_446_000 picoseconds. - Weight::from_parts(8_660_000, 3555) + // Minimum execution time: 11_170_000 picoseconds. + Weight::from_parts(11_416_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -171,8 +198,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(594_000, 0) + // Minimum execution time: 590_000 picoseconds. + Weight::from_parts(653_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -190,8 +217,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 19_953_000 picoseconds. - Weight::from_parts(20_608_000, 3539) + // Minimum execution time: 25_196_000 picoseconds. + Weight::from_parts(25_641_000, 3539) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -201,44 +228,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_290_000 picoseconds. - Weight::from_parts(2_370_000, 0) + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_827_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 943_000 picoseconds. - Weight::from_parts(987_000, 0) + // Minimum execution time: 989_000 picoseconds. + Weight::from_parts(1_051_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 635_000 picoseconds. - Weight::from_parts(699_000, 0) + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(766_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 553_000 picoseconds. - Weight::from_parts(609_000, 0) + // Minimum execution time: 626_000 picoseconds. + Weight::from_parts(657_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 547_000 picoseconds. - Weight::from_parts(581_000, 0) + // Minimum execution time: 595_000 picoseconds. + Weight::from_parts(639_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 700_000 picoseconds. - Weight::from_parts(757_000, 0) + // Minimum execution time: 755_000 picoseconds. + Weight::from_parts(820_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -256,8 +283,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 24_953_000 picoseconds. - Weight::from_parts(25_516_000, 3571) + // Minimum execution time: 31_409_000 picoseconds. + Weight::from_parts(32_098_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,8 +292,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_746_000 picoseconds. - Weight::from_parts(2_944_000, 0) + // Minimum execution time: 3_258_000 picoseconds. + Weight::from_parts(3_448_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -284,8 +311,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 21_325_000 picoseconds. - Weight::from_parts(21_942_000, 3571) + // Minimum execution time: 27_200_000 picoseconds. + Weight::from_parts(28_299_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -293,35 +320,42 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 600_000 picoseconds. - Weight::from_parts(631_000, 0) + // Minimum execution time: 659_000 picoseconds. + Weight::from_parts(699_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 534_000 picoseconds. - Weight::from_parts(566_000, 0) + // Minimum execution time: 595_000 picoseconds. + Weight::from_parts(647_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 540_000 picoseconds. - Weight::from_parts(565_000, 0) + // Minimum execution time: 583_000 picoseconds. + Weight::from_parts(617_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 542_000 picoseconds. - Weight::from_parts(581_000, 0) + // Minimum execution time: 595_000 picoseconds. + Weight::from_parts(633_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 568_000 picoseconds. - Weight::from_parts(597_000, 0) + // Minimum execution time: 610_000 picoseconds. + Weight::from_parts(670_000, 0) + } + pub fn alias_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 630_000 picoseconds. + Weight::from_parts(700_000, 0) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 1205be95c932..8a4879a1506e 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -37,9 +37,10 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AccountId32Aliases, AliasChildLocation, AliasOriginRootUsingFilter, + AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, @@ -52,8 +53,10 @@ use xcm_builder::{ use xcm_executor::XcmExecutor; parameter_types! { + pub const RootLocation: Location = Location::here(); pub const TokenRelayLocation: Location = Location::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Westend); + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub const RelayNetwork: Option = Some(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -185,10 +188,15 @@ parameter_types! { /// Locations that will not be charged fees in the executor, neither for execution nor delivery. /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = ( + Equals, RelayOrOtherSystemParachains, Equals, ); +/// We allow locations to alias into their own child locations, as well as +/// AssetHub to alias into anything. +pub type Aliasers = (AliasChildLocation, AliasOriginRootUsingFilter); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -230,7 +238,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + type Aliasers = Aliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/tests/tests.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/tests/tests.rs index e391d71a9ab7..976ce23d6e87 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/tests/tests.rs @@ -16,7 +16,9 @@ #![cfg(test)] -use coretime_westend_runtime::xcm_config::LocationToAccountId; +use coretime_westend_runtime::{ + xcm_config::LocationToAccountId, Block, Runtime, RuntimeCall, RuntimeOrigin, +}; use parachains_common::AccountId; use sp_core::crypto::Ss58Codec; use xcm::latest::prelude::*; @@ -132,3 +134,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index 09b4ef679d24..1c1041a4317e 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Glutton parachain runtime." +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -18,11 +20,12 @@ frame-benchmarking = { optional = true, workspace = true } frame-executive = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -frame-system-rpc-runtime-api = { workspace = true } frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api = { workspace = true } frame-try-runtime = { optional = true, workspace = true } pallet-aura = { workspace = true } pallet-glutton = { workspace = true } +pallet-message-queue = { workspace = true } pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } sp-api = { workspace = true } @@ -31,7 +34,6 @@ sp-consensus-aura = { workspace = true } sp-core = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } -pallet-message-queue = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } @@ -75,6 +77,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] std = [ "codec/std", diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index ad656cdbb83a..763f8abea34a 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -55,7 +55,7 @@ use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -99,10 +99,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("glutton-westend"), - impl_name: create_runtime_str!("glutton-westend"), + spec_name: alloc::borrow::Cow::Borrowed("glutton-westend"), + impl_name: alloc::borrow::Cow::Borrowed("glutton-westend"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -460,7 +460,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs index d1fb50c1ab09..b67c32495d67 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs @@ -22,7 +22,7 @@ use frame_support::{ traits::{Contains, Everything, Nothing}, weights::Weight, }; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, FrameTransactionalProcessor, ParentAsSuperuser, ParentIsPreset, SovereignSignedViaLocation, @@ -30,7 +30,7 @@ use xcm_builder::{ parameter_types! { pub const WestendLocation: Location = Location::parent(); - pub const WestendNetwork: NetworkId = NetworkId::Westend; + pub const WestendNetwork: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH); pub UniversalLocation: InteriorLocation = [GlobalConsensus(WestendNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); } diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index 34458c2352fb..de2898046c0d 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Rococo's People parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } @@ -70,13 +72,16 @@ cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["rococo"], workspace = true } +[dev-dependencies] +parachains-runtimes-test-utils = { workspace = true, default-features = true } + [features] default = ["std"] std = [ @@ -171,6 +176,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index bb290c0af97d..b8db687da625 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -58,7 +58,7 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -134,10 +134,10 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("people-rococo"), - impl_name: create_runtime_str!("people-rococo"), + spec_name: alloc::borrow::Cow::Borrowed("people-rococo"), + impl_name: alloc::borrow::Cow::Borrowed("people-rococo"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -407,6 +407,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } /// The type used to represent the kinds of proxying allowed. @@ -520,6 +521,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -781,7 +783,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::RelayLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -886,7 +889,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index fabce29b5fd9..d50afdbee475 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `902e7ad7764b`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=people-rococo-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=people-rococo-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,6 +50,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -60,16 +64,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 17_830_000 picoseconds. - Weight::from_parts(18_411_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 29_029_000 picoseconds. + Weight::from_parts(29_911_000, 0) + .saturating_add(Weight::from_parts(0, 3572)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -82,12 +88,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 55_456_000 picoseconds. - Weight::from_parts(56_808_000, 0) - .saturating_add(Weight::from_parts(0, 3535)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 73_046_000 picoseconds. + Weight::from_parts(76_061_000, 0) + .saturating_add(Weight::from_parts(0, 3572)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -110,15 +116,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 11_580_000 picoseconds. + Weight::from_parts(12_050_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -126,8 +133,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_996_000 picoseconds. - Weight::from_parts(6_154_000, 0) + // Minimum execution time: 6_963_000 picoseconds. + Weight::from_parts(7_371_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -137,8 +144,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_768_000 picoseconds. - Weight::from_parts(1_914_000, 0) + // Minimum execution time: 2_281_000 picoseconds. + Weight::from_parts(2_417_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +169,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 24_120_000 picoseconds. - Weight::from_parts(24_745_000, 0) + // Minimum execution time: 30_422_000 picoseconds. + Weight::from_parts(31_342_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -186,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_630_000 picoseconds. - Weight::from_parts(27_289_000, 0) + // Minimum execution time: 35_290_000 picoseconds. + Weight::from_parts(36_161_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -198,45 +205,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_821_000 picoseconds. - Weight::from_parts(1_946_000, 0) + // Minimum execution time: 2_115_000 picoseconds. + Weight::from_parts(2_389_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `89` - // Estimated: `13454` - // Minimum execution time: 16_586_000 picoseconds. - Weight::from_parts(16_977_000, 0) - .saturating_add(Weight::from_parts(0, 13454)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15929` + // Minimum execution time: 22_355_000 picoseconds. + Weight::from_parts(23_011_000, 0) + .saturating_add(Weight::from_parts(0, 15929)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `93` - // Estimated: `13458` - // Minimum execution time: 16_923_000 picoseconds. - Weight::from_parts(17_415_000, 0) - .saturating_add(Weight::from_parts(0, 13458)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15933` + // Minimum execution time: 22_043_000 picoseconds. + Weight::from_parts(22_506_000, 0) + .saturating_add(Weight::from_parts(0, 15933)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `15946` - // Minimum execution time: 18_596_000 picoseconds. - Weight::from_parts(18_823_000, 0) - .saturating_add(Weight::from_parts(0, 15946)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18421` + // Minimum execution time: 26_143_000 picoseconds. + Weight::from_parts(26_577_000, 0) + .saturating_add(Weight::from_parts(0, 18421)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -254,36 +261,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 23_817_000 picoseconds. - Weight::from_parts(24_520_000, 0) + // Minimum execution time: 30_489_000 picoseconds. + Weight::from_parts(31_415_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `11026` - // Minimum execution time: 11_042_000 picoseconds. - Weight::from_parts(11_578_000, 0) - .saturating_add(Weight::from_parts(0, 11026)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `109` + // Estimated: `13474` + // Minimum execution time: 16_848_000 picoseconds. + Weight::from_parts(17_169_000, 0) + .saturating_add(Weight::from_parts(0, 13474)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `100` - // Estimated: `13465` - // Minimum execution time: 17_306_000 picoseconds. - Weight::from_parts(17_817_000, 0) - .saturating_add(Weight::from_parts(0, 13465)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15940` + // Minimum execution time: 22_556_000 picoseconds. + Weight::from_parts(22_875_000, 0) + .saturating_add(Weight::from_parts(0, 15940)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -298,11 +305,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 32_141_000 picoseconds. - Weight::from_parts(32_954_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(10)) + // Estimated: `15946` + // Minimum execution time: 42_772_000 picoseconds. + Weight::from_parts(43_606_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -313,8 +320,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_410_000 picoseconds. - Weight::from_parts(3_556_000, 0) + // Minimum execution time: 4_811_000 picoseconds. + Weight::from_parts(5_060_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -325,22 +332,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_021_000 picoseconds. - Weight::from_parts(25_240_000, 0) + // Minimum execution time: 31_925_000 picoseconds. + Weight::from_parts(32_294_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 33_801_000 picoseconds. - Weight::from_parts(34_655_000, 0) + // Minimum execution time: 41_804_000 picoseconds. + Weight::from_parts(42_347_000, 0) .saturating_add(Weight::from_parts(0, 3555)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs index 58007173ae1d..d55198f60a00 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/mod.rs @@ -21,7 +21,11 @@ use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -82,7 +86,7 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -131,12 +135,35 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -228,4 +255,18 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 4dd44e66dd5e..f594c45e1cf6 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("people-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 30_428_000 picoseconds. - Weight::from_parts(31_184_000, 3593) + // Minimum execution time: 30_760_000 picoseconds. + Weight::from_parts(31_209_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 41_912_000 picoseconds. - Weight::from_parts(43_346_000, 6196) + // Minimum execution time: 43_379_000 picoseconds. + Weight::from_parts(44_202_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `6196` - // Minimum execution time: 67_706_000 picoseconds. - Weight::from_parts(69_671_000, 6196) + // Minimum execution time: 67_467_000 picoseconds. + Weight::from_parts(69_235_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -118,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 29_790_000 picoseconds. - Weight::from_parts(30_655_000, 3535) + // Minimum execution time: 29_243_000 picoseconds. + Weight::from_parts(30_176_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -127,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_438_000 picoseconds. - Weight::from_parts(2_597_000, 0) + // Minimum execution time: 2_294_000 picoseconds. + Weight::from_parts(2_424_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 24_040_000 picoseconds. - Weight::from_parts(24_538_000, 3593) + // Minimum execution time: 24_058_000 picoseconds. + Weight::from_parts(24_588_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `3593` - // Minimum execution time: 58_275_000 picoseconds. - Weight::from_parts(59_899_000, 3593) + // Minimum execution time: 59_164_000 picoseconds. + Weight::from_parts(60_431_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,9 +180,32 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 25_638_000 picoseconds. - Weight::from_parts(26_514_000, 3535) + // Minimum execution time: 28_379_000 picoseconds. + Weight::from_parts(29_153_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `122` + // Estimated: `3593` + // Minimum execution time: 64_505_000 picoseconds. + Weight::from_parts(66_587_000, 3593) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 729a32117041..caa916507348 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("people-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 29_430_000 picoseconds. - Weight::from_parts(30_111_000, 3535) + // Minimum execution time: 28_898_000 picoseconds. + Weight::from_parts(29_717_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -73,8 +73,15 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 607_000 picoseconds. - Weight::from_parts(672_000, 0) + // Minimum execution time: 690_000 picoseconds. + Weight::from_parts(759_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_695_000 picoseconds. + Weight::from_parts(1_799_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -82,58 +89,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_445_000 picoseconds. - Weight::from_parts(7_623_000, 3497) + // Minimum execution time: 7_441_000 picoseconds. + Weight::from_parts(7_746_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_749_000 picoseconds. - Weight::from_parts(7_073_000, 0) + // Minimum execution time: 6_881_000 picoseconds. + Weight::from_parts(7_219_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_275_000 picoseconds. - Weight::from_parts(1_409_000, 0) + // Minimum execution time: 1_390_000 picoseconds. + Weight::from_parts(1_471_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 670_000 picoseconds. - Weight::from_parts(709_000, 0) + // Minimum execution time: 698_000 picoseconds. + Weight::from_parts(743_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 635_000 picoseconds. - Weight::from_parts(723_000, 0) + // Minimum execution time: 695_000 picoseconds. + Weight::from_parts(746_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 650_000 picoseconds. + // Minimum execution time: 664_000 picoseconds. Weight::from_parts(699_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 678_000 picoseconds. - Weight::from_parts(728_000, 0) + // Minimum execution time: 698_000 picoseconds. + Weight::from_parts(748_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 657_000 picoseconds. - Weight::from_parts(703_000, 0) + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(726_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -151,8 +158,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 25_795_000 picoseconds. - Weight::from_parts(26_415_000, 3535) + // Minimum execution time: 25_991_000 picoseconds. + Weight::from_parts(26_602_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -162,8 +169,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 10_792_000 picoseconds. - Weight::from_parts(11_061_000, 3555) + // Minimum execution time: 10_561_000 picoseconds. + Weight::from_parts(10_913_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -171,8 +178,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 624_000 picoseconds. - Weight::from_parts(682_000, 0) + // Minimum execution time: 654_000 picoseconds. + Weight::from_parts(707_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -190,8 +197,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_906_000 picoseconds. - Weight::from_parts(24_740_000, 3503) + // Minimum execution time: 23_813_000 picoseconds. + Weight::from_parts(24_352_000, 3503) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -201,44 +208,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_621_000 picoseconds. - Weight::from_parts(2_788_000, 0) + // Minimum execution time: 2_499_000 picoseconds. + Weight::from_parts(2_655_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 954_000 picoseconds. - Weight::from_parts(1_046_000, 0) + // Minimum execution time: 1_065_000 picoseconds. + Weight::from_parts(1_108_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 742_000 picoseconds. - Weight::from_parts(790_000, 0) + // Minimum execution time: 747_000 picoseconds. + Weight::from_parts(807_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 664_000 picoseconds. - Weight::from_parts(722_000, 0) + // Minimum execution time: 685_000 picoseconds. + Weight::from_parts(750_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 619_000 picoseconds. - Weight::from_parts(672_000, 0) + // Minimum execution time: 664_000 picoseconds. + Weight::from_parts(711_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 798_000 picoseconds. - Weight::from_parts(851_000, 0) + // Minimum execution time: 830_000 picoseconds. + Weight::from_parts(880_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -256,8 +263,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 29_580_000 picoseconds. - Weight::from_parts(31_100_000, 3535) + // Minimum execution time: 30_051_000 picoseconds. + Weight::from_parts(30_720_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,8 +272,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_150_000 picoseconds. - Weight::from_parts(3_326_000, 0) + // Minimum execution time: 3_136_000 picoseconds. + Weight::from_parts(3_265_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -284,8 +291,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 26_152_000 picoseconds. - Weight::from_parts(26_635_000, 3535) + // Minimum execution time: 25_980_000 picoseconds. + Weight::from_parts(26_868_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -293,35 +300,49 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 693_000 picoseconds. - Weight::from_parts(724_000, 0) + // Minimum execution time: 708_000 picoseconds. + Weight::from_parts(755_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 632_000 picoseconds. - Weight::from_parts(678_000, 0) + // Minimum execution time: 667_000 picoseconds. + Weight::from_parts(702_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 646_000 picoseconds. - Weight::from_parts(694_000, 0) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(695_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 622_000 picoseconds. - Weight::from_parts(656_000, 0) + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(707_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 639_000 picoseconds. - Weight::from_parts(679_000, 0) + // Minimum execution time: 685_000 picoseconds. + Weight::from_parts(757_000, 0) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 707_000 picoseconds. + Weight::from_parts(749_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index a2e20e2778b6..724d87587c6c 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -34,7 +34,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -51,7 +51,7 @@ use xcm_executor::XcmExecutor; parameter_types! { pub const RootLocation: Location = Location::here(); pub const RelayLocation: Location = Location::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Rococo); + pub const RelayNetwork: Option = Some(NetworkId::ByGenesis(ROCOCO_GENESIS_HASH)); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); diff --git a/cumulus/parachains/runtimes/people/people-rococo/tests/tests.rs b/cumulus/parachains/runtimes/people/people-rococo/tests/tests.rs index 3627d9c40ec2..00fe7781822a 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/tests/tests.rs @@ -17,7 +17,9 @@ #![cfg(test)] use parachains_common::AccountId; -use people_rococo_runtime::xcm_config::LocationToAccountId; +use people_rococo_runtime::{ + xcm_config::LocationToAccountId, Block, Runtime, RuntimeCall, RuntimeOrigin, +}; use sp_core::crypto::Ss58Codec; use xcm::latest::prelude::*; use xcm_runtime_apis::conversions::LocationToAccountHelper; @@ -132,3 +134,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 6840b97d8c3f..65bc8264934f 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Westend's People parachain runtime" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } @@ -70,13 +72,16 @@ cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } -cumulus-primitives-utility = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["westend"], workspace = true } +[dev-dependencies] +parachains-runtimes-test-utils = { workspace = true, default-features = true } + [features] default = ["std"] std = [ @@ -171,6 +176,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 7a586504badb..620ec41c071c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -58,7 +58,7 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -133,13 +133,13 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("people-westend"), - impl_name: create_runtime_str!("people-westend"), + spec_name: alloc::borrow::Cow::Borrowed("people-westend"), + impl_name: alloc::borrow::Cow::Borrowed("people-westend"), authoring_version: 1, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 1, + transaction_version: 2, system_version: 1, }; @@ -406,6 +406,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } /// The type used to represent the kinds of proxying allowed. @@ -519,6 +520,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_utility::Config for Runtime { @@ -779,7 +781,8 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == xcm_config::RelayLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) @@ -884,7 +887,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use sp_storage::TrackedStorageKey; @@ -1043,7 +1046,9 @@ impl_runtime_apis! { } fn alias_origin() -> Result<(Location, Location), BenchmarkError> { - Err(BenchmarkError::Skip) + let origin = Location::new(1, [Parachain(1000)]); + let target = Location::new(1, [Parachain(1000), AccountId32 { id: [128u8; 32], network: None }]); + Ok((origin, target)) } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index c337289243b7..f06669209a18 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `4105cf7eb2c7`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=people-westend-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=people-westend-dev -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,6 +50,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -60,16 +64,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 17_856_000 picoseconds. - Weight::from_parts(18_473_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 29_434_000 picoseconds. + Weight::from_parts(30_114_000, 0) + .saturating_add(Weight::from_parts(0, 3572)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -82,12 +88,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 56_112_000 picoseconds. - Weight::from_parts(57_287_000, 0) - .saturating_add(Weight::from_parts(0, 3535)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 73_433_000 picoseconds. + Weight::from_parts(75_377_000, 0) + .saturating_add(Weight::from_parts(0, 3572)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Benchmark::Override` (r:0 w:0) @@ -110,15 +116,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 11_627_000 picoseconds. + Weight::from_parts(12_034_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -126,8 +133,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_186_000 picoseconds. - Weight::from_parts(6_420_000, 0) + // Minimum execution time: 7_075_000 picoseconds. + Weight::from_parts(7_406_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -137,8 +144,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_999_000, 0) + // Minimum execution time: 2_308_000 picoseconds. + Weight::from_parts(2_485_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +169,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_833_000 picoseconds. - Weight::from_parts(24_636_000, 0) + // Minimum execution time: 29_939_000 picoseconds. + Weight::from_parts(30_795_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -186,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_557_000 picoseconds. - Weight::from_parts(27_275_000, 0) + // Minimum execution time: 34_830_000 picoseconds. + Weight::from_parts(35_677_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -198,45 +205,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_921_000 picoseconds. - Weight::from_parts(2_040_000, 0) + // Minimum execution time: 2_363_000 picoseconds. + Weight::from_parts(2_517_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Storage: `PolkadotXcm::SupportedVersion` (r:6 w:2) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `89` - // Estimated: `13454` - // Minimum execution time: 16_832_000 picoseconds. - Weight::from_parts(17_312_000, 0) - .saturating_add(Weight::from_parts(0, 13454)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15929` + // Minimum execution time: 22_322_000 picoseconds. + Weight::from_parts(22_709_000, 0) + .saturating_add(Weight::from_parts(0, 15929)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifiers` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `93` - // Estimated: `13458` - // Minimum execution time: 16_687_000 picoseconds. - Weight::from_parts(17_123_000, 0) - .saturating_add(Weight::from_parts(0, 13458)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15933` + // Minimum execution time: 22_418_000 picoseconds. + Weight::from_parts(22_834_000, 0) + .saturating_add(Weight::from_parts(0, 15933)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:7 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `15946` - // Minimum execution time: 18_164_000 picoseconds. - Weight::from_parts(18_580_000, 0) - .saturating_add(Weight::from_parts(0, 15946)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18421` + // Minimum execution time: 26_310_000 picoseconds. + Weight::from_parts(26_623_000, 0) + .saturating_add(Weight::from_parts(0, 18421)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -254,36 +261,36 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 23_577_000 picoseconds. - Weight::from_parts(24_324_000, 0) + // Minimum execution time: 29_863_000 picoseconds. + Weight::from_parts(30_467_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `11026` - // Minimum execution time: 11_014_000 picoseconds. - Weight::from_parts(11_223_000, 0) - .saturating_add(Weight::from_parts(0, 11026)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `109` + // Estimated: `13474` + // Minimum execution time: 17_075_000 picoseconds. + Weight::from_parts(17_578_000, 0) + .saturating_add(Weight::from_parts(0, 13474)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `100` - // Estimated: `13465` - // Minimum execution time: 16_887_000 picoseconds. - Weight::from_parts(17_361_000, 0) - .saturating_add(Weight::from_parts(0, 13465)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15940` + // Minimum execution time: 22_816_000 picoseconds. + Weight::from_parts(23_175_000, 0) + .saturating_add(Weight::from_parts(0, 15940)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -298,11 +305,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `13471` - // Minimum execution time: 31_705_000 picoseconds. - Weight::from_parts(32_166_000, 0) - .saturating_add(Weight::from_parts(0, 13471)) - .saturating_add(T::DbWeight::get().reads(10)) + // Estimated: `15946` + // Minimum execution time: 42_767_000 picoseconds. + Weight::from_parts(43_308_000, 0) + .saturating_add(Weight::from_parts(0, 15946)) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -313,8 +320,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_568_000 picoseconds. - Weight::from_parts(3_669_000, 0) + // Minimum execution time: 4_864_000 picoseconds. + Weight::from_parts(5_010_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -325,22 +332,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_823_000 picoseconds. - Weight::from_parts(25_344_000, 0) + // Minimum execution time: 30_237_000 picoseconds. + Weight::from_parts(30_662_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::ShouldRecordXcm` (r:1 w:0) + /// Proof: `PolkadotXcm::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_516_000 picoseconds. - Weight::from_parts(35_478_000, 0) + // Minimum execution time: 41_418_000 picoseconds. + Weight::from_parts(42_011_000, 0) .saturating_add(Weight::from_parts(0, 3555)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs index b44e8d4b61b8..466da1eadd55 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/mod.rs @@ -21,7 +21,11 @@ use alloc::vec::Vec; use frame_support::weights::Weight; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmFungibleWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; -use xcm::{latest::prelude::*, DoubleEncoded}; +use sp_runtime::BoundedVec; +use xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -82,7 +86,7 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { } fn transact( _origin_type: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -131,12 +135,35 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmFungibleWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmFungibleWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -222,10 +249,23 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { XcmGeneric::::clear_topic() } fn alias_origin(_: &Location) -> Weight { - // XCM Executor does not currently support alias origin operations - Weight::MAX + XcmGeneric::::alias_origin() } fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 8f6bfde986bb..c12da204f35b 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("people-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 30_040_000 picoseconds. - Weight::from_parts(30_758_000, 3593) + // Minimum execution time: 30_401_000 picoseconds. + Weight::from_parts(30_813_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 42_135_000 picoseconds. - Weight::from_parts(42_970_000, 6196) + // Minimum execution time: 43_150_000 picoseconds. + Weight::from_parts(43_919_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `6196` - // Minimum execution time: 67_385_000 picoseconds. - Weight::from_parts(69_776_000, 6196) + // Minimum execution time: 67_808_000 picoseconds. + Weight::from_parts(69_114_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -118,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 29_804_000 picoseconds. - Weight::from_parts(30_662_000, 3535) + // Minimum execution time: 29_312_000 picoseconds. + Weight::from_parts(30_347_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -127,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_358_000 picoseconds. - Weight::from_parts(2_497_000, 0) + // Minimum execution time: 2_283_000 picoseconds. + Weight::from_parts(2_448_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -136,8 +136,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 23_732_000 picoseconds. - Weight::from_parts(24_098_000, 3593) + // Minimum execution time: 23_556_000 picoseconds. + Weight::from_parts(24_419_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `3593` - // Minimum execution time: 58_449_000 picoseconds. - Weight::from_parts(60_235_000, 3593) + // Minimum execution time: 58_342_000 picoseconds. + Weight::from_parts(59_598_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -180,9 +180,32 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 25_708_000 picoseconds. - Weight::from_parts(26_495_000, 3535) + // Minimum execution time: 28_285_000 picoseconds. + Weight::from_parts(29_016_000, 3535) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + // Storage: `ParachainInfo::ParachainId` (r:1 w:0) + // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + // Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + // Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + pub fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `122` + // Estimated: `3593` + // Minimum execution time: 65_211_000 picoseconds. + Weight::from_parts(67_200_000, 3593) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 1377d31f2db7..3fa51a816b69 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,26 +17,28 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `9340d096ec0f`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("people-westend-dev"), DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=people-westend-dev +// --pallet=pallet_xcm_benchmarks::generic +// --header=/__w/polkadot-sdk/polkadot-sdk/cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/xcm // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm_benchmarks::generic -// --chain=people-westend-dev -// --header=./cumulus/file_header.txt -// --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/xcm/ +// --template=cumulus/templates/xcm-bench-template.hbs +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,10 +64,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 29_537_000 picoseconds. - Weight::from_parts(30_513_000, 3535) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 31_309_000 picoseconds. + Weight::from_parts(31_924_000, 3572) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -73,8 +75,26 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 683_000 picoseconds. - Weight::from_parts(738_000, 0) + // Minimum execution time: 635_000 picoseconds. + Weight::from_parts(677_000, 0) + } + // Storage: `System::Account` (r:1 w:1) + // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 3_457_000 picoseconds. + Weight::from_parts(3_656_000, 3593) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + pub fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 644_000 picoseconds. + Weight::from_parts(695_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -82,58 +102,65 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_498_000 picoseconds. - Weight::from_parts(7_904_000, 3497) + // Minimum execution time: 7_701_000 picoseconds. + Weight::from_parts(8_120_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_029_000 picoseconds. - Weight::from_parts(7_325_000, 0) + // Minimum execution time: 6_945_000 picoseconds. + Weight::from_parts(7_187_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_343_000 picoseconds. - Weight::from_parts(1_410_000, 0) + // Minimum execution time: 1_352_000 picoseconds. + Weight::from_parts(1_428_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 696_000 picoseconds. - Weight::from_parts(734_000, 0) + // Minimum execution time: 603_000 picoseconds. + Weight::from_parts(648_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 690_000 picoseconds. - Weight::from_parts(740_000, 0) + // Minimum execution time: 621_000 picoseconds. + Weight::from_parts(661_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 667_000 picoseconds. - Weight::from_parts(697_000, 0) + // Minimum execution time: 591_000 picoseconds. + Weight::from_parts(655_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 692_000 picoseconds. - Weight::from_parts(743_000, 0) + // Minimum execution time: 666_000 picoseconds. + Weight::from_parts(736_000, 0) + } + pub fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 694_000 picoseconds. + Weight::from_parts(759_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 670_000 picoseconds. - Weight::from_parts(712_000, 0) + // Minimum execution time: 632_000 picoseconds. + Weight::from_parts(664_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -149,10 +176,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 26_405_000 picoseconds. - Weight::from_parts(26_877_000, 3535) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 26_932_000 picoseconds. + Weight::from_parts(27_882_000, 3572) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -162,8 +189,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 10_953_000 picoseconds. - Weight::from_parts(11_345_000, 3555) + // Minimum execution time: 11_316_000 picoseconds. + Weight::from_parts(11_608_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -171,8 +198,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 644_000 picoseconds. - Weight::from_parts(693_000, 0) + // Minimum execution time: 564_000 picoseconds. + Weight::from_parts(614_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -190,8 +217,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 24_157_000 picoseconds. - Weight::from_parts(24_980_000, 3503) + // Minimum execution time: 24_373_000 picoseconds. + Weight::from_parts(25_068_000, 3503) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -201,44 +228,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_767_000 picoseconds. - Weight::from_parts(2_844_000, 0) + // Minimum execution time: 2_582_000 picoseconds. + Weight::from_parts(2_714_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_141_000, 0) + // Minimum execution time: 952_000 picoseconds. + Weight::from_parts(1_059_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 776_000 picoseconds. - Weight::from_parts(829_000, 0) + // Minimum execution time: 684_000 picoseconds. + Weight::from_parts(734_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 696_000 picoseconds. - Weight::from_parts(740_000, 0) + // Minimum execution time: 600_000 picoseconds. + Weight::from_parts(650_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 655_000 picoseconds. - Weight::from_parts(684_000, 0) + // Minimum execution time: 599_000 picoseconds. + Weight::from_parts(628_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 825_000 picoseconds. - Weight::from_parts(853_000, 0) + // Minimum execution time: 769_000 picoseconds. + Weight::from_parts(816_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -254,10 +281,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 30_222_000 picoseconds. - Weight::from_parts(31_110_000, 3535) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 31_815_000 picoseconds. + Weight::from_parts(32_738_000, 3572) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,8 +292,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_108_000 picoseconds. - Weight::from_parts(3_325_000, 0) + // Minimum execution time: 3_462_000 picoseconds. + Weight::from_parts(3_563_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -282,10 +309,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `70` - // Estimated: `3535` - // Minimum execution time: 26_548_000 picoseconds. - Weight::from_parts(26_911_000, 3535) + // Measured: `107` + // Estimated: `3572` + // Minimum execution time: 27_752_000 picoseconds. + Weight::from_parts(28_455_000, 3572) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -293,35 +320,42 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 684_000 picoseconds. - Weight::from_parts(726_000, 0) + // Minimum execution time: 605_000 picoseconds. + Weight::from_parts(687_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 649_000 picoseconds. - Weight::from_parts(700_000, 0) + // Minimum execution time: 610_000 picoseconds. + Weight::from_parts(646_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 650_000 picoseconds. - Weight::from_parts(686_000, 0) + // Minimum execution time: 579_000 picoseconds. + Weight::from_parts(636_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 652_000 picoseconds. - Weight::from_parts(703_000, 0) + // Minimum execution time: 583_000 picoseconds. + Weight::from_parts(626_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 673_000 picoseconds. - Weight::from_parts(742_000, 0) + // Minimum execution time: 616_000 picoseconds. + Weight::from_parts(679_000, 0) + } + pub fn alias_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 626_000 picoseconds. + Weight::from_parts(687_000, 0) } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index bec5b923d8ad..7eaa43c05b20 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -34,9 +34,10 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AccountId32Aliases, AliasChildLocation, AliasOriginRootUsingFilter, + AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, @@ -51,7 +52,8 @@ use xcm_executor::XcmExecutor; parameter_types! { pub const RootLocation: Location = Location::here(); pub const RelayLocation: Location = Location::parent(); - pub const RelayNetwork: Option = Some(NetworkId::Westend); + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub const RelayNetwork: Option = Some(NetworkId::ByGenesis(WESTEND_GENESIS_HASH)); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())].into(); @@ -195,6 +197,10 @@ pub type WaivedLocations = ( LocalPlurality, ); +/// We allow locations to alias into their own child locations, as well as +/// AssetHub to alias into anything. +pub type Aliasers = (AliasChildLocation, AliasOriginRootUsingFilter); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -236,7 +242,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + type Aliasers = Aliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); diff --git a/cumulus/parachains/runtimes/people/people-westend/tests/tests.rs b/cumulus/parachains/runtimes/people/people-westend/tests/tests.rs index fa9331952b4b..5cefec44b1cd 100644 --- a/cumulus/parachains/runtimes/people/people-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/people/people-westend/tests/tests.rs @@ -17,7 +17,9 @@ #![cfg(test)] use parachains_common::AccountId; -use people_westend_runtime::xcm_config::LocationToAccountId; +use people_westend_runtime::{ + xcm_config::LocationToAccountId, Block, Runtime, RuntimeCall, RuntimeOrigin, +}; use sp_core::crypto::Ss58Codec; use xcm::latest::prelude::*; use xcm_runtime_apis::conversions::LocationToAccountHelper; @@ -132,3 +134,13 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn xcm_payment_api_works() { + parachains_runtimes_test_utils::test_cases::xcm_payment_api_with_native_token_works::< + Runtime, + RuntimeCall, + RuntimeOrigin, + Block, + >(); +} diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index 01d7fcc2b5c8..cc8f29524514 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Utils for Runtimes testing" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -19,25 +21,27 @@ pallet-balances = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } sp-consensus-aura = { workspace = true } +sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-tracing = { workspace = true, default-features = true } -sp-core = { workspace = true } # Cumulus cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } -pallet-collator-selection = { workspace = true } -parachain-info = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-parachain-inherent = { workspace = true } cumulus-test-relay-sproof-builder = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } # Polkadot -xcm = { workspace = true } -xcm-executor = { workspace = true } pallet-xcm = { workspace = true } polkadot-parachain-primitives = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } [dev-dependencies] hex-literal = { workspace = true, default-features = true } @@ -62,11 +66,13 @@ std = [ "pallet-timestamp/std", "pallet-xcm/std", "parachain-info/std", + "parachains-common/std", "polkadot-parachain-primitives/std", "sp-consensus-aura/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "xcm-executor/std", + "xcm-runtime-apis/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 36cf2bf4f83b..5c33809ba67b 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -441,14 +441,14 @@ impl< AllPalletsWithoutSystem, > RuntimeHelper { - pub fn execute_as_governance(call: Vec, require_weight_at_most: Weight) -> Outcome { + pub fn execute_as_governance(call: Vec) -> Outcome { // prepare xcm as governance will do let xcm = Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::Superuser, - require_weight_at_most, call: call.into(), + fallback_max_weight: None, }, ExpectTransactStatus(MaybeErrorCode::Success), ]); @@ -464,22 +464,26 @@ impl< ) } - pub fn execute_as_origin_xcm( - origin: Location, + pub fn execute_as_origin( + (origin, origin_kind): (Location, OriginKind), call: Call, - buy_execution_fee: Asset, + maybe_buy_execution_fee: Option, ) -> Outcome { + let mut instructions = if let Some(buy_execution_fee) = maybe_buy_execution_fee { + vec![ + WithdrawAsset(buy_execution_fee.clone().into()), + BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, + ] + } else { + vec![UnpaidExecution { check_origin: None, weight_limit: Unlimited }] + }; + // prepare `Transact` xcm - let xcm = Xcm(vec![ - WithdrawAsset(buy_execution_fee.clone().into()), - BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: call.get_dispatch_info().call_weight, - call: call.encode().into(), - }, + instructions.extend(vec![ + Transact { origin_kind, call: call.encode().into(), fallback_max_weight: None }, ExpectTransactStatus(MaybeErrorCode::Success), ]); + let xcm = Xcm(instructions); // execute xcm as parent origin let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs index 1c58df189b67..6bdf3ef09d1b 100644 --- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs @@ -18,7 +18,15 @@ use crate::{AccountIdOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf}; use codec::Encode; -use frame_support::{assert_ok, traits::Get}; +use frame_support::{ + assert_ok, + traits::{Get, OriginTrait}, +}; +use parachains_common::AccountId; +use sp_runtime::traits::{Block as BlockT, StaticLookup}; +use xcm_runtime_apis::fees::{ + runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, Error as XcmPaymentApiError, +}; type RuntimeHelper = crate::RuntimeHelper; @@ -72,17 +80,9 @@ pub fn change_storage_constant_by_governance_works::SystemWeightInfo::set_storage(1); - // execute XCM with Transact to `set_storage` as governance does - assert_ok!(RuntimeHelper::::execute_as_governance( - set_storage_call, - require_weight_at_most - ) - .ensure_complete()); + assert_ok!(RuntimeHelper::::execute_as_governance(set_storage_call,) + .ensure_complete()); // check delivery reward constant after (stored) assert_eq!(StorageConstant::get(), new_storage_constant_value); @@ -127,21 +127,69 @@ pub fn set_storage_keys_by_governance_works( items: storage_items.clone(), }); - // estimate - storing just 1 value - use frame_system::WeightInfo; - let require_weight_at_most = - ::SystemWeightInfo::set_storage( - storage_items.len().try_into().unwrap(), - ); - // execute XCM with Transact to `set_storage` as governance does - assert_ok!(RuntimeHelper::::execute_as_governance( - kill_storage_call, - require_weight_at_most - ) - .ensure_complete()); + assert_ok!( + RuntimeHelper::::execute_as_governance(kill_storage_call,).ensure_complete() + ); }); runtime.execute_with(|| { assert_storage(); }); } + +pub fn xcm_payment_api_with_native_token_works() +where + Runtime: XcmPaymentApiV1 + + frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + cumulus_pallet_xcmp_queue::Config + + pallet_timestamp::Config, + ValidatorIdOf: From>, + RuntimeOrigin: OriginTrait::AccountId>, + <::Lookup as StaticLookup>::Source: + From<::AccountId>, + Block: BlockT, +{ + use xcm::prelude::*; + ExtBuilder::::default().build().execute_with(|| { + let transfer_amount = 100u128; + let xcm_to_weigh = Xcm::::builder_unsafe() + .withdraw_asset((Here, transfer_amount)) + .buy_execution((Here, transfer_amount), Unlimited) + .deposit_asset(AllCounted(1), [1u8; 32]) + .build(); + let versioned_xcm_to_weigh = VersionedXcm::from(xcm_to_weigh.clone().into()); + + // We first try calling it with a lower XCM version. + let lower_version_xcm_to_weigh = + versioned_xcm_to_weigh.clone().into_version(XCM_VERSION - 1).unwrap(); + let xcm_weight = Runtime::query_xcm_weight(lower_version_xcm_to_weigh); + assert!(xcm_weight.is_ok()); + let native_token: Location = Parent.into(); + let native_token_versioned = VersionedAssetId::from(AssetId(native_token)); + let lower_version_native_token = + native_token_versioned.clone().into_version(XCM_VERSION - 1).unwrap(); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), lower_version_native_token); + assert!(execution_fees.is_ok()); + + // Now we call it with the latest version. + let xcm_weight = Runtime::query_xcm_weight(versioned_xcm_to_weigh); + assert!(xcm_weight.is_ok()); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), native_token_versioned); + assert!(execution_fees.is_ok()); + + // If we call it with anything other than the native token it will error. + let non_existent_token: Location = Here.into(); + let non_existent_token_versioned = VersionedAssetId::from(AssetId(non_existent_token)); + let execution_fees = + Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), non_existent_token_versioned); + assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound)); + }); +} diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 14c4fe520384..5b17f4f57388 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -32,6 +32,9 @@ frame-system = { workspace = true } frame-system-benchmarking = { optional = true, workspace = true } frame-system-rpc-runtime-api = { workspace = true } frame-try-runtime = { optional = true, workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-asset-tx-payment = { workspace = true } +pallet-assets = { workspace = true } pallet-aura = { workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } @@ -40,9 +43,6 @@ pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } -pallet-asset-tx-payment = { workspace = true } -pallet-assets = { workspace = true } -pallet-asset-conversion = { workspace = true } sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } @@ -57,9 +57,9 @@ sp-transaction-pool = { workspace = true } sp-version = { workspace = true } # Polkadot -polkadot-primitives = { workspace = true } pallet-xcm = { workspace = true } polkadot-parachain-primitives = { workspace = true } +polkadot-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } @@ -67,8 +67,8 @@ xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } # Cumulus +assets-common = { workspace = true } cumulus-pallet-aura-ext = { workspace = true } -pallet-message-queue = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-session-benchmarking = { workspace = true } cumulus-pallet-xcm = { workspace = true } @@ -76,9 +76,10 @@ cumulus-pallet-xcmp-queue = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-utility = { workspace = true } pallet-collator-selection = { workspace = true } +pallet-message-queue = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } -assets-common = { workspace = true } +snowbridge-router-primitives = { workspace = true } primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] } @@ -123,6 +124,7 @@ std = [ "polkadot-runtime-common/std", "primitive-types/std", "scale-info/std", + "snowbridge-router-primitives/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -168,10 +170,12 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", + "snowbridge-router-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 136592c56026..b51670c792d6 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -36,6 +36,7 @@ extern crate alloc; use alloc::{vec, vec::Vec}; use assets_common::{ + foreign_creators::ForeignCreators, local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, AssetIdForTrustBackedAssetsConvert, }; @@ -73,7 +74,7 @@ use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Dispatchable}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -82,7 +83,7 @@ pub use sp_runtime::{traits::ConvertInto, MultiAddress, Perbill, Permill}; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm_config::{ForeignAssetsAssetId, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{ForeignAssetsAssetId, LocationToAccountId, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -242,8 +243,8 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("penpal-parachain"), - impl_name: create_runtime_str!("penpal-parachain"), + spec_name: alloc::borrow::Cow::Borrowed("penpal-parachain"), + impl_name: alloc::borrow::Cow::Borrowed("penpal-parachain"), authoring_version: 1, spec_version: 1, impl_version: 0, @@ -494,7 +495,10 @@ impl pallet_assets::Config for Runtime { type AssetId = ForeignAssetsAssetId; type AssetIdParameter = ForeignAssetsAssetId; type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; + // This is to allow any other remote location to create foreign assets. Used in tests, not + // recommended on real chains. + type CreateOrigin = + ForeignCreators; type ForceOrigin = EnsureRoot; type AssetDeposit = ForeignAssetsAssetDeposit; type MetadataDepositBase = ForeignAssetsMetadataDepositBase; @@ -1117,7 +1121,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{Benchmarking, BenchmarkBatch}; use sp_storage::TrackedStorageKey; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index b72d6d232a1d..10481d5d2ebc 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -34,7 +34,7 @@ use core::marker::PhantomData; use frame_support::{ parameter_types, traits::{ - tokens::imbalance::ResolveAssetTo, ConstU32, Contains, ContainsPair, Everything, + tokens::imbalance::ResolveAssetTo, ConstU32, Contains, ContainsPair, Equals, Everything, EverythingBut, Get, Nothing, PalletInfoAccess, }, weights::Weight, @@ -44,13 +44,15 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{xcm_config::AssetFeeAsExistentialDepositMultiplier, TREASURY_PALLET_ID}; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::{impls::ToAuthor, xcm_sender::ExponentialPrice}; +use snowbridge_router_primitives::inbound::EthereumLocationsConverterFor; use sp_runtime::traits::{AccountIdConversion, ConvertInto, Identity, TryConvertInto}; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, - ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete, + AccountId32Aliases, AliasOriginRootUsingFilter, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + AsPrefixedGeneralIndex, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, + FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter, @@ -65,8 +67,8 @@ parameter_types! { pub const PenpalNativeCurrency: Location = Location::here(); // The Penpal runtime is utilized for testing with various environment setups. // This storage item allows us to customize the `NetworkId` where Penpal is deployed. - // By default, it is set to `NetworkId::Rococo` and can be changed using `System::set_storage`. - pub storage RelayNetworkId: NetworkId = NetworkId::Westend; + // By default, it is set to `Westend Network` and can be changed using `System::set_storage`. + pub storage RelayNetworkId: NetworkId = NetworkId::ByGenesis(WESTEND_GENESIS_HASH); pub RelayNetwork: Option = Some(RelayNetworkId::get()); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [ @@ -92,6 +94,12 @@ pub type LocationToAccountId = ( AccountId32Aliases, // Foreign locations alias into accounts according to a hash of their standard description. HashedDescription>, + // Different global consensus parachain sovereign account. + // (Used for over-bridge transfers and reserve processing) + GlobalConsensusParachainConvertsFor, + // Ethereum contract sovereign account. + // (Used to get convert ethereum contract locations to sovereign account) + EthereumLocationsConverterFor, ); /// Means for transacting assets on this chain. @@ -202,6 +210,7 @@ pub type XcmOriginToTransactDispatchOrigin = ( ); parameter_types! { + pub const RootLocation: Location = Location::here(); // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); pub const MaxInstructions: u32 = 100; @@ -328,6 +337,7 @@ pub type TrustedReserves = ( pub type TrustedTeleporters = (AssetFromChain,); +pub type WaivedLocations = Equals; /// `AssetId`/`Balance` converter for `TrustBackedAssets`. pub type TrustBackedAssetsConvertedConcreteId = assets_common::TrustBackedAssetsConvertedConcreteId; @@ -391,14 +401,15 @@ impl xcm_executor::Config for XcmConfig { type AssetLocker = (); type AssetExchanger = PoolAssetsExchanger; type FeeManager = XcmFeeManagerFromComponents< - (), + WaivedLocations, SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + // We allow trusted Asset Hub root to alias other locations. + type Aliasers = AliasOriginRootUsingFilter; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index b0581c8d43ff..e8761445f161 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Simple runtime used by the rococo parachain(s)" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -41,15 +43,14 @@ sp-version = { workspace = true } # Polkadot pallet-xcm = { workspace = true } polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } -polkadot-runtime-common = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } -pallet-message-queue = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, features = ["experimental-ump-signals"] } +cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-ping = { workspace = true } @@ -57,9 +58,10 @@ cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } cumulus-primitives-utility = { workspace = true } +pallet-message-queue = { workspace = true } +parachain-info = { workspace = true } parachains-common = { workspace = true } testnet-parachains-constants = { features = ["rococo"], workspace = true } -parachain-info = { workspace = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } @@ -134,6 +136,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] # A feature that should be enabled when the runtime should be built for on-chain diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 34bd45b6ef99..42556e0b493c 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -30,7 +30,7 @@ use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, Hash as HashT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, @@ -85,7 +85,7 @@ use xcm_executor::traits::JustTry; // XCM imports use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; use polkadot_parachain_primitives::primitives::Sibling; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, FungibleAdapter, IsConcrete, NativeAsset, @@ -106,8 +106,8 @@ impl_opaque_keys! { /// This runtime version. #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("test-parachain"), - impl_name: create_runtime_str!("test-parachain"), + spec_name: alloc::borrow::Cow::Borrowed("test-parachain"), + impl_name: alloc::borrow::Cow::Borrowed("test-parachain"), authoring_version: 1, spec_version: 1_014_000, impl_version: 0, @@ -332,7 +332,7 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { pub const RocLocation: Location = Location::parent(); - pub const RococoNetwork: NetworkId = NetworkId::Rococo; + pub const RococoNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RococoNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); diff --git a/cumulus/polkadot-omni-node/Cargo.toml b/cumulus/polkadot-omni-node/Cargo.toml index a736e1ef80c5..8b46bc882868 100644 --- a/cumulus/polkadot-omni-node/Cargo.toml +++ b/cumulus/polkadot-omni-node/Cargo.toml @@ -6,6 +6,8 @@ edition.workspace = true build = "build.rs" description = "Generic binary that can run a parachain node with u32 block number and Aura consensus" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/polkadot-omni-node/README.md b/cumulus/polkadot-omni-node/README.md index d87b3b63c407..015019961c9f 100644 --- a/cumulus/polkadot-omni-node/README.md +++ b/cumulus/polkadot-omni-node/README.md @@ -49,10 +49,10 @@ chain-spec-builder create --relay-chain --para-id -r +polkadot-omni-node --dev --chain ``` ## Useful links diff --git a/cumulus/polkadot-omni-node/lib/Cargo.toml b/cumulus/polkadot-omni-node/lib/Cargo.toml index a690229f1695..018fc88a2aea 100644 --- a/cumulus/polkadot-omni-node/lib/Cargo.toml +++ b/cumulus/polkadot-omni-node/lib/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Helper library that can be used to build a parachain node" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,55 +19,61 @@ async-trait = { workspace = true } clap = { features = ["derive"], workspace = true } codec = { workspace = true, default-features = true } color-print = { workspace = true } +docify = { workspace = true } futures = { workspace = true } log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -docify = { workspace = true } # Local jsonrpsee = { features = ["server"], workspace = true } parachains-common = { workspace = true, default-features = true } +scale-info = { workspace = true } +subxt-metadata = { workspace = true, default-features = true } # Substrate frame-benchmarking = { optional = true, workspace = true, default-features = true } frame-benchmarking-cli = { workspace = true, default-features = true } -sp-runtime = { workspace = true } -sp-core = { workspace = true, default-features = true } -sp-session = { workspace = true, default-features = true } -frame-try-runtime = { optional = true, workspace = true, default-features = true } -sc-consensus = { workspace = true, default-features = true } frame-support = { optional = true, workspace = true, default-features = true } +frame-system-rpc-runtime-api = { workspace = true, default-features = true } +frame-try-runtime = { optional = true, workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-transaction-payment-rpc = { workspace = true, default-features = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-client-db = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-manual-seal = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-runtime-utilities = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } -sp-transaction-pool = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -sc-basic-authorship = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } -sp-genesis-builder = { workspace = true } +sp-api = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } -sc-chain-spec = { workspace = true, default-features = true } -sc-rpc = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } sp-weights = { workspace = true, default-features = true } -sc-tracing = { workspace = true, default-features = true } -frame-system-rpc-runtime-api = { workspace = true, default-features = true } -pallet-transaction-payment = { workspace = true, default-features = true } -pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } -sp-inherents = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } -sp-consensus-aura = { workspace = true, default-features = true } -sc-consensus-manual-seal = { workspace = true, default-features = true } -sc-sysinfo = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } substrate-frame-rpc-system = { workspace = true, default-features = true } -pallet-transaction-payment-rpc = { workspace = true, default-features = true } substrate-state-trie-migration-rpc = { workspace = true, default-features = true } # Polkadot @@ -76,9 +84,9 @@ polkadot-primitives = { workspace = true, default-features = true } cumulus-client-cli = { workspace = true, default-features = true } cumulus-client-collator = { workspace = true, default-features = true } cumulus-client-consensus-aura = { workspace = true, default-features = true } -cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } cumulus-client-consensus-common = { workspace = true, default-features = true } cumulus-client-consensus-proposer = { workspace = true, default-features = true } +cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } cumulus-client-parachain-inherent = { workspace = true, default-features = true } cumulus-client-service = { workspace = true, default-features = true } cumulus-primitives-aura = { workspace = true, default-features = true } @@ -88,18 +96,15 @@ futures-timer = "3.0.3" [dev-dependencies] assert_cmd = { workspace = true } +cumulus-test-runtime = { workspace = true } nix = { features = ["signal"], workspace = true } tokio = { version = "1.32.0", features = ["macros", "parking_lot", "time"] } wait-timeout = { workspace = true } [features] default = [] -rococo-native = [ - "polkadot-cli/rococo-native", -] -westend-native = [ - "polkadot-cli/westend-native", -] +rococo-native = ["polkadot-cli/rococo-native"] +westend-native = ["polkadot-cli/westend-native"] runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", diff --git a/cumulus/polkadot-omni-node/lib/src/cli.rs b/cumulus/polkadot-omni-node/lib/src/cli.rs index dc59c185d909..9c4e2561592d 100644 --- a/cumulus/polkadot-omni-node/lib/src/cli.rs +++ b/cumulus/polkadot-omni-node/lib/src/cli.rs @@ -126,9 +126,14 @@ pub struct Cli { /// Start a dev node that produces a block each `dev_block_time` ms. /// - /// This is a dev option, and it won't result in starting or connecting to a parachain network. - /// The resulting node will work on its own, running the wasm blob and artificially producing - /// a block each `dev_block_time` ms, as if it was part of a parachain. + /// This is a dev option. It enables a manual sealing, meaning blocks are produced manually + /// rather than being part of an actual network consensus process. Using the option won't + /// result in starting or connecting to a parachain network. The resulting node will work on + /// its own, running the wasm blob and artificially producing a block each `dev_block_time` ms, + /// as if it was part of a parachain. + /// + /// The `--dev` flag sets the `dev_block_time` to a default value of 3000ms unless explicitly + /// provided. #[arg(long)] pub dev_block_time: Option, diff --git a/cumulus/polkadot-omni-node/lib/src/command.rs b/cumulus/polkadot-omni-node/lib/src/command.rs index cf283819966f..fe7f7cac0971 100644 --- a/cumulus/polkadot-omni-node/lib/src/command.rs +++ b/cumulus/polkadot-omni-node/lib/src/command.rs @@ -34,11 +34,13 @@ use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunc use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; -use sc_cli::{Result, SubstrateCli}; +use sc_cli::{CliConfiguration, Result, SubstrateCli}; use sp_runtime::traits::AccountIdConversion; #[cfg(feature = "runtime-benchmarks")] use sp_runtime::traits::HashingFor; +const DEFAULT_DEV_BLOCK_TIME_MS: u64 = 3000; + /// Structure that can be used in order to provide customizers for different functionalities of the /// node binary that is being built using this library. pub struct RunConfig { @@ -230,10 +232,19 @@ pub fn run(cmd_config: RunConfig) -> Result<() .ok_or("Could not find parachain extension in chain-spec.")?, ); + if cli.run.base.is_dev()? { + // Set default dev block time to 3000ms if not set. + // TODO: take block time from AURA config if set. + let dev_block_time = cli.dev_block_time.unwrap_or(DEFAULT_DEV_BLOCK_TIME_MS); + return node_spec + .start_manual_seal_node(config, para_id, dev_block_time) + .map_err(Into::into); + } + if let Some(dev_block_time) = cli.dev_block_time { return node_spec .start_manual_seal_node(config, para_id, dev_block_time) - .map_err(Into::into) + .map_err(Into::into); } // If Statemint (Statemine, Westmint, Rockmine) DB exists and we're using the diff --git a/cumulus/polkadot-omni-node/lib/src/common/runtime.rs b/cumulus/polkadot-omni-node/lib/src/common/runtime.rs index 509d13b9d7a2..fcc1d7f0643e 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/runtime.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/runtime.rs @@ -16,7 +16,19 @@ //! Runtime parameters. +use codec::Decode; +use cumulus_client_service::ParachainHostFunctions; use sc_chain_spec::ChainSpec; +use sc_executor::WasmExecutor; +use sc_runtime_utilities::fetch_latest_metadata_from_code_blob; +use scale_info::{form::PortableForm, TypeDef, TypeDefPrimitive}; +use std::fmt::Display; +use subxt_metadata::{Metadata, StorageEntryType}; + +/// Expected parachain system pallet runtime type name. +pub const DEFAULT_PARACHAIN_SYSTEM_PALLET_NAME: &str = "ParachainSystem"; +/// Expected frame system pallet runtime type name. +pub const DEFAULT_FRAME_SYSTEM_PALLET_NAME: &str = "System"; /// The Aura ID used by the Aura consensus #[derive(PartialEq)] @@ -35,7 +47,7 @@ pub enum Consensus { } /// The choice of block number for the parachain omni-node. -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum BlockNumber { /// u32 U32, @@ -43,6 +55,34 @@ pub enum BlockNumber { U64, } +impl Display for BlockNumber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BlockNumber::U32 => write!(f, "u32"), + BlockNumber::U64 => write!(f, "u64"), + } + } +} + +impl Into for BlockNumber { + fn into(self) -> TypeDefPrimitive { + match self { + BlockNumber::U32 => TypeDefPrimitive::U32, + BlockNumber::U64 => TypeDefPrimitive::U64, + } + } +} + +impl BlockNumber { + fn from_type_def(type_def: &TypeDef) -> Option { + match type_def { + TypeDef::Primitive(TypeDefPrimitive::U32) => Some(BlockNumber::U32), + TypeDef::Primitive(TypeDefPrimitive::U64) => Some(BlockNumber::U64), + _ => None, + } + } +} + /// Helper enum listing the supported Runtime types #[derive(PartialEq)] pub enum Runtime { @@ -62,7 +102,112 @@ pub trait RuntimeResolver { pub struct DefaultRuntimeResolver; impl RuntimeResolver for DefaultRuntimeResolver { - fn runtime(&self, _chain_spec: &dyn ChainSpec) -> sc_cli::Result { - Ok(Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519))) + fn runtime(&self, chain_spec: &dyn ChainSpec) -> sc_cli::Result { + let Ok(metadata_inspector) = MetadataInspector::new(chain_spec) else { + log::info!("Unable to check metadata. Skipping metadata checks. Metadata checks are supported for metadata versions v14 and higher."); + return Ok(Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519))) + }; + + let block_number = match metadata_inspector.block_number() { + Some(inner) => inner, + None => { + log::warn!( + r#"⚠️ There isn't a runtime type named `System`, corresponding to the `frame-system` + pallet (https://docs.rs/frame-system/latest/frame_system/). Please check Omni Node docs for runtime conventions: + https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html#runtime-conventions. + Note: We'll assume a block number size of `u32`."# + ); + BlockNumber::U32 + }, + }; + + if !metadata_inspector.pallet_exists(DEFAULT_PARACHAIN_SYSTEM_PALLET_NAME) { + log::warn!( + r#"⚠️ The parachain system pallet (https://docs.rs/crate/cumulus-pallet-parachain-system/latest) is + missing from the runtime’s metadata. Please check Omni Node docs for runtime conventions: + https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html#runtime-conventions."# + ); + } + + Ok(Runtime::Omni(block_number, Consensus::Aura(AuraConsensusId::Sr25519))) + } +} + +struct MetadataInspector(Metadata); + +impl MetadataInspector { + fn new(chain_spec: &dyn ChainSpec) -> Result { + MetadataInspector::fetch_metadata(chain_spec).map(MetadataInspector) + } + + fn pallet_exists(&self, name: &str) -> bool { + self.0.pallet_by_name(name).is_some() + } + + fn block_number(&self) -> Option { + let pallet_metadata = self.0.pallet_by_name(DEFAULT_FRAME_SYSTEM_PALLET_NAME); + pallet_metadata + .and_then(|inner| inner.storage()) + .and_then(|inner| inner.entry_by_name("Number")) + .and_then(|number_ty| match number_ty.entry_type() { + StorageEntryType::Plain(ty_id) => Some(ty_id), + _ => None, + }) + .and_then(|ty_id| self.0.types().resolve(*ty_id)) + .and_then(|portable_type| BlockNumber::from_type_def(&portable_type.type_def)) + } + + fn fetch_metadata(chain_spec: &dyn ChainSpec) -> Result { + let mut storage = chain_spec.build_storage()?; + let code_bytes = storage + .top + .remove(sp_storage::well_known_keys::CODE) + .ok_or("chain spec genesis does not contain code")?; + let opaque_metadata = fetch_latest_metadata_from_code_blob( + &WasmExecutor::::builder() + .with_allow_missing_host_functions(true) + .build(), + sp_runtime::Cow::Borrowed(code_bytes.as_slice()), + ) + .map_err(|err| err.to_string())?; + + Metadata::decode(&mut (*opaque_metadata).as_slice()).map_err(Into::into) + } +} + +#[cfg(test)] +mod tests { + use crate::runtime::{ + BlockNumber, MetadataInspector, DEFAULT_FRAME_SYSTEM_PALLET_NAME, + DEFAULT_PARACHAIN_SYSTEM_PALLET_NAME, + }; + use codec::Decode; + use cumulus_client_service::ParachainHostFunctions; + use sc_executor::WasmExecutor; + use sc_runtime_utilities::fetch_latest_metadata_from_code_blob; + + fn cumulus_test_runtime_metadata() -> subxt_metadata::Metadata { + let opaque_metadata = fetch_latest_metadata_from_code_blob( + &WasmExecutor::::builder() + .with_allow_missing_host_functions(true) + .build(), + sp_runtime::Cow::Borrowed(cumulus_test_runtime::WASM_BINARY.unwrap()), + ) + .unwrap(); + + subxt_metadata::Metadata::decode(&mut (*opaque_metadata).as_slice()).unwrap() + } + + #[test] + fn test_pallet_exists() { + let metadata_inspector = MetadataInspector(cumulus_test_runtime_metadata()); + assert!(metadata_inspector.pallet_exists(DEFAULT_PARACHAIN_SYSTEM_PALLET_NAME)); + assert!(metadata_inspector.pallet_exists(DEFAULT_FRAME_SYSTEM_PALLET_NAME)); + } + + #[test] + fn test_runtime_block_number() { + let metadata_inspector = MetadataInspector(cumulus_test_runtime_metadata()); + assert_eq!(metadata_inspector.block_number().unwrap(), BlockNumber::U32); } } diff --git a/cumulus/polkadot-omni-node/lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs index 8397cb778dcf..868368f3ca1a 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/spec.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs @@ -44,23 +44,28 @@ use sc_transaction_pool::TransactionPoolHandle; use sp_keystore::KeystorePtr; use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; -pub(crate) trait BuildImportQueue { +pub(crate) trait BuildImportQueue< + Block: BlockT, + RuntimeApi, + BlockImport: sc_consensus::BlockImport, +> +{ fn build_import_queue( client: Arc>, - block_import: ParachainBlockImport, + block_import: ParachainBlockImport, config: &Configuration, telemetry_handle: Option, task_manager: &TaskManager, ) -> sc_service::error::Result>; } -pub(crate) trait StartConsensus +pub(crate) trait StartConsensus where RuntimeApi: ConstructNodeRuntimeApi>, { fn start_consensus( client: Arc>, - block_import: ParachainBlockImport, + block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, @@ -74,6 +79,7 @@ where announce_block: Arc>) + Send + Sync>, backend: Arc>, node_extra_args: NodeExtraArgs, + block_import_extra_return_value: BIAuxiliaryData, ) -> Result<(), sc_service::Error>; } @@ -92,6 +98,31 @@ fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { } } +pub(crate) trait InitBlockImport { + type BlockImport: sc_consensus::BlockImport + Clone + Send + Sync; + type BlockImportAuxiliaryData; + + fn init_block_import( + client: Arc>, + ) -> sc_service::error::Result<(Self::BlockImport, Self::BlockImportAuxiliaryData)>; +} + +pub(crate) struct ClientBlockImport; + +impl InitBlockImport for ClientBlockImport +where + RuntimeApi: Send + ConstructNodeRuntimeApi>, +{ + type BlockImport = Arc>; + type BlockImportAuxiliaryData = (); + + fn init_block_import( + client: Arc>, + ) -> sc_service::error::Result<(Self::BlockImport, Self::BlockImportAuxiliaryData)> { + Ok((client.clone(), ())) + } +} + pub(crate) trait BaseNodeSpec { type Block: NodeBlock; @@ -100,7 +131,13 @@ pub(crate) trait BaseNodeSpec { ParachainClient, >; - type BuildImportQueue: BuildImportQueue; + type BuildImportQueue: BuildImportQueue< + Self::Block, + Self::RuntimeApi, + >::BlockImport, + >; + + type InitBlockImport: self::InitBlockImport; /// Starts a `ServiceBuilder` for a full service. /// @@ -108,7 +145,14 @@ pub(crate) trait BaseNodeSpec { /// be able to perform chain operations. fn new_partial( config: &Configuration, - ) -> sc_service::error::Result> { + ) -> sc_service::error::Result< + ParachainService< + Self::Block, + Self::RuntimeApi, + >::BlockImport, + >::BlockImportAuxiliaryData + > + >{ let telemetry = config .telemetry_endpoints .clone() @@ -160,7 +204,10 @@ pub(crate) trait BaseNodeSpec { .build(), ); - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + let (block_import, block_import_auxiliary_data) = + Self::InitBlockImport::init_block_import(client.clone())?; + + let block_import = ParachainBlockImport::new(block_import, backend.clone()); let import_queue = Self::BuildImportQueue::build_import_queue( client.clone(), @@ -178,7 +225,7 @@ pub(crate) trait BaseNodeSpec { task_manager, transaction_pool, select_chain: (), - other: (block_import, telemetry, telemetry_worker_handle), + other: (block_import, telemetry, telemetry_worker_handle, block_import_auxiliary_data), }) } } @@ -190,7 +237,12 @@ pub(crate) trait NodeSpec: BaseNodeSpec { TransactionPoolHandle>, >; - type StartConsensus: StartConsensus; + type StartConsensus: StartConsensus< + Self::Block, + Self::RuntimeApi, + >::BlockImport, + >::BlockImportAuxiliaryData, + >; const SYBIL_RESISTANCE: CollatorSybilResistance; @@ -208,153 +260,153 @@ pub(crate) trait NodeSpec: BaseNodeSpec { where Net: NetworkBackend, { - Box::pin( - async move { - let parachain_config = prepare_node_config(parachain_config); - - let params = Self::new_partial(¶chain_config)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::<_, _, Net>::new( - ¶chain_config.network, - prometheus_registry.clone(), - ); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level: Self::SYBIL_RESISTANCE, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - let backend_for_rpc = backend.clone(); - - Box::new(move |_| { - Self::BuildRpcExtensions::build_rpc_extensions( - client.clone(), - backend_for_rpc.clone(), - transaction_pool.clone(), - ) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, + let fut = async move { + let parachain_config = prepare_node_config(parachain_config); + + let params = Self::new_partial(¶chain_config)?; + let (block_import, mut telemetry, telemetry_worker_handle, block_import_auxiliary_data) = + params.other; + let client = params.client.clone(); + let backend = params.backend.clone(); + let mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = FullNetworkConfiguration::<_, _, Net>::new( + ¶chain_config.network, + prometheus_registry.clone(), + ); + + let (network, system_rpc_tx, tx_handler_controller, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + net_config, client: client.clone(), transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), para_id, + spawn_handle: task_manager.spawn_handle(), relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service, - })?; - - if validator { - Self::StartConsensus::start_consensus( + import_queue: params.import_queue, + sybil_resistance_level: Self::SYBIL_RESISTANCE, + }) + .await?; + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |_| { + Self::BuildRpcExtensions::build_rpc_extensions( client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - node_extra_args, - )?; + backend_for_rpc.clone(), + transaction_pool.clone(), + ) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend: backend.clone(), + network: network.clone(), + sync_service: sync_service.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + if validator { + warn_if_slow_hardware(&hwbench); } - start_network.start_network(); + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } - Ok(task_manager) + let announce_block = { + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + start_relay_chain_tasks(StartRelayChainTasksParams { + client: client.clone(), + announce_block: announce_block.clone(), + para_id, + relay_chain_interface: relay_chain_interface.clone(), + task_manager: &mut task_manager, + da_recovery_profile: if validator { + DARecoveryProfile::Collator + } else { + DARecoveryProfile::FullNode + }, + import_queue: import_queue_service, + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle.clone()), + sync_service, + })?; + + if validator { + Self::StartConsensus::start_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + params.keystore_container.keystore(), + relay_chain_slot_duration, + para_id, + collator_key.expect("Command line arguments do not allow this. qed"), + overseer_handle, + announce_block, + backend.clone(), + node_extra_args, + block_import_auxiliary_data, + )?; } - .instrument(sc_tracing::tracing::info_span!( + + Ok(task_manager) + }; + + Box::pin(Instrument::instrument( + fut, + sc_tracing::tracing::info_span!( sc_tracing::logging::PREFIX_LOG_SPAN, - name = "Parachain", - )), - ) + name = "Parachain" + ), + )) } } diff --git a/cumulus/polkadot-omni-node/lib/src/common/types.rs b/cumulus/polkadot-omni-node/lib/src/common/types.rs index 4bc58dc9db7e..978368be2584 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/types.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/types.rs @@ -22,7 +22,6 @@ use sc_service::{PartialComponents, TFullBackend, TFullClient}; use sc_telemetry::{Telemetry, TelemetryWorkerHandle}; use sc_transaction_pool::TransactionPoolHandle; use sp_runtime::{generic, traits::BlakeTwo256}; -use std::sync::Arc; pub use parachains_common::{AccountId, Balance, Hash, Nonce}; @@ -42,15 +41,20 @@ pub type ParachainClient = pub type ParachainBackend = TFullBackend; -pub type ParachainBlockImport = - TParachainBlockImport>, ParachainBackend>; +pub type ParachainBlockImport = + TParachainBlockImport>; /// Assembly of PartialComponents (enough to run chain ops subcommands) -pub type ParachainService = PartialComponents< +pub type ParachainService = PartialComponents< ParachainClient, ParachainBackend, (), DefaultImportQueue, TransactionPoolHandle>, - (ParachainBlockImport, Option, Option), + ( + ParachainBlockImport, + Option, + Option, + BIExtraReturnValue, + ), >; diff --git a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs index 0b1ed5d82889..6bfd5f4f4cbd 100644 --- a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs +++ b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs @@ -202,7 +202,7 @@ macro_rules! impl_node_runtime_apis { fn dispatch_benchmark( _: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, String> { unimplemented!() } } diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs index ec5d0a439ec4..816f76117a26 100644 --- a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs @@ -18,7 +18,10 @@ use crate::{ common::{ aura::{AuraIdT, AuraRuntimeApi}, rpc::BuildParachainRpcExtensions, - spec::{BaseNodeSpec, BuildImportQueue, NodeSpec, StartConsensus}, + spec::{ + BaseNodeSpec, BuildImportQueue, ClientBlockImport, InitBlockImport, NodeSpec, + StartConsensus, + }, types::{ AccountId, Balance, Hash, Nonce, ParachainBackend, ParachainBlockImport, ParachainClient, @@ -30,11 +33,14 @@ use crate::{ use cumulus_client_collator::service::{ CollatorService, ServiceInterface as CollatorServiceInterface, }; -use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; #[docify::export(slot_based_colator_import)] use cumulus_client_consensus_aura::collators::slot_based::{ self as slot_based, Params as SlotBasedParams, }; +use cumulus_client_consensus_aura::collators::{ + lookahead::{self as aura, Params as AuraParams}, + slot_based::{SlotBasedBlockImport, SlotBasedBlockImportHandle}, +}; use cumulus_client_consensus_proposer::{Proposer, ProposerInterface}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; #[allow(deprecated)] @@ -54,6 +60,7 @@ use sc_service::{Configuration, Error, TaskManager}; use sc_telemetry::TelemetryHandle; use sc_transaction_pool::TransactionPoolHandle; use sp_api::ProvideRuntimeApi; +use sp_core::traits::SpawnNamed; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; use sp_runtime::{ @@ -90,20 +97,23 @@ where /// Build the import queue for parachain runtimes that started with relay chain consensus and /// switched to aura. -pub(crate) struct BuildRelayToAuraImportQueue( - PhantomData<(Block, RuntimeApi, AuraId)>, +pub(crate) struct BuildRelayToAuraImportQueue( + PhantomData<(Block, RuntimeApi, AuraId, BlockImport)>, ); -impl BuildImportQueue - for BuildRelayToAuraImportQueue +impl + BuildImportQueue + for BuildRelayToAuraImportQueue where RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, + BlockImport: + sc_consensus::BlockImport + Send + Sync + 'static, { fn build_import_queue( client: Arc>, - block_import: ParachainBlockImport, + block_import: ParachainBlockImport, config: &Configuration, telemetry_handle: Option, task_manager: &TaskManager, @@ -158,20 +168,20 @@ where /// Uses the lookahead collator to support async backing. /// /// Start an aura powered parachain node. Some system chains use this. -pub(crate) struct AuraNode( - pub PhantomData<(Block, RuntimeApi, AuraId, StartConsensus)>, +pub(crate) struct AuraNode( + pub PhantomData<(Block, RuntimeApi, AuraId, StartConsensus, InitBlockImport)>, ); -impl Default - for AuraNode +impl Default + for AuraNode { fn default() -> Self { Self(Default::default()) } } -impl BaseNodeSpec - for AuraNode +impl BaseNodeSpec + for AuraNode where Block: NodeBlock, RuntimeApi: ConstructNodeRuntimeApi>, @@ -179,14 +189,19 @@ where + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, AuraId: AuraIdT + Sync, + InitBlockImport: self::InitBlockImport + Send, + InitBlockImport::BlockImport: + sc_consensus::BlockImport + 'static, { type Block = Block; type RuntimeApi = RuntimeApi; - type BuildImportQueue = BuildRelayToAuraImportQueue; + type BuildImportQueue = + BuildRelayToAuraImportQueue; + type InitBlockImport = InitBlockImport; } -impl NodeSpec - for AuraNode +impl NodeSpec + for AuraNode where Block: NodeBlock, RuntimeApi: ConstructNodeRuntimeApi>, @@ -194,7 +209,15 @@ where + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, AuraId: AuraIdT + Sync, - StartConsensus: self::StartConsensus + 'static, + StartConsensus: self::StartConsensus< + Block, + RuntimeApi, + InitBlockImport::BlockImport, + InitBlockImport::BlockImportAuxiliaryData, + > + 'static, + InitBlockImport: self::InitBlockImport + Send, + InitBlockImport::BlockImport: + sc_consensus::BlockImport + 'static, { type BuildRpcExtensions = BuildParachainRpcExtensions; type StartConsensus = StartConsensus; @@ -218,6 +241,7 @@ where RuntimeApi, AuraId, StartSlotBasedAuraConsensus, + StartSlotBasedAuraConsensus, >::default()) } else { Box::new(AuraNode::< @@ -225,6 +249,7 @@ where RuntimeApi, AuraId, StartLookaheadAuraConsensus, + ClientBlockImport, >::default()) } } @@ -242,9 +267,17 @@ where AuraId: AuraIdT + Sync, { #[docify::export_content] - fn launch_slot_based_collator( + fn launch_slot_based_collator( params: SlotBasedParams< - ParachainBlockImport, + Block, + ParachainBlockImport< + Block, + SlotBasedBlockImport< + Block, + Arc>, + ParachainClient, + >, + >, CIDP, ParachainClient, ParachainBackend, @@ -252,33 +285,31 @@ where CHP, Proposer, CS, + Spawner, >, - task_manager: &TaskManager, ) where CIDP: CreateInherentDataProviders + 'static, CIDP::InherentDataProviders: Send, CHP: cumulus_client_consensus_common::ValidationCodeHashProvider + Send + 'static, Proposer: ProposerInterface + Send + Sync + 'static, CS: CollatorServiceInterface + Send + Sync + Clone + 'static, + Spawner: SpawnNamed, { - let (collation_future, block_builder_future) = - slot_based::run::::Pair, _, _, _, _, _, _, _, _>(params); - - task_manager.spawn_essential_handle().spawn( - "collation-task", - Some("parachain-block-authoring"), - collation_future, - ); - task_manager.spawn_essential_handle().spawn( - "block-builder-task", - Some("parachain-block-authoring"), - block_builder_future, - ); + slot_based::run::::Pair, _, _, _, _, _, _, _, _, _>(params); } } -impl, RuntimeApi, AuraId> StartConsensus - for StartSlotBasedAuraConsensus +impl, RuntimeApi, AuraId> + StartConsensus< + Block, + RuntimeApi, + SlotBasedBlockImport< + Block, + Arc>, + ParachainClient, + >, + SlotBasedBlockImportHandle, + > for StartSlotBasedAuraConsensus where RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, @@ -286,7 +317,14 @@ where { fn start_consensus( client: Arc>, - block_import: ParachainBlockImport, + block_import: ParachainBlockImport< + Block, + SlotBasedBlockImport< + Block, + Arc>, + ParachainClient, + >, + >, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, @@ -300,6 +338,7 @@ where announce_block: Arc>) + Send + Sync>, backend: Arc>, _node_extra_args: NodeExtraArgs, + block_import_handle: SlotBasedBlockImportHandle, ) -> Result<(), Error> { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), @@ -335,16 +374,39 @@ where authoring_duration: Duration::from_millis(2000), reinitialize: false, slot_drift: Duration::from_secs(1), + block_import_handle, + spawner: task_manager.spawn_handle(), }; // We have a separate function only to be able to use `docify::export` on this piece of // code. - Self::launch_slot_based_collator(params, task_manager); + Self::launch_slot_based_collator(params); Ok(()) } } +impl, RuntimeApi, AuraId> InitBlockImport + for StartSlotBasedAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + type BlockImport = SlotBasedBlockImport< + Block, + Arc>, + ParachainClient, + >; + type BlockImportAuxiliaryData = SlotBasedBlockImportHandle; + + fn init_block_import( + client: Arc>, + ) -> sc_service::error::Result<(Self::BlockImport, Self::BlockImportAuxiliaryData)> { + Ok(SlotBasedBlockImport::new(client.clone(), client)) + } +} + /// Wait for the Aura runtime API to appear on chain. /// This is useful for chains that started out without Aura. Components that /// are depending on Aura functionality will wait until Aura appears in the runtime. @@ -373,7 +435,8 @@ pub(crate) struct StartLookaheadAuraConsensus( PhantomData<(Block, RuntimeApi, AuraId)>, ); -impl, RuntimeApi, AuraId> StartConsensus +impl, RuntimeApi, AuraId> + StartConsensus>, ()> for StartLookaheadAuraConsensus where RuntimeApi: ConstructNodeRuntimeApi>, @@ -382,7 +445,7 @@ where { fn start_consensus( client: Arc>, - block_import: ParachainBlockImport, + block_import: ParachainBlockImport>>, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, @@ -396,6 +459,7 @@ where announce_block: Arc>) + Send + Sync>, backend: Arc>, node_extra_args: NodeExtraArgs, + _: (), ) -> Result<(), Error> { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs index e8043bd7b2aa..f33865ad45cd 100644 --- a/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs @@ -16,28 +16,37 @@ use crate::common::{ rpc::BuildRpcExtensions as BuildRpcExtensionsT, - spec::{BaseNodeSpec, BuildImportQueue, NodeSpec as NodeSpecT}, + spec::{BaseNodeSpec, BuildImportQueue, ClientBlockImport, NodeSpec as NodeSpecT}, types::{Hash, ParachainBlockImport, ParachainClient}, }; use codec::Encode; use cumulus_client_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig}; -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::{CollectCollationInfo, ParaId}; +use polkadot_primitives::UpgradeGoAhead; use sc_consensus::{DefaultImportQueue, LongestChain}; use sc_consensus_manual_seal::rpc::{ManualSeal, ManualSealApiServer}; use sc_network::NetworkBackend; -use sc_service::{build_polkadot_syncing_strategy, Configuration, PartialComponents, TaskManager}; +use sc_service::{Configuration, PartialComponents, TaskManager}; use sc_telemetry::TelemetryHandle; +use sp_api::ProvideRuntimeApi; use sp_runtime::traits::Header; use std::{marker::PhantomData, sync::Arc}; pub struct ManualSealNode(PhantomData); -impl BuildImportQueue - for ManualSealNode +impl + BuildImportQueue< + NodeSpec::Block, + NodeSpec::RuntimeApi, + Arc>, + > for ManualSealNode { fn build_import_queue( client: Arc>, - _block_import: ParachainBlockImport, + _block_import: ParachainBlockImport< + NodeSpec::Block, + Arc>, + >, config: &Configuration, _telemetry_handle: Option, task_manager: &TaskManager, @@ -54,6 +63,7 @@ impl BaseNodeSpec for ManualSealNode { type Block = NodeSpec::Block; type RuntimeApi = NodeSpec::RuntimeApi; type BuildImportQueue = Self; + type InitBlockImport = ClientBlockImport; } impl ManualSealNode { @@ -78,14 +88,14 @@ impl ManualSealNode { keystore_container, select_chain: _, transaction_pool, - other: (_, mut telemetry, _), + other: (_, mut telemetry, _, _), } = Self::new_partial(&config)?; let select_chain = LongestChain::new(backend.clone()); // Since this is a dev node, prevent it from connecting to peers. config.network.default_peers_set.in_peers = 0; config.network.default_peers_set.out_peers = 0; - let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, Net>::new( + let net_config = sc_network::config::FullNetworkConfiguration::<_, _, Net>::new( &config.network, config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()), ); @@ -93,17 +103,7 @@ impl ManualSealNode { config.prometheus_config.as_ref().map(|cfg| &cfg.registry), ); - let syncing_strategy = build_polkadot_syncing_strategy( - config.protocol_id(), - config.chain_spec.fork_id(), - &mut net_config, - None, - client.clone(), - &task_manager.spawn_handle(), - config.prometheus_config.as_ref().map(|config| &config.registry), - )?; - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -112,7 +112,7 @@ impl ManualSealNode { import_queue, net_config, block_announce_validator_builder: None, - syncing_strategy, + warp_sync_config: None, block_relay: None, metrics, })?; @@ -157,6 +157,18 @@ impl ManualSealNode { .header(block) .expect("Header lookup should succeed") .expect("Header passed in as parent should be present in backend."); + + let should_send_go_ahead = match client_for_cidp + .runtime_api() + .collect_collation_info(block, ¤t_para_head) + { + Ok(info) => info.new_validation_code.is_some(), + Err(e) => { + log::error!("Failed to collect collation info: {:?}", e); + false + }, + }; + let current_para_block_head = Some(polkadot_primitives::HeadData(current_para_head.encode())); let client_for_xcm = client_for_cidp.clone(); @@ -179,6 +191,12 @@ impl ManualSealNode { raw_downward_messages: vec![], raw_horizontal_messages: vec![], additional_key_values: None, + upgrade_go_ahead: should_send_go_ahead.then(|| { + log::info!( + "Detected pending validation code, sending go-ahead signal." + ); + UpgradeGoAhead::GoAhead + }), }; Ok(( // This is intentional, as the runtime that we expect to run against this @@ -229,7 +247,6 @@ impl ManualSealNode { telemetry: telemetry.as_mut(), })?; - start_network.start_network(); Ok(task_manager) } } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 5520126d0742..9130f60ceb38 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -6,6 +6,8 @@ edition.workspace = true build = "build.rs" description = "Runs a polkadot parachain node" license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -22,29 +24,29 @@ serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } # Local -polkadot-omni-node-lib = { features = ["rococo-native", "westend-native"], workspace = true } -rococo-parachain-runtime = { workspace = true } -glutton-westend-runtime = { workspace = true } asset-hub-rococo-runtime = { workspace = true, default-features = true } asset-hub-westend-runtime = { workspace = true } +bridge-hub-rococo-runtime = { workspace = true, default-features = true } +bridge-hub-westend-runtime = { workspace = true, default-features = true } collectives-westend-runtime = { workspace = true } contracts-rococo-runtime = { workspace = true } -bridge-hub-rococo-runtime = { workspace = true, default-features = true } coretime-rococo-runtime = { workspace = true } coretime-westend-runtime = { workspace = true } -bridge-hub-westend-runtime = { workspace = true, default-features = true } +glutton-westend-runtime = { workspace = true } +parachains-common = { workspace = true, default-features = true } penpal-runtime = { workspace = true } people-rococo-runtime = { workspace = true } people-westend-runtime = { workspace = true } -parachains-common = { workspace = true, default-features = true } +polkadot-omni-node-lib = { features = ["rococo-native", "westend-native"], workspace = true } +rococo-parachain-runtime = { workspace = true } # Substrate -sp-core = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } -sc-chain-spec = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } # Polkadot xcm = { workspace = true, default-features = true } @@ -76,6 +78,7 @@ runtime-benchmarks = [ "people-rococo-runtime/runtime-benchmarks", "people-westend-runtime/runtime-benchmarks", "rococo-parachain-runtime/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "polkadot-omni-node-lib/try-runtime", diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 185b2d40833f..715ce3e1a03e 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Core primitives for Aura in Cumulus" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 533d368d3b00..307860897aec 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Cumulus related core primitive types and traits" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -41,4 +43,5 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index dfb574ef3301..f88e663db19e 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -333,10 +333,6 @@ pub mod rpsr_digest { } } -/// The default claim queue offset to be used if it's not configured/accessible in the parachain -/// runtime -pub const DEFAULT_CLAIM_QUEUE_OFFSET: u8 = 0; - /// Information about a collation. /// /// This was used in version 1 of the [`CollectCollationInfo`] runtime api. diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index a4271d3fd9cc..2ff990b8d514 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Inherent that needs to be present in every parachain block. Contains messages and a relay chain storage-proof." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/primitives/proof-size-hostfunction/Cargo.toml b/cumulus/primitives/proof-size-hostfunction/Cargo.toml index e61c865d05fb..b3b300d66ef3 100644 --- a/cumulus/primitives/proof-size-hostfunction/Cargo.toml +++ b/cumulus/primitives/proof-size-hostfunction/Cargo.toml @@ -5,19 +5,21 @@ authors.workspace = true edition.workspace = true description = "Hostfunction exposing storage proof size to the runtime." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -sp-runtime-interface = { workspace = true } sp-externalities = { workspace = true } +sp-runtime-interface = { workspace = true } sp-trie = { workspace = true } [dev-dependencies] -sp-state-machine = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index e1ae6743335a..4bcbabc1f16c 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Utilities to reclaim storage weight." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -25,9 +27,9 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true } docify = { workspace = true } [dev-dependencies] +cumulus-test-runtime = { workspace = true } sp-io = { workspace = true } sp-trie = { workspace = true } -cumulus-test-runtime = { workspace = true } [features] default = ["std"] diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs index 5471640695ca..5cbe662e2700 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -198,7 +198,7 @@ where let block_weight_proof_size = current.total().proof_size(); let missing_from_node = node_side_pov_size.saturating_sub(block_weight_proof_size); if missing_from_node > 0 { - log::warn!( + log::debug!( target: LOG_TARGET, "Node-side PoV size higher than runtime proof size weight. node-side: {node_side_pov_size} extrinsic_len: {extrinsic_len} runtime: {block_weight_proof_size}, missing: {missing_from_node}. Setting to node-side proof size." ); diff --git a/cumulus/primitives/storage-weight-reclaim/src/tests.rs b/cumulus/primitives/storage-weight-reclaim/src/tests.rs index c5552b0f0a33..ab83762cc0db 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/tests.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/tests.rs @@ -90,7 +90,7 @@ fn basic_refund() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(0)); @@ -130,7 +130,7 @@ fn underestimating_refund() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(0)); @@ -168,7 +168,7 @@ fn sets_to_node_storage_proof_if_higher() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(1000)); @@ -211,7 +211,7 @@ fn sets_to_node_storage_proof_if_higher() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(175)); @@ -256,7 +256,7 @@ fn does_nothing_without_extension() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, None); @@ -288,7 +288,7 @@ fn negative_refund_is_added_to_weight() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(100)); @@ -321,7 +321,7 @@ fn test_zero_proof_size() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(0)); @@ -354,7 +354,7 @@ fn test_larger_pre_dispatch_proof_size() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(300)); @@ -394,7 +394,7 @@ fn test_incorporates_check_weight_unspent_weight() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(100)); @@ -434,7 +434,7 @@ fn test_incorporates_check_weight_unspent_weight_on_negative() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(100)); @@ -478,7 +478,7 @@ fn test_nothing_relcaimed() { assert_eq!(get_storage_weight().total().proof_size(), 250); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); // Should return `setup_test_externalities` proof recorder value: 100. assert_eq!(pre, Some(0)); @@ -525,7 +525,7 @@ fn test_incorporates_check_weight_unspent_weight_reverse_order() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(100)); @@ -567,7 +567,7 @@ fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) .unwrap(); assert_eq!(pre, Some(100)); diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index cb328e2f2cc6..70cb3e607b98 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true description = "Provides timestamp related functionality for parachains." license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 2ca8b82001d5..84039b9345b2 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Helper datatypes for Cumulus" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -15,14 +17,14 @@ log = { workspace = true } # Substrate frame-support = { workspace = true } -sp-runtime = { workspace = true } pallet-asset-conversion = { workspace = true } +sp-runtime = { workspace = true } # Polkadot polkadot-runtime-common = { workspace = true } xcm = { workspace = true } -xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-executor = { workspace = true } # Cumulus cumulus-primitives-core = { workspace = true } @@ -50,4 +52,5 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 33023816c718..2c72ca98f35a 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -12,40 +12,40 @@ workspace = true codec = { features = ["derive"], workspace = true } # Substrate -sc-service = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-consensus-aura = { workspace = true, default-features = true } -sc-block-builder = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-executor-common = { workspace = true, default-features = true } -substrate-test-client = { workspace = true } -sp-application-crypto = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sp-consensus-aura = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } -pallet-transaction-payment = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } +substrate-test-client = { workspace = true } # Polkadot -polkadot-primitives = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } # Cumulus -cumulus-test-runtime = { workspace = true } -cumulus-test-service = { workspace = true } -cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } -cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } +cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } +cumulus-test-runtime = { workspace = true } +cumulus-test-service = { workspace = true } [features] runtime-benchmarks = [ diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index 863a8fa93f6f..26cf02b3dea9 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -167,7 +167,7 @@ pub fn generate_extrinsic_with_pair( /// Generate an extrinsic from the provided function call, origin and [`Client`]. pub fn generate_extrinsic( client: &Client, - origin: sp_keyring::AccountKeyring, + origin: sp_keyring::Sr25519Keyring, function: impl Into, ) -> UncheckedExtrinsic { generate_extrinsic_with_pair(client, origin.into(), function, None) @@ -176,8 +176,8 @@ pub fn generate_extrinsic( /// Transfer some token from one account to another using a provided test [`Client`]. pub fn transfer( client: &Client, - origin: sp_keyring::AccountKeyring, - dest: sp_keyring::AccountKeyring, + origin: sp_keyring::Sr25519Keyring, + dest: sp_keyring::Sr25519Keyring, value: Balance, ) -> UncheckedExtrinsic { let function = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index e266b5807081..c1efa141a45d 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" description = "Mocked relay state proof builder for testing Cumulus." +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 8117e6e69709..150838e5e96e 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -18,37 +18,37 @@ frame-executive = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } frame-system-rpc-runtime-api = { workspace = true } +pallet-aura = { workspace = true } +pallet-authorship = { workspace = true } pallet-balances = { workspace = true } +pallet-glutton = { workspace = true } pallet-message-queue = { workspace = true } +pallet-session = { workspace = true } pallet-sudo = { workspace = true } -pallet-aura = { workspace = true } -pallet-authorship = { workspace = true } pallet-timestamp = { workspace = true } -pallet-glutton = { workspace = true } pallet-transaction-payment = { workspace = true } -pallet-session = { workspace = true } sp-api = { workspace = true } sp-block-builder = { workspace = true } +sp-consensus-aura = { workspace = true } sp-core = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } -sp-consensus-aura = { workspace = true } sp-transaction-pool = { workspace = true } sp-version = { workspace = true } -sp-keyring = { workspace = true } # Cumulus +cumulus-pallet-aura-ext = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } -parachain-info = { workspace = true } cumulus-primitives-aura = { workspace = true } -pallet-collator-selection = { workspace = true } -cumulus-pallet-aura-ext = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } +pallet-collator-selection = { workspace = true } +parachain-info = { workspace = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } @@ -96,3 +96,4 @@ std = [ ] increment-spec-version = [] elastic-scaling = [] +experimental-ump-signals = ["cumulus-pallet-parachain-system/experimental-ump-signals"] diff --git a/cumulus/test/runtime/build.rs b/cumulus/test/runtime/build.rs index 7a7fe8ffaa82..43e60c1074a0 100644 --- a/cumulus/test/runtime/build.rs +++ b/cumulus/test/runtime/build.rs @@ -29,6 +29,14 @@ fn main() { .with_current_project() .enable_feature("elastic-scaling") .import_memory() + .set_file_name("wasm_binary_elastic_scaling_mvp.rs") + .build(); + + WasmBuilder::new() + .with_current_project() + .enable_feature("elastic-scaling") + .enable_feature("experimental-ump-signals") + .import_memory() .set_file_name("wasm_binary_elastic_scaling.rs") .build(); } diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index 6cf56ef5363f..84ba71ae795f 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -58,9 +58,9 @@ pub fn preset_names() -> Vec { /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) | - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => + let patch = match id.as_ref() { + sp_genesis_builder::DEV_RUNTIME_PRESET | + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => testnet_genesis_with_default_endowed(100.into()), _ => return None, }; diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 01c1571f343f..4abc10276af1 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -27,6 +27,11 @@ pub mod wasm_spec_version_incremented { include!(concat!(env!("OUT_DIR"), "/wasm_binary_spec_version_incremented.rs")); } +pub mod elastic_scaling_mvp { + #[cfg(feature = "std")] + include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling_mvp.rs")); +} + pub mod elastic_scaling { #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling.rs")); @@ -45,7 +50,7 @@ use sp_core::{ConstBool, ConstU32, ConstU64, OpaqueMetadata}; use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, MultiAddress, MultiSignature, @@ -126,8 +131,8 @@ const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; #[cfg(not(feature = "increment-spec-version"))] #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("cumulus-test-parachain"), - impl_name: create_runtime_str!("cumulus-test-parachain"), + spec_name: alloc::borrow::Cow::Borrowed("cumulus-test-parachain"), + impl_name: alloc::borrow::Cow::Borrowed("cumulus-test-parachain"), authoring_version: 1, // Read the note above. spec_version: 1, @@ -140,8 +145,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { #[cfg(feature = "increment-spec-version")] #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("cumulus-test-parachain"), - impl_name: create_runtime_str!("cumulus-test-parachain"), + spec_name: alloc::borrow::Cow::Borrowed("cumulus-test-parachain"), + impl_name: alloc::borrow::Cow::Borrowed("cumulus-test-parachain"), authoring_version: 1, // Read the note above. spec_version: 2, diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 86a8c48bb54f..b3d92444c7d1 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -22,80 +22,80 @@ prometheus = { workspace = true } rand = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +tempfile = { workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } tracing = { workspace = true, default-features = true } url = { workspace = true } -tempfile = { workspace = true } # Substrate frame-system = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { workspace = true, default-features = true } pallet-transaction-payment = { workspace = true, default-features = true } sc-basic-authorship = { workspace = true, default-features = true } +sc-block-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } +sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-consensus-aura = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +sc-executor-wasmtime = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } -sc-telemetry = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } sp-arithmetic = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } -sp-genesis-builder = { workspace = true, default-features = true } sp-runtime = { workspace = true } sp-state-machine = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } -sp-consensus-aura = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } substrate-test-client = { workspace = true } -sc-cli = { workspace = true, default-features = true } -sc-block-builder = { workspace = true, default-features = true } -sc-executor-wasmtime = { workspace = true, default-features = true } -sc-executor-common = { workspace = true, default-features = true } # Polkadot -polkadot-primitives = { workspace = true, default-features = true } -polkadot-service = { workspace = true, default-features = true } -polkadot-test-service = { workspace = true } polkadot-cli = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-service = { workspace = true, default-features = true } +polkadot-test-service = { workspace = true } # Cumulus cumulus-client-cli = { workspace = true, default-features = true } -parachains-common = { workspace = true, default-features = true } +cumulus-client-collator = { workspace = true, default-features = true } +cumulus-client-consensus-aura = { workspace = true, default-features = true } cumulus-client-consensus-common = { workspace = true, default-features = true } cumulus-client-consensus-proposer = { workspace = true, default-features = true } -cumulus-client-consensus-aura = { workspace = true, default-features = true } cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } cumulus-client-parachain-inherent = { workspace = true, default-features = true } +cumulus-client-pov-recovery = { workspace = true, default-features = true } cumulus-client-service = { workspace = true, default-features = true } -cumulus-client-collator = { workspace = true, default-features = true } +cumulus-pallet-parachain-system = { workspace = true } cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } cumulus-relay-chain-inprocess-interface = { workspace = true, default-features = true } cumulus-relay-chain-interface = { workspace = true, default-features = true } -cumulus-test-runtime = { workspace = true } cumulus-relay-chain-minimal-node = { workspace = true, default-features = true } -cumulus-client-pov-recovery = { workspace = true, default-features = true } cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } -cumulus-pallet-parachain-system = { workspace = true } -cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } +cumulus-test-runtime = { workspace = true } pallet-timestamp = { workspace = true, default-features = true } +parachains-common = { workspace = true, default-features = true } [dev-dependencies] +cumulus-test-client = { workspace = true } futures = { workspace = true } portpicker = { workspace = true } sp-authority-discovery = { workspace = true, default-features = true } -cumulus-test-client = { workspace = true } # Polkadot dependencies polkadot-test-service = { workspace = true } diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 3d4e4dca5f8d..5ebcc14592d7 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -116,3 +116,13 @@ pub fn get_elastic_scaling_chain_spec(id: Option) -> ChainSpec { .expect("WASM binary was not built, please build it!"), ) } + +/// Get the chain spec for a specific parachain ID. +pub fn get_elastic_scaling_mvp_chain_spec(id: Option) -> ChainSpec { + get_chain_spec_with_extra_endowed( + id, + Default::default(), + cumulus_test_runtime::elastic_scaling_mvp::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index 220b0449f339..e019089e70fe 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -262,10 +262,16 @@ impl SubstrateCli for TestCollatorCli { tracing::info!("Using default test service chain spec."); Box::new(cumulus_test_service::get_chain_spec(Some(ParaId::from(2000)))) as Box<_> }, + "elastic-scaling-mvp" => { + tracing::info!("Using elastic-scaling mvp chain spec."); + Box::new(cumulus_test_service::get_elastic_scaling_mvp_chain_spec(Some( + ParaId::from(2100), + ))) as Box<_> + }, "elastic-scaling" => { tracing::info!("Using elastic-scaling chain spec."); Box::new(cumulus_test_service::get_elastic_scaling_chain_spec(Some(ParaId::from( - 2100, + 2200, )))) as Box<_> }, path => { diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index fe3cbfbbb498..2c13d20333a7 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -27,7 +27,10 @@ use cumulus_client_collator::service::CollatorService; use cumulus_client_consensus_aura::{ collators::{ lookahead::{self as aura, Params as AuraParams}, - slot_based::{self as slot_based, Params as SlotBasedParams}, + slot_based::{ + self as slot_based, Params as SlotBasedParams, SlotBasedBlockImport, + SlotBasedBlockImportHandle, + }, }, ImportQueueParams, }; @@ -131,7 +134,8 @@ pub type Client = TFullClient; /// The block-import type being used by the test service. -pub type ParachainBlockImport = TParachainBlockImport, Backend>; +pub type ParachainBlockImport = + TParachainBlockImport, Client>, Backend>; /// Transaction pool type used by the test service pub type TransactionPool = Arc>; @@ -184,7 +188,7 @@ pub type Service = PartialComponents< (), sc_consensus::import_queue::BasicQueue, sc_transaction_pool::TransactionPoolHandle, - ParachainBlockImport, + (ParachainBlockImport, SlotBasedBlockImportHandle), >; /// Starts a `ServiceBuilder` for a full service. @@ -217,7 +221,9 @@ pub fn new_partial( )?; let client = Arc::new(client); - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + let (block_import, slot_based_handle) = + SlotBasedBlockImport::new(client.clone(), client.clone()); + let block_import = ParachainBlockImport::new(block_import, backend.clone()); let transaction_pool = Arc::from( sc_transaction_pool::Builder::new( @@ -260,7 +266,7 @@ pub fn new_partial( task_manager, transaction_pool, select_chain: (), - other: block_import, + other: (block_import, slot_based_handle), }; Ok(params) @@ -349,7 +355,8 @@ where let client = params.client.clone(); let backend = params.backend.clone(); - let block_import = params.other; + let block_import = params.other.0; + let slot_based_handle = params.other.1; let relay_chain_interface = build_relay_chain_interface( relay_chain_config, parachain_config.prometheus_registry(), @@ -367,7 +374,7 @@ where prometheus_registry.clone(), ); - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = build_network(BuildNetworkParams { parachain_config: ¶chain_config, net_config, @@ -497,20 +504,11 @@ where authoring_duration: Duration::from_millis(2000), reinitialize: false, slot_drift: Duration::from_secs(1), + block_import_handle: slot_based_handle, + spawner: task_manager.spawn_handle(), }; - let (collation_future, block_builder_future) = - slot_based::run::(params); - task_manager.spawn_essential_handle().spawn( - "collation-task", - None, - collation_future, - ); - task_manager.spawn_essential_handle().spawn( - "block-builder-task", - None, - block_builder_future, - ); + slot_based::run::(params); } else { tracing::info!(target: LOG_TARGET, "Starting block authoring with lookahead collator."); let params = AuraParams { @@ -542,8 +540,6 @@ where } } - start_network.start_network(); - Ok((task_manager, client, network, rpc_handlers, transaction_pool, backend)) } diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 8598481fae76..ae8cb79bb55e 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -5,41 +5,43 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +array-bytes = { workspace = true } codec = { workspace = true, default-features = true } -paste = { workspace = true, default-features = true } -log = { workspace = true } impl-trait-for-tuples = { workspace = true } -array-bytes = { workspace = true } +log = { workspace = true } +paste = { workspace = true, default-features = true } # Substrate frame-support = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } +sp-arithmetic = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-arithmetic = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } # Cumulus -cumulus-primitives-core = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } cumulus-pallet-parachain-system = { workspace = true, default-features = true } +cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } cumulus-test-relay-sproof-builder = { workspace = true, default-features = true } parachains-common = { workspace = true, default-features = true } # Polkadot -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index b91246a7bda2..ff14b747973c 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -36,7 +36,10 @@ pub use core::{cell::RefCell, fmt::Debug}; pub use cumulus_primitives_core::AggregateMessageOrigin as CumulusAggregateMessageOrigin; pub use frame_support::{ assert_ok, - sp_runtime::{traits::Header as HeaderT, DispatchResult}, + sp_runtime::{ + traits::{Dispatchable, Header as HeaderT}, + DispatchResult, + }, traits::{ EnqueueMessage, ExecuteOverweightError, Get, Hooks, OnInitialize, OriginTrait, ProcessMessage, ProcessMessageError, ServiceQueues, @@ -221,7 +224,7 @@ pub trait Network { pub trait Chain: TestExt { type Network: Network; type Runtime: SystemConfig; - type RuntimeCall; + type RuntimeCall: Clone + Dispatchable; type RuntimeOrigin; type RuntimeEvent; type System; @@ -1221,7 +1224,7 @@ macro_rules! __impl_check_assertion { Args: Clone, { fn check_assertion(test: $crate::Test) { - use $crate::TestExt; + use $crate::{Dispatchable, TestExt}; let chain_name = std::any::type_name::<$chain<$network>>(); @@ -1229,6 +1232,15 @@ macro_rules! __impl_check_assertion { if let Some(dispatchable) = test.hops_dispatchable.get(chain_name) { $crate::assert_ok!(dispatchable(test.clone())); } + if let Some(call) = test.hops_calls.get(chain_name) { + $crate::assert_ok!( + match call.clone().dispatch(test.signed_origin.clone()) { + // We get rid of `post_info`. + Ok(_) => Ok(()), + Err(error_with_post_info) => Err(error_with_post_info.error), + } + ); + } if let Some(assertion) = test.hops_assertion.get(chain_name) { assertion(test); } @@ -1530,11 +1542,12 @@ where pub root_origin: Origin::RuntimeOrigin, pub hops_assertion: HashMap, pub hops_dispatchable: HashMap DispatchResult>, + pub hops_calls: HashMap, pub args: Args, _marker: PhantomData<(Destination, Hops)>, } -/// `Test` implementation +/// `Test` implementation. impl Test where Args: Clone, @@ -1544,7 +1557,7 @@ where Destination::RuntimeOrigin: OriginTrait> + Clone, Hops: Clone + CheckAssertion, { - /// Creates a new `Test` instance + /// Creates a new `Test` instance. pub fn new(test_args: TestContext) -> Self { Test { sender: TestAccount { @@ -1559,6 +1572,7 @@ where root_origin: ::RuntimeOrigin::root(), hops_assertion: Default::default(), hops_dispatchable: Default::default(), + hops_calls: Default::default(), args: test_args.args, _marker: Default::default(), } @@ -1573,6 +1587,11 @@ where let chain_name = std::any::type_name::(); self.hops_dispatchable.insert(chain_name.to_string(), dispatchable); } + /// Stores a call in a particular Chain, this will later be dispatched. + pub fn set_call(&mut self, call: Origin::RuntimeCall) { + let chain_name = std::any::type_name::(); + self.hops_calls.insert(chain_name.to_string(), call); + } /// Executes all dispatchables and assertions in order from `Origin` to `Destination` pub fn assert(&mut self) { Origin::check_assertion(self.clone()); diff --git a/docs/contributor/container.md b/docs/contributor/container.md index ec51b8b9d7cc..e387f568d7b5 100644 --- a/docs/contributor/container.md +++ b/docs/contributor/container.md @@ -24,7 +24,7 @@ The command below allows building a Linux binary without having to even install docker run --rm -it \ -w /polkadot-sdk \ -v $(pwd):/polkadot-sdk \ - docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408 \ + docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-11-19-v202411281558 \ cargo build --release --locked -p polkadot-parachain-bin --bin polkadot-parachain sudo chown -R $(id -u):$(id -g) target/ ``` diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 0c39367eeed3..a856e94f42b5 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -16,112 +16,112 @@ workspace = true [dependencies] # Needed for all FRAME-based code codec = { workspace = true } -scale-info = { workspace = true } frame = { features = [ "experimental", "runtime", ], workspace = true, default-features = true } -pallet-examples = { workspace = true } pallet-contracts = { workspace = true } pallet-default-config-example = { workspace = true, default-features = true } pallet-example-offchain-worker = { workspace = true, default-features = true } +pallet-examples = { workspace = true } +scale-info = { workspace = true } # How we build docs in rust-docs -simple-mermaid = "0.1.1" docify = { workspace = true } serde_json = { workspace = true } +simple-mermaid = "0.1.1" # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. -polkadot-sdk = { features = ["runtime-full"], workspace = true, default-features = true } -node-cli = { workspace = true } -kitchensink-runtime = { workspace = true } chain-spec-builder = { workspace = true, default-features = true } -subkey = { workspace = true, default-features = true } -frame-system = { workspace = true } -frame-support = { workspace = true } -frame-executive = { workspace = true } frame-benchmarking = { workspace = true } -pallet-example-authorization-tx-extension = { workspace = true, default-features = true } -pallet-example-single-block-migrations = { workspace = true, default-features = true } +frame-executive = { workspace = true } frame-metadata-hash-extension = { workspace = true, default-features = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +kitchensink-runtime = { workspace = true } log = { workspace = true, default-features = true } +node-cli = { workspace = true } +pallet-example-authorization-tx-extension = { workspace = true, default-features = true } +pallet-example-single-block-migrations = { workspace = true, default-features = true } +polkadot-sdk = { features = ["runtime-full"], workspace = true, default-features = true } +subkey = { workspace = true, default-features = true } # Substrate Client -sc-network = { workspace = true, default-features = true } -sc-rpc-api = { workspace = true, default-features = true } -sc-rpc = { workspace = true, default-features = true } -sc-client-db = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } +sc-client-db = { workspace = true, default-features = true } sc-consensus-aura = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-manual-seal = { workspace = true, default-features = true } sc-consensus-pow = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } -sc-chain-spec = { workspace = true, default-features = true } substrate-wasm-builder = { workspace = true, default-features = true } # Cumulus +cumulus-client-service = { workspace = true, default-features = true } cumulus-pallet-aura-ext = { workspace = true, default-features = true } cumulus-pallet-parachain-system = { workspace = true, default-features = true } -parachain-info = { workspace = true, default-features = true } cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } -cumulus-client-service = { workspace = true, default-features = true } cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = true } +parachain-info = { workspace = true, default-features = true } # Omni Node polkadot-omni-node-lib = { workspace = true, default-features = true } # Pallets and FRAME internals -pallet-aura = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-preimage = { workspace = true, default-features = true } -pallet-transaction-payment = { workspace = true, default-features = true } -pallet-asset-tx-payment = { workspace = true, default-features = true } -pallet-skip-feeless-payment = { workspace = true, default-features = true } pallet-asset-conversion-tx-payment = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } -pallet-multisig = { workspace = true, default-features = true } -pallet-proxy = { workspace = true, default-features = true } +pallet-asset-tx-payment = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +pallet-aura = { workspace = true, default-features = true } pallet-authorship = { workspace = true, default-features = true } +pallet-babe = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-broker = { workspace = true, default-features = true } pallet-collective = { workspace = true, default-features = true } pallet-democracy = { workspace = true, default-features = true } -pallet-uniques = { workspace = true, default-features = true } +pallet-grandpa = { workspace = true, default-features = true } +pallet-multisig = { workspace = true, default-features = true } pallet-nfts = { workspace = true, default-features = true } -pallet-scheduler = { workspace = true, default-features = true } +pallet-preimage = { workspace = true, default-features = true } +pallet-proxy = { workspace = true, default-features = true } pallet-referenda = { workspace = true, default-features = true } -pallet-broker = { workspace = true, default-features = true } -pallet-babe = { workspace = true, default-features = true } -pallet-grandpa = { workspace = true, default-features = true } +pallet-scheduler = { workspace = true, default-features = true } +pallet-skip-feeless-payment = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-uniques = { workspace = true, default-features = true } +pallet-utility = { workspace = true, default-features = true } # Primitives -sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } -sp-runtime-interface = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-arithmetic = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-offchain = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-runtime-interface = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } sp-weights = { workspace = true, default-features = true } # XCM +pallet-xcm = { workspace = true } xcm = { workspace = true, default-features = true } xcm-builder = { workspace = true } xcm-docs = { workspace = true } xcm-executor = { workspace = true } xcm-simulator = { workspace = true } -pallet-xcm = { workspace = true } # runtime guides @@ -129,13 +129,14 @@ chain-spec-guide-runtime = { workspace = true, default-features = true } # Templates minimal-template-runtime = { workspace = true, default-features = true } -solochain-template-runtime = { workspace = true, default-features = true } parachain-template-runtime = { workspace = true, default-features = true } +solochain-template-runtime = { workspace = true, default-features = true } # local packages -first-runtime = { workspace = true, default-features = true } first-pallet = { workspace = true, default-features = true } +first-runtime = { workspace = true, default-features = true } [dev-dependencies] assert_cmd = "2.0.14" +cmd_lib = { workspace = true } rand = "0.8" diff --git a/docs/sdk/packages/guides/first-pallet/Cargo.toml b/docs/sdk/packages/guides/first-pallet/Cargo.toml index dad5b8863494..a1411580119d 100644 --- a/docs/sdk/packages/guides/first-pallet/Cargo.toml +++ b/docs/sdk/packages/guides/first-pallet/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { workspace = true } -frame = { workspace = true, features = ["experimental", "runtime"] } docify = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } +scale-info = { workspace = true } [features] default = ["std"] diff --git a/docs/sdk/packages/guides/first-runtime/src/lib.rs b/docs/sdk/packages/guides/first-runtime/src/lib.rs index 92d51962b6fe..2ab060c8c43f 100644 --- a/docs/sdk/packages/guides/first-runtime/src/lib.rs +++ b/docs/sdk/packages/guides/first-runtime/src/lib.rs @@ -31,8 +31,8 @@ use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, RuntimeDispatchInfo #[docify::export] #[runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("first-runtime"), - impl_name: create_runtime_str!("first-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("first-runtime"), + impl_name: alloc::borrow::Cow::Borrowed("first-runtime"), authoring_version: 1, spec_version: 0, impl_version: 1, @@ -130,30 +130,28 @@ pub mod genesis_config_presets { interface::{Balance, MinimumBalance}, BalancesConfig, RuntimeGenesisConfig, SudoConfig, }; + use frame::deps::frame_support::build_struct_json_patch; use serde_json::Value; /// Returns a development genesis config preset. #[docify::export] pub fn development_config_genesis() -> Value { let endowment = >::get().max(1) * 1000; - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { - balances: AccountKeyring::iter() + balances: Sr25519Keyring::iter() .map(|a| (a.to_account_id(), endowment)) .collect::>(), }, - sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.to_account_id()) }, + }) } /// Get the set of the available genesis config presets. #[docify::export] pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(DEV_RUNTIME_PRESET) => development_config_genesis(), + let patch = match id.as_ref() { + DEV_RUNTIME_PRESET => development_config_genesis(), _ => return None, }; Some( diff --git a/docs/sdk/src/guides/your_first_node.rs b/docs/sdk/src/guides/your_first_node.rs index da37c11c206f..3c782e4793ba 100644 --- a/docs/sdk/src/guides/your_first_node.rs +++ b/docs/sdk/src/guides/your_first_node.rs @@ -103,6 +103,7 @@ #[cfg(test)] mod tests { use assert_cmd::Command; + use cmd_lib::*; use rand::Rng; use sc_chain_spec::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET}; use sp_genesis_builder::PresetId; @@ -173,13 +174,10 @@ mod tests { println!("Building polkadot-sdk-docs-first-runtime..."); #[docify::export_content] fn build_runtime() { - Command::new("cargo") - .arg("build") - .arg("--release") - .arg("-p") - .arg(FIRST_RUNTIME) - .assert() - .success(); + run_cmd!( + cargo build --release -p $FIRST_RUNTIME + ) + .expect("Failed to run command"); } build_runtime() } @@ -274,14 +272,10 @@ mod tests { let chain_spec_builder = find_release_binary(&CHAIN_SPEC_BUILDER).unwrap(); let runtime_path = find_wasm(PARA_RUNTIME).unwrap(); let output = "/tmp/demo-chain-spec.json"; - Command::new(chain_spec_builder) - .args(["-c", output]) - .arg("create") - .args(["--para-id", "1000", "--relay-chain", "dontcare"]) - .args(["-r", runtime_path.to_str().unwrap()]) - .args(["named-preset", "development"]) - .assert() - .success(); + let runtime_str = runtime_path.to_str().unwrap(); + run_cmd!( + $chain_spec_builder -c $output create --para-id 1000 --relay-chain dontcare -r $runtime_str named-preset development + ).expect("Failed to run command"); std::fs::remove_file(output).unwrap(); } build_para_chain_spec_works(); diff --git a/docs/sdk/src/reference_docs/chain_spec_genesis.rs b/docs/sdk/src/reference_docs/chain_spec_genesis.rs index b7a0a648d0cf..d5cc482711ad 100644 --- a/docs/sdk/src/reference_docs/chain_spec_genesis.rs +++ b/docs/sdk/src/reference_docs/chain_spec_genesis.rs @@ -174,13 +174,13 @@ //! ``` //! Here are some examples in the form of rust tests: //! ## Listing available preset names: -#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", list_presets)] +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", cmd_list_presets)] //! ## Displaying preset with given name -#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", get_preset)] +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", cmd_get_preset)] //! ## Building a solo chain-spec (the default) using given preset -#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", generate_chain_spec)] +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", cmd_generate_chain_spec)] //! ## Building a parachain chain-spec using given preset -#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", generate_para_chain_spec)] +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", cmd_generate_para_chain_spec)] //! //! [`RuntimeGenesisConfig`]: //! chain_spec_guide_runtime::runtime::RuntimeGenesisConfig diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml b/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml index 07c0342f5fbe..925cb7bb2e65 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml @@ -10,8 +10,8 @@ edition.workspace = true publish = false [dependencies] -docify = { workspace = true } codec = { workspace = true } +docify = { workspace = true } frame-support = { workspace = true } scale-info = { workspace = true } serde = { workspace = true } @@ -31,17 +31,18 @@ pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } # genesis builder that allows us to interact with runtime genesis config -sp-genesis-builder = { workspace = true } -sp-runtime = { features = ["serde"], workspace = true } +sp-application-crypto = { features = ["serde"], workspace = true } sp-core = { workspace = true } +sp-genesis-builder = { workspace = true } sp-keyring = { workspace = true } -sp-application-crypto = { features = ["serde"], workspace = true } +sp-runtime = { features = ["serde"], workspace = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dev-dependencies] chain-spec-builder = { workspace = true, default-features = true } +cmd_lib = { workspace = true } sc-chain-spec = { workspace = true, default-features = true } [features] diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs index c1316b2f8734..5432d37e907d 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/presets.rs @@ -25,7 +25,7 @@ use alloc::vec; use frame_support::build_struct_json_patch; use serde_json::{json, to_string, Value}; use sp_application_crypto::Ss58Codec; -use sp_keyring::AccountKeyring; +use sp_keyring::Sr25519Keyring; /// A demo preset with strings only. pub const PRESET_1: &str = "preset_1"; @@ -70,7 +70,7 @@ fn preset_2() -> Value { some_integer: 200, some_enum: FooEnum::Data2(SomeFooData2 { values: vec![0x0c, 0x10] }) }, - bar: BarConfig { initial_account: Some(AccountKeyring::Ferdie.public().into()) }, + bar: BarConfig { initial_account: Some(Sr25519Keyring::Ferdie.public().into()) }, }) } @@ -80,7 +80,7 @@ fn preset_2() -> Value { fn preset_3() -> Value { json!({ "bar": { - "initialAccount": AccountKeyring::Alice.public().to_ss58check(), + "initialAccount": Sr25519Keyring::Alice.public().to_ss58check(), }, "foo": { "someEnum": FooEnum::Data1( @@ -121,12 +121,12 @@ fn preset_invalid() -> Value { /// If no preset with given `id` exits `None` is returned. #[docify::export] pub fn get_builtin_preset(id: &sp_genesis_builder::PresetId) -> Option> { - let preset = match id.try_into() { - Ok(PRESET_1) => preset_1(), - Ok(PRESET_2) => preset_2(), - Ok(PRESET_3) => preset_3(), - Ok(PRESET_4) => preset_4(), - Ok(PRESET_INVALID) => preset_invalid(), + let preset = match id.as_ref() { + PRESET_1 => preset_1(), + PRESET_2 => preset_2(), + PRESET_3 => preset_3(), + PRESET_4 => preset_4(), + PRESET_INVALID => preset_invalid(), _ => return None, }; diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs index 5be3a59dc7bb..282fc1ff489c 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs @@ -39,8 +39,8 @@ use sp_genesis_builder::PresetId; /// The runtime version. #[runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("minimal-template-runtime"), - impl_name: create_runtime_str!("minimal-template-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"), + impl_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"), authoring_version: 1, spec_version: 0, impl_version: 1, diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs index c2fe5a6727e6..b773af24de80 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs @@ -1,194 +1,192 @@ +use cmd_lib::*; use serde_json::{json, Value}; -use std::{process::Command, str}; +use std::str; -const WASM_FILE_PATH: &str = - "../../../../../target/release/wbuild/chain-spec-guide-runtime/chain_spec_guide_runtime.wasm"; +fn wasm_file_path() -> &'static str { + chain_spec_guide_runtime::runtime::WASM_BINARY_PATH + .expect("chain_spec_guide_runtime wasm should exist. qed") +} const CHAIN_SPEC_BUILDER_PATH: &str = "../../../../../target/release/chain-spec-builder"; +macro_rules! bash( + ( chain-spec-builder $($a:tt)* ) => {{ + let path = get_chain_spec_builder_path(); + spawn_with_output!( + $path $($a)* + ) + .expect("a process running. qed") + .wait_with_output() + .expect("to get output. qed.") + + }} +); + fn get_chain_spec_builder_path() -> &'static str { - // dev-dependencies do not build binary. So let's do the naive work-around here: - let _ = std::process::Command::new("cargo") - .arg("build") - .arg("--release") - .arg("-p") - .arg("staging-chain-spec-builder") - .arg("--bin") - .arg("chain-spec-builder") - .status() - .expect("Failed to execute command"); + run_cmd!( + cargo build --release -p staging-chain-spec-builder --bin chain-spec-builder + ) + .expect("Failed to execute command"); CHAIN_SPEC_BUILDER_PATH } +#[docify::export_content] +fn cmd_list_presets(runtime_path: &str) -> String { + bash!( + chain-spec-builder list-presets -r $runtime_path + ) +} + #[test] -#[docify::export] fn list_presets() { - let output = Command::new(get_chain_spec_builder_path()) - .arg("list-presets") - .arg("-r") - .arg(WASM_FILE_PATH) - .output() - .expect("Failed to execute command"); - - let output: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + let output: serde_json::Value = + serde_json::from_slice(cmd_list_presets(wasm_file_path()).as_bytes()).unwrap(); + assert_eq!( + output, + json!({ + "presets":[ + "preset_1", + "preset_2", + "preset_3", + "preset_4", + "preset_invalid" + ] + }), + "Output did not match expected" + ); +} - let expected_output = json!({ - "presets":[ - "preset_1", - "preset_2", - "preset_3", - "preset_4", - "preset_invalid" - ] - }); - assert_eq!(output, expected_output, "Output did not match expected"); +#[docify::export_content] +fn cmd_get_preset(runtime_path: &str) -> String { + bash!( + chain-spec-builder display-preset -r $runtime_path -p preset_2 + ) } #[test] -#[docify::export] fn get_preset() { - let output = Command::new(get_chain_spec_builder_path()) - .arg("display-preset") - .arg("-r") - .arg(WASM_FILE_PATH) - .arg("-p") - .arg("preset_2") - .output() - .expect("Failed to execute command"); - - let output: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); - - //note: copy of chain_spec_guide_runtime::preset_2 - let expected_output = json!({ - "bar": { - "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - }, - "foo": { - "someEnum": { - "Data2": { - "values": "0x0c10" - } + let output: serde_json::Value = + serde_json::from_slice(cmd_get_preset(wasm_file_path()).as_bytes()).unwrap(); + assert_eq!( + output, + json!({ + "bar": { + "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + }, + "foo": { + "someEnum": { + "Data2": { + "values": "0x0c10" + } + }, + "someInteger": 200 }, - "someInteger": 200 - }, - }); - assert_eq!(output, expected_output, "Output did not match expected"); + }), + "Output did not match expected" + ); +} + +#[docify::export_content] +fn cmd_generate_chain_spec(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c /dev/stdout create -r $runtime_path named-preset preset_2 + ) } #[test] -#[docify::export] fn generate_chain_spec() { - let output = Command::new(get_chain_spec_builder_path()) - .arg("-c") - .arg("/dev/stdout") - .arg("create") - .arg("-r") - .arg(WASM_FILE_PATH) - .arg("named-preset") - .arg("preset_2") - .output() - .expect("Failed to execute command"); - - let mut output: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); - - //remove code field for better readability + let mut output: serde_json::Value = + serde_json::from_slice(cmd_generate_chain_spec(wasm_file_path()).as_bytes()).unwrap(); if let Some(code) = output["genesis"]["runtimeGenesis"].as_object_mut().unwrap().get_mut("code") { *code = Value::String("0x123".to_string()); } - - let expected_output = json!({ - "name": "Custom", - "id": "custom", - "chainType": "Live", - "bootNodes": [], - "telemetryEndpoints": null, - "protocolId": null, - "properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" }, - "codeSubstitutes": {}, - "genesis": { - "runtimeGenesis": { - "code": "0x123", - "patch": { - "bar": { - "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" - }, - "foo": { - "someEnum": { - "Data2": { - "values": "0x0c10" + assert_eq!( + output, + json!({ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x123", + "patch": { + "bar": { + "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" + }, + "foo": { + "someEnum": { + "Data2": { + "values": "0x0c10" + } + }, + "someInteger": 200 } - }, - "someInteger": 200 + } } } - } - } - }); - assert_eq!(output, expected_output, "Output did not match expected"); + }), + "Output did not match expected" + ); +} + +#[docify::export_content] +fn cmd_generate_para_chain_spec(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c /dev/stdout create -c polkadot -p 1000 -r $runtime_path named-preset preset_2 + ) } #[test] -#[docify::export] fn generate_para_chain_spec() { - let output = Command::new(get_chain_spec_builder_path()) - .arg("-c") - .arg("/dev/stdout") - .arg("create") - .arg("-c") - .arg("polkadot") - .arg("-p") - .arg("1000") - .arg("-r") - .arg(WASM_FILE_PATH) - .arg("named-preset") - .arg("preset_2") - .output() - .expect("Failed to execute command"); - - let mut output: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); - - //remove code field for better readability + let mut output: serde_json::Value = + serde_json::from_slice(cmd_generate_para_chain_spec(wasm_file_path()).as_bytes()).unwrap(); if let Some(code) = output["genesis"]["runtimeGenesis"].as_object_mut().unwrap().get_mut("code") { *code = Value::String("0x123".to_string()); } - - let expected_output = json!({ - "name": "Custom", - "id": "custom", - "chainType": "Live", - "bootNodes": [], - "telemetryEndpoints": null, - "protocolId": null, - "relay_chain": "polkadot", - "para_id": 1000, - "properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" }, - "codeSubstitutes": {}, - "genesis": { - "runtimeGenesis": { - "code": "0x123", - "patch": { - "bar": { - "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" - }, - "foo": { - "someEnum": { - "Data2": { - "values": "0x0c10" - } + assert_eq!( + output, + json!({ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "relay_chain": "polkadot", + "para_id": 1000, + "properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x123", + "patch": { + "bar": { + "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" }, - "someInteger": 200 + "foo": { + "someEnum": { + "Data2": { + "values": "0x0c10" + } + }, + "someInteger": 200 + } } } - } - } - }); - assert_eq!(output, expected_output, "Output did not match expected"); + }}), + "Output did not match expected" + ); } #[test] -#[docify::export] +#[docify::export_content] fn preset_4_json() { assert_eq!( chain_spec_guide_runtime::presets::preset_4(), diff --git a/docs/sdk/src/reference_docs/omni_node.rs b/docs/sdk/src/reference_docs/omni_node.rs index 44d63704a458..150755fb29a2 100644 --- a/docs/sdk/src/reference_docs/omni_node.rs +++ b/docs/sdk/src/reference_docs/omni_node.rs @@ -177,9 +177,25 @@ //! [This](https://github.com/paritytech/polkadot-sdk/issues/5565) future improvement to OmniNode //! aims to make such checks automatic. //! +//! ### Runtime conventions +//! +//! The Omni Node needs to make some assumptions about the runtime. During startup, the node fetches +//! the runtime metadata and asserts that the runtime represents a compatible parachain. +//! The checks are best effort and will generate warning level logs in the Omni Node log file on +//! failure. +//! +//! The list of checks may evolve in the future and for now only few rules are implemented: +//! * runtimes must define a type for [`cumulus-pallet-parachain-system`], which is recommended to +//! be named as `ParachainSystem`. +//! * runtimes must define a type for [`frame-system`] pallet, which is recommended to be named as +//! `System`. The configured [`block number`] here will be used by Omni Node to configure AURA +//! accordingly. //! //! [`templates`]: crate::polkadot_sdk::templates //! [`parachain-template`]: https://github.com/paritytech/polkadot-sdk-parachain-template //! [`--dev-block-time`]: polkadot_omni_node_lib::cli::Cli::dev_block_time //! [`polkadot-omni-node`]: https://crates.io/crates/polkadot-omni-node //! [`chain-spec-builder`]: https://crates.io/crates/staging-chain-spec-builder +//! [`cumulus-pallet-parachain-system`]: https://docs.rs/cumulus-pallet-parachain-system/latest/cumulus_pallet_parachain_system/ +//! [`frame-system`]: https://docs.rs/frame-system/latest/frame_system/ +//! [`block number`]: https://docs.rs/frame-system/latest/frame_system/pallet/storage_types/struct.Number.html diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 3a939464868f..ded8157ad90e 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -20,6 +20,8 @@ authors.workspace = true edition.workspace = true version = "6.0.0" default-run = "polkadot" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -44,10 +46,10 @@ tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_suppo [dev-dependencies] assert_cmd = { workspace = true } nix = { features = ["signal"], workspace = true } +polkadot-core-primitives = { workspace = true, default-features = true } +substrate-rpc-client = { workspace = true, default-features = true } tempfile = { workspace = true } tokio = { workspace = true, default-features = true } -substrate-rpc-client = { workspace = true, default-features = true } -polkadot-core-primitives = { workspace = true, default-features = true } [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index da37f6062c57..6909d142b3a6 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -20,27 +22,27 @@ crate-type = ["cdylib", "rlib"] [dependencies] cfg-if = { workspace = true } clap = { features = ["derive"], optional = true, workspace = true } -log = { workspace = true, default-features = true } -thiserror = { workspace = true } futures = { workspace = true } +log = { workspace = true, default-features = true } pyroscope = { optional = true, workspace = true } pyroscope_pprofrs = { optional = true, workspace = true } +thiserror = { workspace = true } polkadot-service = { optional = true, workspace = true } -sp-core = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -sp-maybe-compressed-blob = { workspace = true, default-features = true } frame-benchmarking-cli = { optional = true, workspace = true, default-features = true } -sc-cli = { optional = true, workspace = true, default-features = true } -sc-service = { optional = true, workspace = true, default-features = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -sc-tracing = { optional = true, workspace = true, default-features = true } -sc-sysinfo = { workspace = true, default-features = true } +sc-cli = { optional = true, workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } +sc-service = { optional = true, workspace = true, default-features = true } sc-storage-monitor = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +sc-tracing = { optional = true, workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } [build-dependencies] diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index eb67a3956342..777bb9c60671 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -79,7 +79,7 @@ pub struct RunCmd { /// Disable the BEEFY gadget. /// - /// Currently enabled by default on 'Rococo', 'Wococo' and 'Versi'. + /// Currently enabled by default. #[arg(long)] pub no_beefy: bool, diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 42ca27953738..1fb14e9d58e7 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -5,15 +5,17 @@ description = "Core Polkadot types used by Relay Chains and parachains." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -codec = { features = ["derive"], workspace = true } [features] default = ["std"] diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index 969742c5bb0a..ba712a89613b 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -5,22 +5,24 @@ description = "Erasure coding used for Polkadot's availability system" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } -novelpoly = { workspace = true } codec = { features = ["derive", "std"], workspace = true } +novelpoly = { workspace = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } thiserror = { workspace = true } [dev-dependencies] -quickcheck = { workspace = true } criterion = { features = ["cargo_bench_support"], workspace = true } +quickcheck = { workspace = true } [[bench]] name = "scaling_with_validators" diff --git a/polkadot/erasure-coding/fuzzer/Cargo.toml b/polkadot/erasure-coding/fuzzer/Cargo.toml index 6f451f0319b2..5f1c2bda4058 100644 --- a/polkadot/erasure-coding/fuzzer/Cargo.toml +++ b/polkadot/erasure-coding/fuzzer/Cargo.toml @@ -10,10 +10,10 @@ publish = false workspace = true [dependencies] -polkadot-erasure-coding = { workspace = true, default-features = true } honggfuzz = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } [[bin]] name = "reconstruct" diff --git a/polkadot/grafana/README.md b/polkadot/grafana/README.md index e909fdd29a75..0ecb0b70515b 100644 --- a/polkadot/grafana/README.md +++ b/polkadot/grafana/README.md @@ -90,4 +90,4 @@ and issue statement or initiate dispute. - **Assignment delay tranches**. Approval voting is designed such that validators assigned to check a specific candidate are split up into equal delay tranches (0.5 seconds each). All validators checks are ordered by the delay tranche index. Early tranches of validators have the opportunity to check the candidate first before later tranches -that act as as backups in case of no shows. +that act as backups in case of no shows. diff --git a/polkadot/grafana/parachains/status.json b/polkadot/grafana/parachains/status.json index 5942cbdf4479..22250967848d 100644 --- a/polkadot/grafana/parachains/status.json +++ b/polkadot/grafana/parachains/status.json @@ -1405,7 +1405,7 @@ "type": "prometheus", "uid": "$data_source" }, - "description": "Approval voting requires that validators which are assigned to check a specific \ncandidate are split up into delay tranches (0.5s each). Then, all validators checks are ordered by the delay \ntranche index. Early tranches of validators will check the candidate first and later tranches act as as backups in case of no shows.", + "description": "Approval voting requires that validators which are assigned to check a specific \ncandidate are split up into delay tranches (0.5s each). Then, all validators checks are ordered by the delay \ntranche index. Early tranches of validators will check the candidate first and later tranches act as backups in case of no shows.", "gridPos": { "h": 9, "w": 18, diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index 777458673f5b..eb9568cc22bc 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -5,11 +5,14 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Collator-side subsystem that handles incoming candidate submissions from the parachain." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +codec = { features = ["bit-vec", "derive"], workspace = true } futures = { workspace = true } gum = { workspace = true, default-features = true } polkadot-erasure-coding = { workspace = true, default-features = true } @@ -17,16 +20,15 @@ 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 } +schnellru = { workspace = true } sp-core = { workspace = true, default-features = true } sp-maybe-compressed-blob = { workspace = true, default-features = true } thiserror = { workspace = true } -codec = { features = ["bit-vec", "derive"], workspace = true } -schnellru = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives = { workspace = true, features = ["test"] } polkadot-primitives-test-helpers = { workspace = true } -assert_matches = { workspace = true } rstest = { workspace = true } sp-keyring = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, features = ["test"] } diff --git a/polkadot/node/collation-generation/src/error.rs b/polkadot/node/collation-generation/src/error.rs index 68902f58579a..2599026080df 100644 --- a/polkadot/node/collation-generation/src/error.rs +++ b/polkadot/node/collation-generation/src/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use polkadot_primitives::vstaging::CandidateReceiptError; +use polkadot_primitives::vstaging::CommittedCandidateReceiptError; use thiserror::Error; #[derive(Debug, Error)] @@ -34,7 +34,7 @@ pub enum Error { #[error("Collation submitted before initialization")] SubmittedBeforeInit, #[error("V2 core index check failed: {0}")] - CandidateReceiptCheck(CandidateReceiptError), + CandidateReceiptCheck(CommittedCandidateReceiptError), #[error("PoV size {0} exceeded maximum size of {1}")] POVSizeExceeded(usize, usize), } diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 9e975acf10b8..b371017a8289 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -554,7 +554,7 @@ async fn construct_and_distribute_receipt( ccr.to_plain() } else { - if commitments.selected_core().is_some() { + if commitments.core_selector().map_err(Error::CandidateReceiptCheck)?.is_some() { gum::warn!( target: LOG_TARGET, ?pov_hash, diff --git a/polkadot/node/core/approval-voting-parallel/Cargo.toml b/polkadot/node/core/approval-voting-parallel/Cargo.toml index 3a98cce80e92..a3b3e97da497 100644 --- a/polkadot/node/core/approval-voting-parallel/Cargo.toml +++ b/polkadot/node/core/approval-voting-parallel/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Approval Voting Subsystem running approval work in parallel" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,38 +19,38 @@ 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-core-approval-voting = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +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-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-primitives = { 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-application-crypto = { workspace = true, default-features = false, features = ["full_crypto"] } 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 } +rand_core = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } async-trait = { workspace = true } +kvdb-memorydb = { workspace = true } +log = { workspace = true, default-features = 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 } +sp-consensus-babe = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-tracing = { workspace = true } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index f9754d2babc9..2c292ba5efcb 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -5,55 +5,57 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Approval Voting Subsystem of the Polkadot node" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +async-trait = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } +codec = { features = ["bit-vec", "derive"], workspace = true } +derive_more = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } -codec = { features = ["bit-vec", "derive"], workspace = true } gum = { workspace = true, default-features = true } -bitvec = { features = ["alloc"], workspace = true } -schnellru = { workspace = true } +itertools = { workspace = true } +kvdb = { workspace = true } merlin = { workspace = true, default-features = true } +schnellru = { workspace = true } schnorrkel = { workspace = true, default-features = true } -kvdb = { workspace = true } -derive_more = { workspace = true, default-features = true } thiserror = { workspace = true } -itertools = { workspace = true } -async-trait = { workspace = true } +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-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } sc-keystore = { workspace = true } +sp-application-crypto = { features = ["full_crypto"], workspace = true } sp-consensus = { workspace = true } sp-consensus-slots = { workspace = true } -sp-application-crypto = { features = ["full_crypto"], workspace = true } sp-runtime = { workspace = true } # rand_core should match schnorrkel -rand_core = { workspace = true } -rand_chacha = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +rand_chacha = { workspace = true, default-features = true } +rand_core = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } async-trait = { workspace = true } +kvdb-memorydb = { workspace = true } +log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = 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 } polkadot-node-subsystem-test-helpers = { workspace = true } -assert_matches = { workspace = true } -kvdb-memorydb = { workspace = true } +polkadot-primitives = { workspace = true, features = ["test"] } polkadot-primitives-test-helpers = { workspace = true } -log = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true } -polkadot-primitives = { workspace = true, features = ["test"] } polkadot-subsystem-bench = { workspace = true } diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs index 372dd49803cb..69278868fa3d 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs @@ -264,8 +264,8 @@ fn add_block_entry_adds_child() { fn canonicalize_works() { let (mut db, store) = make_db(); - // -> B1 -> C1 -> D1 - // A -> B2 -> C2 -> D2 + // -> B1 -> C1 -> D1 -> E1 + // A -> B2 -> C2 -> D2 -> E2 // // We'll canonicalize C1. Everything except D1 should disappear. // @@ -293,18 +293,22 @@ fn canonicalize_works() { let block_hash_c2 = Hash::repeat_byte(5); let block_hash_d1 = Hash::repeat_byte(6); let block_hash_d2 = Hash::repeat_byte(7); + let block_hash_e1 = Hash::repeat_byte(8); + let block_hash_e2 = Hash::repeat_byte(9); let candidate_receipt_genesis = make_candidate(ParaId::from(1_u32), genesis); let candidate_receipt_a = make_candidate(ParaId::from(2_u32), block_hash_a); let candidate_receipt_b = make_candidate(ParaId::from(3_u32), block_hash_a); let candidate_receipt_b1 = make_candidate(ParaId::from(4_u32), block_hash_b1); let candidate_receipt_c1 = make_candidate(ParaId::from(5_u32), block_hash_c1); + let candidate_receipt_e1 = make_candidate(ParaId::from(6_u32), block_hash_e1); let cand_hash_1 = candidate_receipt_genesis.hash(); let cand_hash_2 = candidate_receipt_a.hash(); let cand_hash_3 = candidate_receipt_b.hash(); let cand_hash_4 = candidate_receipt_b1.hash(); let cand_hash_5 = candidate_receipt_c1.hash(); + let cand_hash_6 = candidate_receipt_e1.hash(); let block_entry_a = make_block_entry(block_hash_a, genesis, 1, Vec::new()); let block_entry_b1 = make_block_entry(block_hash_b1, block_hash_a, 2, Vec::new()); @@ -326,6 +330,12 @@ fn canonicalize_works() { let block_entry_d2 = make_block_entry(block_hash_d2, block_hash_c2, 4, vec![(CoreIndex(0), cand_hash_5)]); + let block_entry_e1 = + make_block_entry(block_hash_e1, block_hash_d1, 5, vec![(CoreIndex(0), cand_hash_6)]); + + let block_entry_e2 = + make_block_entry(block_hash_e2, block_hash_d2, 5, vec![(CoreIndex(0), cand_hash_6)]); + let candidate_info = { let mut candidate_info = HashMap::new(); candidate_info.insert( @@ -345,6 +355,8 @@ fn canonicalize_works() { candidate_info .insert(cand_hash_5, NewCandidateInfo::new(candidate_receipt_c1, GroupIndex(5), None)); + candidate_info + .insert(cand_hash_6, NewCandidateInfo::new(candidate_receipt_e1, GroupIndex(6), None)); candidate_info }; @@ -357,6 +369,8 @@ fn canonicalize_works() { block_entry_c2.clone(), block_entry_d1.clone(), block_entry_d2.clone(), + block_entry_e1.clone(), + block_entry_e2.clone(), ]; let mut overlay_db = OverlayedBackend::new(&db); @@ -438,7 +452,7 @@ fn canonicalize_works() { assert_eq!( load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap().unwrap(), - StoredBlockRange(4, 5) + StoredBlockRange(4, 6) ); check_candidates_in_store(vec![ @@ -447,6 +461,7 @@ fn canonicalize_works() { (cand_hash_3, Some(vec![block_hash_d1])), (cand_hash_4, Some(vec![block_hash_d1])), (cand_hash_5, None), + (cand_hash_6, Some(vec![block_hash_e1])), ]); check_blocks_in_store(vec![ @@ -456,6 +471,37 @@ fn canonicalize_works() { (block_hash_c1, None), (block_hash_c2, None), (block_hash_d1, Some(vec![cand_hash_3, cand_hash_4])), + (block_hash_e1, Some(vec![cand_hash_6])), + (block_hash_d2, None), + ]); + + let mut overlay_db = OverlayedBackend::new(&db); + canonicalize(&mut overlay_db, 4, block_hash_d1).unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap().unwrap(), + StoredBlockRange(5, 6) + ); + + check_candidates_in_store(vec![ + (cand_hash_1, None), + (cand_hash_2, None), + (cand_hash_3, None), + (cand_hash_4, None), + (cand_hash_5, None), + (cand_hash_6, Some(vec![block_hash_e1])), + ]); + + check_blocks_in_store(vec![ + (block_hash_a, None), + (block_hash_b1, None), + (block_hash_b2, None), + (block_hash_c1, None), + (block_hash_c2, None), + (block_hash_d1, None), + (block_hash_e1, Some(vec![cand_hash_6])), (block_hash_d2, None), ]); } diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 2176cc7675be..7cea22d1a6a7 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -1582,8 +1582,9 @@ async fn handle_actions< session_info_provider, ) .await?; - - approval_voting_sender.send_messages(messages.into_iter()).await; + for message in messages.into_iter() { + approval_voting_sender.send_unbounded_message(message); + } let next_actions: Vec = next_actions.into_iter().map(|v| v.clone()).chain(actions_iter).collect(); @@ -1668,6 +1669,7 @@ async fn distribution_messages_for_activation SubsystemResult<()> { let range = match overlay_db.load_stored_blocks()? { None => return Ok(()), - Some(range) if range.0 >= canon_number => return Ok(()), + Some(range) if range.0 > canon_number => return Ok(()), Some(range) => range, }; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 099ab419dfbf..be569a1de3ec 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -4459,6 +4459,114 @@ async fn setup_overseer_with_two_blocks_each_with_one_assignment_triggered( assert!(our_assignment.triggered()); } +// Builds a chain with a fork where both relay blocks include the same candidate. +async fn build_chain_with_block_with_two_candidates( + block_hash1: Hash, + slot: Slot, + sync_oracle_handle: TestSyncOracleHandle, + candidate_receipt: Vec, +) -> (ChainBuilder, SessionInfo) { + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + let session_info = SessionInfo { + validator_groups: IndexedVec::>::from(vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3), ValidatorIndex(4)], + ]), + ..session_info(&validators) + }; + + let candidates = Some( + candidate_receipt + .iter() + .enumerate() + .map(|(i, receipt)| (receipt.clone(), CoreIndex(i as u32), GroupIndex(i as u32))) + .collect(), + ); + let mut chain_builder = ChainBuilder::new(); + + chain_builder + .major_syncing(sync_oracle_handle.is_major_syncing.clone()) + .add_block( + block_hash1, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot, + candidates: candidates.clone(), + session_info: Some(session_info.clone()), + end_syncing: true, + }, + ); + (chain_builder, session_info) +} + +async fn setup_overseer_with_blocks_with_two_assignments_triggered( + virtual_overseer: &mut VirtualOverseer, + store: TestStore, + clock: &Arc, + sync_oracle_handle: TestSyncOracleHandle, +) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + let candidate_commitments = CandidateCommitments::default(); + let mut candidate_receipt = dummy_candidate_receipt_v2(block_hash); + candidate_receipt.commitments_hash = candidate_commitments.hash(); + let candidate_hash = candidate_receipt.hash(); + + let mut candidate_commitments2 = CandidateCommitments::default(); + candidate_commitments2.processed_downward_messages = 3; + let mut candidate_receipt2 = dummy_candidate_receipt_v2(block_hash); + candidate_receipt2.commitments_hash = candidate_commitments2.hash(); + let candidate_hash2 = candidate_receipt2.hash(); + + let slot = Slot::from(1); + let (chain_builder, _session_info) = build_chain_with_block_with_two_candidates( + block_hash, + slot, + sync_oracle_handle, + vec![candidate_receipt, candidate_receipt2], + ) + .await; + chain_builder.build(virtual_overseer).await; + + assert!(!clock.inner.lock().current_wakeup_is(1)); + clock.inner.lock().wakeup_all(1); + + assert!(clock.inner.lock().current_wakeup_is(slot_to_tick(slot))); + clock.inner.lock().wakeup_all(slot_to_tick(slot)); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + clock.inner.lock().wakeup_all(slot_to_tick(slot + 2)); + + assert_eq!(clock.inner.lock().wakeups.len(), 0); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + let candidate_entry = store.load_candidate_entry(&candidate_hash).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + let candidate_entry = store.load_candidate_entry(&candidate_hash2).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); +} + // Tests that for candidates that we did not approve yet, for which we triggered the assignment and // the approval work we restart the work to approve it. #[test] @@ -4920,6 +5028,212 @@ fn subsystem_sends_pending_approvals_on_approval_restart() { }); } +// Test that after restart approvals are sent after all assignments have been distributed. +#[test] +fn subsystem_sends_assignment_approval_in_correct_order_on_approval_restart() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(2)].try_into().unwrap(), + }), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(1), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFDelay { + core_index: CoreIndex(1), + }), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + assignments + }, + |_| Ok(0), + )); + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + let store_clone = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle } = test_harness; + + setup_overseer_with_blocks_with_two_assignments_triggered( + &mut virtual_overseer, + store, + &clock, + sync_oracle_handle, + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _ + )) => { + } + ); + + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { + exec_kind, + response_sender, + .. + }) if exec_kind == PvfExecKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + .unwrap(); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { + exec_kind, + response_sender, + .. + }) if exec_kind == PvfExecKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + .unwrap(); + } + ); + + // Configure a big coalesce number, so that the signature is cached instead of being sent to + // approval-distribution. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 2, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 2, + })); + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(&mut virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + virtual_overseer + }); + + let config = HarnessConfigBuilder::default().backend(store_clone).major_syncing(true).build(); + // On restart we should first distribute all assignments covering a coalesced approval. + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle } = test_harness; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + let candidate_commitments = CandidateCommitments::default(); + let mut candidate_receipt = dummy_candidate_receipt_v2(block_hash); + candidate_receipt.commitments_hash = candidate_commitments.hash(); + + let mut candidate_commitments2 = CandidateCommitments::default(); + candidate_commitments2.processed_downward_messages = 3; + let mut candidate_receipt2 = dummy_candidate_receipt_v2(block_hash); + candidate_receipt2.commitments_hash = candidate_commitments2.hash(); + + let slot = Slot::from(1); + + clock.inner.lock().set_tick(slot_to_tick(slot + 2)); + let (chain_builder, _session_info) = build_chain_with_block_with_two_candidates( + block_hash, + slot, + sync_oracle_handle, + vec![candidate_receipt.into(), candidate_receipt2.into()], + ) + .await; + chain_builder.build(&mut virtual_overseer).await; + + futures_timer::Delay::new(Duration::from_millis(2000)).await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks( + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + _, + )) => { + } + ); + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(approval)) => { + assert_eq!(approval.candidate_indices.count_ones(), 2); + } + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(&mut virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + virtual_overseer + }); +} + // Test we correctly update the timer when we mark the beginning of gathering assignments. #[test] fn test_gathering_assignments_statements() { diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 1d14e4cfba37..f3bd1f09caea 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -5,36 +5,38 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +bitvec = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } kvdb = { workspace = true } thiserror = { workspace = true } -gum = { workspace = true, default-features = true } -bitvec = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true, default-features = true } polkadot-erasure-coding = { workspace = true, default-features = true } +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-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } sp-consensus = { workspace = true } [dev-dependencies] -log = { workspace = true, default-features = true } assert_matches = { workspace = true } kvdb-memorydb = { workspace = true } +log = { workspace = true, default-features = true } sp-tracing = { workspace = true } -sp-core = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } -polkadot-node-subsystem-test-helpers = { workspace = true } -sp-keyring = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-primitives-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index cd1acf9daa93..be829a84ee6e 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -5,35 +5,37 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "The Candidate Backing Subsystem. Tracks parachain candidates that can be backed, as well as the issuance of statements about candidates." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +bitvec = { features = ["alloc"], workspace = true } +fatality = { workspace = true } futures = { workspace = true } -sp-keystore = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +gum = { workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } -polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-statement-table = { workspace = true, default-features = true } -bitvec = { features = ["alloc"], workspace = true } -gum = { workspace = true, default-features = true } -thiserror = { workspace = true } -fatality = { workspace = true } schnellru = { workspace = true } +sp-keystore = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] -sp-core = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } -futures = { features = ["thread-pool"], workspace = true } assert_matches = { workspace = true } -rstest = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } polkadot-primitives = { workspace = true, features = ["test"] } +polkadot-primitives-test-helpers = { workspace = true } +rstest = { workspace = true } +sc-keystore = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } diff --git a/polkadot/node/core/backing/src/error.rs b/polkadot/node/core/backing/src/error.rs index e09d8425f78a..e1852be826f4 100644 --- a/polkadot/node/core/backing/src/error.rs +++ b/polkadot/node/core/backing/src/error.rs @@ -105,6 +105,9 @@ pub enum Error { #[error("Availability store error")] StoreAvailableData(#[source] StoreAvailableDataError), + + #[error("Runtime API returned None for executor params")] + MissingExecutorParams, } /// Utility for eating top level errors and log them. diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index b5362d32ad88..8b54a8b5907b 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -93,17 +93,15 @@ use polkadot_node_subsystem::{ RuntimeApiMessage, RuntimeApiRequest, StatementDistributionMessage, StoreAvailableDataError, }, - overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, SpawnedSubsystem, + SubsystemError, }; use polkadot_node_subsystem_util::{ self as util, - backing_implicit_view::{FetchError as ImplicitViewFetchError, View as ImplicitView}, - executor_params_at_relay_parent, request_from_runtime, request_session_index_for_child, - request_validator_groups, request_validators, - runtime::{ - self, fetch_claim_queue, prospective_parachains_mode, request_min_backing_votes, - ClaimQueueSnapshot, ProspectiveParachainsMode, - }, + backing_implicit_view::View as ImplicitView, + request_claim_queue, request_disabled_validators, request_session_executor_params, + request_session_index_for_child, request_validator_groups, request_validators, + runtime::{self, request_min_backing_votes, ClaimQueueSnapshot}, Validator, }; use polkadot_parachain_primitives::primitives::IsSystem; @@ -111,7 +109,7 @@ use polkadot_primitives::{ node_features::FeatureIndex, vstaging::{ BackedCandidate, CandidateReceiptV2 as CandidateReceipt, - CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, }, CandidateCommitments, CandidateHash, CoreIndex, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, PersistedValidationData, SessionIndex, @@ -124,10 +122,10 @@ use polkadot_statement_table::{ SignedStatement as TableSignedStatement, Statement as TableStatement, Summary as TableSummary, }, - Config as TableConfig, Context as TableContextTrait, Table, + Context as TableContextTrait, Table, }; use sp_keystore::KeystorePtr; -use util::runtime::{get_disabled_validators_with_fallback, request_node_features}; +use util::runtime::request_node_features; mod error; @@ -214,11 +212,12 @@ where } struct PerRelayParentState { - prospective_parachains_mode: ProspectiveParachainsMode, /// The hash of the relay parent on top of which this job is doing it's work. parent: Hash, - /// Session index. - session_index: SessionIndex, + /// The node features. + node_features: NodeFeatures, + /// The executor parameters. + executor_params: Arc, /// The `CoreIndex` assigned to the local validator at this relay parent. assigned_core: Option, /// The candidates that are backed by enough validators in their group, by hash. @@ -255,76 +254,193 @@ struct PerCandidateState { relay_parent: Hash, } -enum ActiveLeafState { - // If prospective-parachains is disabled, one validator may only back one candidate per - // paraid. - ProspectiveParachainsDisabled { seconded: HashSet }, - ProspectiveParachainsEnabled { max_candidate_depth: usize, allowed_ancestry_len: usize }, +/// A cache for storing data per-session to reduce repeated +/// runtime API calls and avoid redundant computations. +struct PerSessionCache { + /// Cache for storing validators list, retrieved from the runtime. + validators_cache: LruMap>>, + /// Cache for storing node features, retrieved from the runtime. + node_features_cache: LruMap>, + /// Cache for storing executor parameters, retrieved from the runtime. + executor_params_cache: LruMap>, + /// Cache for storing the minimum backing votes threshold, retrieved from the runtime. + minimum_backing_votes_cache: LruMap, + /// Cache for storing validator-to-group mappings, computed from validator groups. + validator_to_group_cache: + LruMap>>>, } -impl ActiveLeafState { - fn new(mode: ProspectiveParachainsMode) -> Self { - match mode { - ProspectiveParachainsMode::Disabled => - Self::ProspectiveParachainsDisabled { seconded: HashSet::new() }, - ProspectiveParachainsMode::Enabled { max_candidate_depth, allowed_ancestry_len } => - Self::ProspectiveParachainsEnabled { max_candidate_depth, allowed_ancestry_len }, +impl Default for PerSessionCache { + /// Creates a new `PerSessionCache` with a default capacity. + fn default() -> Self { + Self::new(2) + } +} + +impl PerSessionCache { + /// Creates a new `PerSessionCache` with a given capacity. + fn new(capacity: u32) -> Self { + PerSessionCache { + validators_cache: LruMap::new(ByLength::new(capacity)), + node_features_cache: LruMap::new(ByLength::new(capacity)), + executor_params_cache: LruMap::new(ByLength::new(capacity)), + minimum_backing_votes_cache: LruMap::new(ByLength::new(capacity)), + validator_to_group_cache: LruMap::new(ByLength::new(capacity)), } } - fn add_seconded_candidate(&mut self, para_id: ParaId) { - if let Self::ProspectiveParachainsDisabled { seconded } = self { - seconded.insert(para_id); + /// Gets validators from the cache or fetches them from the runtime if not present. + async fn validators( + &mut self, + session_index: SessionIndex, + parent: Hash, + sender: &mut impl overseer::SubsystemSender, + ) -> Result>, RuntimeApiError> { + // Try to get the validators list from the cache. + if let Some(validators) = self.validators_cache.get(&session_index) { + return Ok(Arc::clone(validators)); } + + // Fetch the validators list from the runtime since it was not in the cache. + let validators: Vec = + request_validators(parent, sender).await.await.map_err(|err| { + RuntimeApiError::Execution { runtime_api_name: "Validators", source: Arc::new(err) } + })??; + + // Wrap the validators list in an Arc to avoid a deep copy when storing it in the cache. + let validators = Arc::new(validators); + + // Cache the fetched validators list for future use. + self.validators_cache.insert(session_index, Arc::clone(&validators)); + + Ok(validators) + } + + /// Gets the node features from the cache or fetches it from the runtime if not present. + async fn node_features( + &mut self, + session_index: SessionIndex, + parent: Hash, + sender: &mut impl overseer::SubsystemSender, + ) -> Result, Error> { + // Try to get the node features from the cache. + if let Some(node_features) = self.node_features_cache.get(&session_index) { + return Ok(node_features.clone()); + } + + // Fetch the node features from the runtime since it was not in the cache. + let node_features: Option = + request_node_features(parent, session_index, sender).await?; + + // Cache the fetched node features for future use. + self.node_features_cache.insert(session_index, node_features.clone()); + + Ok(node_features) } -} -impl From<&ActiveLeafState> for ProspectiveParachainsMode { - fn from(state: &ActiveLeafState) -> Self { - match *state { - ActiveLeafState::ProspectiveParachainsDisabled { .. } => - ProspectiveParachainsMode::Disabled, - ActiveLeafState::ProspectiveParachainsEnabled { - max_candidate_depth, - allowed_ancestry_len, - } => ProspectiveParachainsMode::Enabled { max_candidate_depth, allowed_ancestry_len }, + /// Gets the executor parameters from the cache or + /// fetches them from the runtime if not present. + async fn executor_params( + &mut self, + session_index: SessionIndex, + parent: Hash, + sender: &mut impl overseer::SubsystemSender, + ) -> Result, RuntimeApiError> { + // Try to get the executor parameters from the cache. + if let Some(executor_params) = self.executor_params_cache.get(&session_index) { + return Ok(Arc::clone(executor_params)); } + + // Fetch the executor parameters from the runtime since it was not in the cache. + let executor_params = request_session_executor_params(parent, session_index, sender) + .await + .await + .map_err(|err| RuntimeApiError::Execution { + runtime_api_name: "SessionExecutorParams", + source: Arc::new(err), + })?? + .ok_or_else(|| RuntimeApiError::Execution { + runtime_api_name: "SessionExecutorParams", + source: Arc::new(Error::MissingExecutorParams), + })?; + + // Wrap the executor parameters in an Arc to avoid a deep copy when storing it in the cache. + let executor_params = Arc::new(executor_params); + + // Cache the fetched executor parameters for future use. + self.executor_params_cache.insert(session_index, Arc::clone(&executor_params)); + + Ok(executor_params) + } + + /// Gets the minimum backing votes threshold from the + /// cache or fetches it from the runtime if not present. + async fn minimum_backing_votes( + &mut self, + session_index: SessionIndex, + parent: Hash, + sender: &mut impl overseer::SubsystemSender, + ) -> Result { + // Try to get the value from the cache. + if let Some(minimum_backing_votes) = self.minimum_backing_votes_cache.get(&session_index) { + return Ok(*minimum_backing_votes); + } + + // Fetch the value from the runtime since it was not in the cache. + let minimum_backing_votes = request_min_backing_votes(parent, session_index, sender) + .await + .map_err(|err| RuntimeApiError::Execution { + runtime_api_name: "MinimumBackingVotes", + source: Arc::new(err), + })?; + + // Cache the fetched value for future use. + self.minimum_backing_votes_cache.insert(session_index, minimum_backing_votes); + + Ok(minimum_backing_votes) + } + + /// Gets or computes the validator-to-group mapping for a session. + fn validator_to_group( + &mut self, + session_index: SessionIndex, + validators: &[ValidatorId], + validator_groups: &[Vec], + ) -> Arc>> { + let validator_to_group = self + .validator_to_group_cache + .get_or_insert(session_index, || { + let mut vector = vec![None; validators.len()]; + + for (group_idx, validator_group) in validator_groups.iter().enumerate() { + for validator in validator_group { + vector[validator.0 as usize] = Some(GroupIndex(group_idx as u32)); + } + } + + Arc::new(IndexedVec::<_, _>::from(vector)) + }) + .expect("Just inserted"); + + Arc::clone(validator_to_group) } } /// The state of the subsystem. struct State { /// The utility for managing the implicit and explicit views in a consistent way. - /// - /// We only feed leaves which have prospective parachains enabled to this view. implicit_view: ImplicitView, - /// State tracked for all active leaves, whether or not they have prospective parachains - /// enabled. - per_leaf: HashMap, /// State tracked for all relay-parents backing work is ongoing for. This includes /// all active leaves. - /// - /// relay-parents fall into one of 3 categories. - /// 1. active leaves which do support prospective parachains - /// 2. active leaves which do not support prospective parachains - /// 3. relay-chain blocks which are ancestors of an active leaf and do support prospective - /// parachains. - /// - /// Relay-chain blocks which don't support prospective parachains are - /// never included in the fragment chains of active leaves which do. - /// - /// While it would be technically possible to support such leaves in - /// fragment chains, it only benefits the transition period when asynchronous - /// backing is being enabled and complicates code. per_relay_parent: HashMap, /// State tracked for all candidates relevant to the implicit view. /// /// This is guaranteed to have an entry for each candidate with a relay parent in the implicit /// or explicit view for which a `Seconded` statement has been successfully imported. per_candidate: HashMap, - /// Cache the per-session Validator->Group mapping. - validator_to_group_cache: - LruMap>>>, + /// A local cache for storing per-session data. This cache helps to + /// reduce repeated calls to the runtime and avoid redundant computations. + per_session_cache: PerSessionCache, /// A clonable sender which is dispatched to background candidate validation tasks to inform /// the main task of the result. background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, @@ -339,10 +455,9 @@ impl State { ) -> Self { State { implicit_view: ImplicitView::default(), - per_leaf: HashMap::default(), per_relay_parent: HashMap::default(), per_candidate: HashMap::new(), - validator_to_group_cache: LruMap::new(ByLength::new(2)), + per_session_cache: PerSessionCache::default(), background_validation_tx, keystore, } @@ -632,6 +747,7 @@ async fn request_candidate_validation( ) -> Result { let (tx, rx) = oneshot::channel(); let is_system = candidate_receipt.descriptor.para_id().is_system(); + let relay_parent = candidate_receipt.descriptor.relay_parent(); sender .send_message(CandidateValidationMessage::ValidateFromExhaustive { @@ -641,9 +757,9 @@ async fn request_candidate_validation( pov, executor_params, exec_kind: if is_system { - PvfExecKind::BackingSystemParas + PvfExecKind::BackingSystemParas(relay_parent) } else { - PvfExecKind::Backing + PvfExecKind::Backing(relay_parent) }, response_sender: tx, }) @@ -669,7 +785,8 @@ struct BackgroundValidationParams { tx_command: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, candidate: CandidateReceipt, relay_parent: Hash, - session_index: SessionIndex, + node_features: NodeFeatures, + executor_params: Arc, persisted_validation_data: PersistedValidationData, pov: PoVData, n_validators: usize, @@ -688,7 +805,8 @@ async fn validate_and_make_available( mut tx_command, candidate, relay_parent, - session_index, + node_features, + executor_params, persisted_validation_data, pov, n_validators, @@ -713,15 +831,6 @@ async fn validate_and_make_available( } }; - let executor_params = match executor_params_at_relay_parent(relay_parent, &mut sender).await { - Ok(ep) => ep, - Err(e) => return Err(Error::UtilError(e)), - }; - - let node_features = request_node_features(relay_parent, session_index, &mut sender) - .await? - .unwrap_or(NodeFeatures::EMPTY); - let pov = match pov { PoVData::Ready(pov) => pov, PoVData::FetchFromValidator { from_validator, candidate_hash, pov_hash } => @@ -757,7 +866,7 @@ async fn validate_and_make_available( validation_code, candidate.clone(), pov.clone(), - executor_params, + executor_params.as_ref().clone(), ) .await? }; @@ -853,87 +962,42 @@ async fn handle_active_leaves_update( update: ActiveLeavesUpdate, state: &mut State, ) -> Result<(), Error> { - enum LeafHasProspectiveParachains { - Enabled(Result), - Disabled, - } - // Activate in implicit view before deactivate, per the docs // on ImplicitView, this is more efficient. let res = if let Some(leaf) = update.activated { - // Only activate in implicit view if prospective - // parachains are enabled. - let mode = prospective_parachains_mode(ctx.sender(), leaf.hash).await?; - let leaf_hash = leaf.hash; - Some(( - leaf, - match mode { - ProspectiveParachainsMode::Disabled => LeafHasProspectiveParachains::Disabled, - ProspectiveParachainsMode::Enabled { .. } => LeafHasProspectiveParachains::Enabled( - state.implicit_view.activate_leaf(ctx.sender(), leaf_hash).await.map(|_| mode), - ), - }, - )) + Some((leaf, state.implicit_view.activate_leaf(ctx.sender(), leaf_hash).await.map(|_| ()))) } else { None }; for deactivated in update.deactivated { - state.per_leaf.remove(&deactivated); state.implicit_view.deactivate_leaf(deactivated); } // clean up `per_relay_parent` according to ancestry // of leaves. we do this so we can clean up candidates right after // as a result. - // - // when prospective parachains are disabled, the implicit view is empty, - // which means we'll clean up everything that's not a leaf - the expected behavior - // for pre-asynchronous backing. { - let remaining: HashSet<_> = state - .per_leaf - .keys() - .chain(state.implicit_view.all_allowed_relay_parents()) - .collect(); + let remaining: HashSet<_> = state.implicit_view.all_allowed_relay_parents().collect(); state.per_relay_parent.retain(|r, _| remaining.contains(&r)); } // clean up `per_candidate` according to which relay-parents // are known. - // - // when prospective parachains are disabled, we clean up all candidates - // because we've cleaned up all relay parents. this is correct. state .per_candidate .retain(|_, pc| state.per_relay_parent.contains_key(&pc.relay_parent)); // Get relay parents which might be fresh but might be known already // that are explicit or implicit from the new active leaf. - let (fresh_relay_parents, leaf_mode) = match res { + let fresh_relay_parents = match res { None => return Ok(()), - Some((leaf, LeafHasProspectiveParachains::Disabled)) => { - // defensive in this case - for enabled, this manifests as an error. - if state.per_leaf.contains_key(&leaf.hash) { - return Ok(()) - } - - state - .per_leaf - .insert(leaf.hash, ActiveLeafState::new(ProspectiveParachainsMode::Disabled)); - - (vec![leaf.hash], ProspectiveParachainsMode::Disabled) - }, - Some((leaf, LeafHasProspectiveParachains::Enabled(Ok(prospective_parachains_mode)))) => { + Some((leaf, Ok(_))) => { let fresh_relay_parents = state.implicit_view.known_allowed_relay_parents_under(&leaf.hash, None); - let active_leaf_state = ActiveLeafState::new(prospective_parachains_mode); - - state.per_leaf.insert(leaf.hash, active_leaf_state); - let fresh_relay_parent = match fresh_relay_parents { Some(f) => f.to_vec(), None => { @@ -946,9 +1010,9 @@ async fn handle_active_leaves_update( vec![leaf.hash] }, }; - (fresh_relay_parent, prospective_parachains_mode) + fresh_relay_parent }, - Some((leaf, LeafHasProspectiveParachains::Enabled(Err(e)))) => { + Some((leaf, Err(e))) => { gum::debug!( target: LOG_TARGET, leaf_hash = ?leaf.hash, @@ -966,26 +1030,13 @@ async fn handle_active_leaves_update( continue } - let mode = match state.per_leaf.get(&maybe_new) { - None => { - // If the relay-parent isn't a leaf itself, - // then it is guaranteed by the prospective parachains - // subsystem that it is an ancestor of a leaf which - // has prospective parachains enabled and that the - // block itself did. - leaf_mode - }, - Some(l) => l.into(), - }; - // construct a `PerRelayParent` from the runtime API // and insert it. let per = construct_per_relay_parent_state( ctx, maybe_new, &state.keystore, - &mut state.validator_to_group_cache, - mode, + &mut state.per_session_cache, ) .await?; @@ -1084,52 +1135,47 @@ async fn construct_per_relay_parent_state( ctx: &mut Context, relay_parent: Hash, keystore: &KeystorePtr, - validator_to_group_cache: &mut LruMap< - SessionIndex, - Arc>>, - >, - mode: ProspectiveParachainsMode, + per_session_cache: &mut PerSessionCache, ) -> Result, Error> { let parent = relay_parent; - let (session_index, validators, groups, cores) = futures::try_join!( + let (session_index, groups, claim_queue, disabled_validators) = futures::try_join!( request_session_index_for_child(parent, ctx.sender()).await, - request_validators(parent, ctx.sender()).await, request_validator_groups(parent, ctx.sender()).await, - request_from_runtime(parent, ctx.sender(), |tx| { - RuntimeApiRequest::AvailabilityCores(tx) - },) - .await, + request_claim_queue(parent, ctx.sender()).await, + request_disabled_validators(parent, ctx.sender()).await, ) .map_err(Error::JoinMultiple)?; let session_index = try_runtime_api!(session_index); - let inject_core_index = request_node_features(parent, session_index, ctx.sender()) + let validators = per_session_cache.validators(session_index, parent, ctx.sender()).await; + let validators = try_runtime_api!(validators); + + let node_features = per_session_cache + .node_features(session_index, parent, ctx.sender()) .await? - .unwrap_or(NodeFeatures::EMPTY) + .unwrap_or(NodeFeatures::EMPTY); + + let inject_core_index = node_features .get(FeatureIndex::ElasticScalingMVP as usize) .map(|b| *b) .unwrap_or(false); + let executor_params = + per_session_cache.executor_params(session_index, parent, ctx.sender()).await; + let executor_params = try_runtime_api!(executor_params); + gum::debug!(target: LOG_TARGET, inject_core_index, ?parent, "New state"); - let validators: Vec<_> = try_runtime_api!(validators); let (validator_groups, group_rotation_info) = try_runtime_api!(groups); - let cores = try_runtime_api!(cores); - let minimum_backing_votes = - try_runtime_api!(request_min_backing_votes(parent, session_index, ctx.sender()).await); - - // TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 - // Once runtime ver `DISABLED_VALIDATORS_RUNTIME_REQUIREMENT` is released remove this call to - // `get_disabled_validators_with_fallback`, add `request_disabled_validators` call to the - // `try_join!` above and use `try_runtime_api!` to get `disabled_validators` - let disabled_validators = - get_disabled_validators_with_fallback(ctx.sender(), parent).await.map_err(|e| { - Error::UtilError(TryFrom::try_from(e).expect("the conversion is infallible; qed")) - })?; - let maybe_claim_queue = try_runtime_api!(fetch_claim_queue(ctx.sender(), parent).await); + let minimum_backing_votes = per_session_cache + .minimum_backing_votes(session_index, parent, ctx.sender()) + .await; + let minimum_backing_votes = try_runtime_api!(minimum_backing_votes); + let claim_queue = try_runtime_api!(claim_queue); + let disabled_validators = try_runtime_api!(disabled_validators); let signing_context = SigningContext { parent_hash: parent, session_index }; let validator = match Validator::construct( @@ -1151,33 +1197,15 @@ async fn construct_per_relay_parent_state( }, }; - let n_cores = cores.len(); + let n_cores = validator_groups.len(); let mut groups = HashMap::>::new(); let mut assigned_core = None; - let has_claim_queue = maybe_claim_queue.is_some(); - let mut claim_queue = maybe_claim_queue.unwrap_or_default().0; - - for (idx, core) in cores.iter().enumerate() { + for idx in 0..n_cores { let core_index = CoreIndex(idx as _); - if !has_claim_queue { - match core { - CoreState::Scheduled(scheduled) => - claim_queue.insert(core_index, [scheduled.para_id].into_iter().collect()), - CoreState::Occupied(occupied) if mode.is_enabled() => { - // Async backing makes it legal to build on top of - // occupied core. - if let Some(next) = &occupied.next_up_on_available { - claim_queue.insert(core_index, [next.para_id].into_iter().collect()) - } else { - continue - } - }, - _ => continue, - }; - } else if !claim_queue.contains_key(&core_index) { + if !claim_queue.contains_key(&core_index) { continue } @@ -1191,44 +1219,28 @@ async fn construct_per_relay_parent_state( } gum::debug!(target: LOG_TARGET, ?groups, "TableContext"); - let validator_to_group = validator_to_group_cache - .get_or_insert(session_index, || { - let mut vector = vec![None; validators.len()]; + let validator_to_group = + per_session_cache.validator_to_group(session_index, &validators, &validator_groups); - for (group_idx, validator_group) in validator_groups.iter().enumerate() { - for validator in validator_group { - vector[validator.0 as usize] = Some(GroupIndex(group_idx as u32)); - } - } - - Arc::new(IndexedVec::<_, _>::from(vector)) - }) - .expect("Just inserted"); - - let table_context = TableContext { validator, groups, validators, disabled_validators }; - let table_config = TableConfig { - allow_multiple_seconded: match mode { - ProspectiveParachainsMode::Enabled { .. } => true, - ProspectiveParachainsMode::Disabled => false, - }, - }; + let table_context = + TableContext { validator, groups, validators: validators.to_vec(), disabled_validators }; Ok(Some(PerRelayParentState { - prospective_parachains_mode: mode, parent, - session_index, + node_features, + executor_params, assigned_core, backed: HashSet::new(), - table: Table::new(table_config), + table: Table::new(), table_context, issued_statements: HashSet::new(), awaiting_validation: HashSet::new(), fallbacks: HashMap::new(), minimum_backing_votes, inject_core_index, - n_cores: cores.len() as u32, + n_cores: validator_groups.len() as u32, claim_queue: ClaimQueueSnapshot::from(claim_queue), - validator_to_group: validator_to_group.clone(), + validator_to_group, group_rotation_info, })) } @@ -1244,7 +1256,6 @@ enum SecondingAllowed { #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] async fn seconding_sanity_check( ctx: &mut Context, - active_leaves: &HashMap, implicit_view: &ImplicitView, hypothetical_candidate: HypotheticalCandidate, ) -> SecondingAllowed { @@ -1255,49 +1266,36 @@ async fn seconding_sanity_check( let candidate_relay_parent = hypothetical_candidate.relay_parent(); let candidate_hash = hypothetical_candidate.candidate_hash(); - for (head, leaf_state) in active_leaves { - if ProspectiveParachainsMode::from(leaf_state).is_enabled() { - // Check that the candidate relay parent is allowed for para, skip the - // leaf otherwise. - let allowed_parents_for_para = - implicit_view.known_allowed_relay_parents_under(head, Some(candidate_para)); - if !allowed_parents_for_para.unwrap_or_default().contains(&candidate_relay_parent) { - continue - } - - let (tx, rx) = oneshot::channel(); - ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalMembership( - HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(*head), - }, - tx, - )) - .await; - let response = rx.map_ok(move |candidate_memberships| { - let is_member_or_potential = candidate_memberships - .into_iter() - .find_map(|(candidate, leaves)| { - (candidate.candidate_hash() == candidate_hash).then_some(leaves) - }) - .and_then(|leaves| leaves.into_iter().find(|leaf| leaf == head)) - .is_some(); - - (is_member_or_potential, head) - }); - responses.push_back(response.boxed()); - } else { - if *head == candidate_relay_parent { - if let ActiveLeafState::ProspectiveParachainsDisabled { seconded } = leaf_state { - if seconded.contains(&candidate_para) { - // The leaf is already occupied. For non-prospective parachains, we only - // second one candidate. - return SecondingAllowed::No - } - } - responses.push_back(futures::future::ok((true, head)).boxed()); - } + for head in implicit_view.leaves() { + // Check that the candidate relay parent is allowed for para, skip the + // leaf otherwise. + let allowed_parents_for_para = + implicit_view.known_allowed_relay_parents_under(head, Some(candidate_para)); + if !allowed_parents_for_para.unwrap_or_default().contains(&candidate_relay_parent) { + continue } + + let (tx, rx) = oneshot::channel(); + ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalMembership( + HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(*head), + }, + tx, + )) + .await; + let response = rx.map_ok(move |candidate_memberships| { + let is_member_or_potential = candidate_memberships + .into_iter() + .find_map(|(candidate, leaves)| { + (candidate.candidate_hash() == candidate_hash).then_some(leaves) + }) + .and_then(|leaves| leaves.into_iter().find(|leaf| leaf == head)) + .is_some(); + + (is_member_or_potential, head) + }); + responses.push_back(response.boxed()); } if responses.is_empty() { @@ -1346,11 +1344,7 @@ async fn handle_can_second_request( tx: oneshot::Sender, ) { let relay_parent = request.candidate_relay_parent; - let response = if state - .per_relay_parent - .get(&relay_parent) - .map_or(false, |pr_state| pr_state.prospective_parachains_mode.is_enabled()) - { + let response = if state.per_relay_parent.get(&relay_parent).is_some() { let hypothetical_candidate = HypotheticalCandidate::Incomplete { candidate_hash: request.candidate_hash, candidate_para: request.candidate_para_id, @@ -1358,13 +1352,8 @@ async fn handle_can_second_request( candidate_relay_parent: relay_parent, }; - let result = seconding_sanity_check( - ctx, - &state.per_leaf, - &state.implicit_view, - hypothetical_candidate, - ) - .await; + let result = + seconding_sanity_check(ctx, &state.implicit_view, hypothetical_candidate).await; match result { SecondingAllowed::No => false, @@ -1417,16 +1406,14 @@ async fn handle_validated_candidate_command( // sanity check that we're allowed to second the candidate // and that it doesn't conflict with other candidates we've // seconded. - let hypothetical_membership = match seconding_sanity_check( + if let SecondingAllowed::No = seconding_sanity_check( ctx, - &state.per_leaf, &state.implicit_view, hypothetical_candidate, ) .await { - SecondingAllowed::No => return Ok(()), - SecondingAllowed::Yes(membership) => membership, + return Ok(()) }; let statement = @@ -1476,24 +1463,6 @@ async fn handle_validated_candidate_command( Some(p) => p.seconded_locally = true, } - // record seconded candidates for non-prospective-parachains mode. - for leaf in hypothetical_membership { - let leaf_data = match state.per_leaf.get_mut(&leaf) { - None => { - gum::warn!( - target: LOG_TARGET, - leaf_hash = ?leaf, - "Missing `per_leaf` for known active leaf." - ); - - continue - }, - Some(d) => d, - }; - - leaf_data.add_seconded_candidate(candidate.descriptor().para_id()); - } - rp_state.issued_statements.insert(candidate_hash); metrics.on_candidate_seconded(); @@ -1597,13 +1566,11 @@ fn sign_statement( /// Import a statement into the statement table and return the summary of the import. /// -/// This will fail with `Error::RejectedByProspectiveParachains` if the message type -/// is seconded, the candidate is fresh, -/// and any of the following are true: +/// This will fail with `Error::RejectedByProspectiveParachains` if the message type is seconded, +/// the candidate is fresh, and any of the following are true: /// 1. There is no `PersistedValidationData` attached. -/// 2. Prospective parachains are enabled for the relay parent and the prospective parachains -/// subsystem returned an empty `HypotheticalMembership` i.e. did not recognize the candidate as -/// being applicable to any of the active leaves. +/// 2. Prospective parachains subsystem returned an empty `HypotheticalMembership` i.e. did not +/// recognize the candidate as being applicable to any of the active leaves. #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] async fn import_statement( ctx: &mut Context, @@ -1624,8 +1591,7 @@ async fn import_statement( // If this is a new candidate (statement is 'seconded' and candidate is unknown), // we need to create an entry in the `PerCandidateState` map. // - // If the relay parent supports prospective parachains, we also need - // to inform the prospective parachains subsystem of the seconded candidate. + // We also need to inform the prospective parachains subsystem of the seconded candidate. // If `ProspectiveParachainsMessage::Second` fails, then we return // Error::RejectedByProspectiveParachains. // @@ -1636,30 +1602,28 @@ async fn import_statement( // our active leaves. if let StatementWithPVD::Seconded(candidate, pvd) = statement.payload() { if !per_candidate.contains_key(&candidate_hash) { - if rp_state.prospective_parachains_mode.is_enabled() { - let (tx, rx) = oneshot::channel(); - ctx.send_message(ProspectiveParachainsMessage::IntroduceSecondedCandidate( - IntroduceSecondedCandidateRequest { - candidate_para: candidate.descriptor.para_id(), - candidate_receipt: candidate.clone(), - persisted_validation_data: pvd.clone(), - }, - tx, - )) - .await; + let (tx, rx) = oneshot::channel(); + ctx.send_message(ProspectiveParachainsMessage::IntroduceSecondedCandidate( + IntroduceSecondedCandidateRequest { + candidate_para: candidate.descriptor.para_id(), + candidate_receipt: candidate.clone(), + persisted_validation_data: pvd.clone(), + }, + tx, + )) + .await; - match rx.await { - Err(oneshot::Canceled) => { - gum::warn!( - target: LOG_TARGET, - "Could not reach the Prospective Parachains subsystem." - ); + match rx.await { + Err(oneshot::Canceled) => { + gum::warn!( + target: LOG_TARGET, + "Could not reach the Prospective Parachains subsystem." + ); - return Err(Error::RejectedByProspectiveParachains) - }, - Ok(false) => return Err(Error::RejectedByProspectiveParachains), - Ok(true) => {}, - } + return Err(Error::RejectedByProspectiveParachains) + }, + Ok(false) => return Err(Error::RejectedByProspectiveParachains), + Ok(true) => {}, } // Only save the candidate if it was approved by prospective parachains. @@ -1722,28 +1686,15 @@ async fn post_import_statement_actions( "Candidate backed", ); - if rp_state.prospective_parachains_mode.is_enabled() { - // Inform the prospective parachains subsystem - // that the candidate is now backed. - ctx.send_message(ProspectiveParachainsMessage::CandidateBacked( - para_id, - candidate_hash, - )) - .await; - // Notify statement distribution of backed candidate. - ctx.send_message(StatementDistributionMessage::Backed(candidate_hash)).await; - } else { - // The provisioner waits on candidate-backing, which means - // that we need to send unbounded messages to avoid cycles. - // - // Backed candidates are bounded by the number of validators, - // parachains, and the block production rate of the relay chain. - let message = ProvisionerMessage::ProvisionableData( - rp_state.parent, - ProvisionableData::BackedCandidate(backed.receipt()), - ); - ctx.send_unbounded_message(message); - } + // Inform the prospective parachains subsystem + // that the candidate is now backed. + ctx.send_message(ProspectiveParachainsMessage::CandidateBacked( + para_id, + candidate_hash, + )) + .await; + // Notify statement distribution of backed candidate. + ctx.send_message(StatementDistributionMessage::Backed(candidate_hash)).await; } else { gum::debug!(target: LOG_TARGET, ?candidate_hash, "Cannot get BackedCandidate"); } @@ -1894,7 +1845,8 @@ async fn kick_off_validation_work( tx_command: background_validation_tx.clone(), candidate: attesting.candidate, relay_parent: rp_state.parent, - session_index: rp_state.session_index, + node_features: rp_state.node_features.clone(), + executor_params: Arc::clone(&rp_state.executor_params), persisted_validation_data, pov, n_validators: rp_state.table_context.validators.len(), @@ -2048,7 +2000,8 @@ async fn validate_and_second( tx_command: background_validation_tx.clone(), candidate: candidate.clone(), relay_parent: rp_state.parent, - session_index: rp_state.session_index, + node_features: rp_state.node_features.clone(), + executor_params: Arc::clone(&rp_state.executor_params), persisted_validation_data, pov: PoVData::Ready(pov), n_validators: rp_state.table_context.validators.len(), diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index dbb974a634fe..1a5fbeda100c 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -14,23 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use self::test_helpers::mock::new_leaf; use super::*; use assert_matches::assert_matches; use futures::{future, Future}; use polkadot_node_primitives::{BlockData, InvalidCandidate, SignedFullStatement, Statement}; use polkadot_node_subsystem::{ - errors::RuntimeApiError, messages::{ - AllMessages, CollatorProtocolMessage, PvfExecKind, RuntimeApiMessage, RuntimeApiRequest, - ValidationFailed, + AllMessages, ChainApiMessage, CollatorProtocolMessage, HypotheticalMembership, PvfExecKind, + RuntimeApiMessage, RuntimeApiRequest, ValidationFailed, }, - ActiveLeavesUpdate, FromOrchestra, OverseerSignal, TimeoutExt, + ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, TimeoutExt, }; -use polkadot_node_subsystem_test_helpers as test_helpers; +use polkadot_node_subsystem_test_helpers::mock::new_leaf; use polkadot_primitives::{ - node_features, vstaging::MutateDescriptorV2, CandidateDescriptor, GroupRotationInfo, HeadData, - PersistedValidationData, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, + node_features, + vstaging::{CoreState, MutateDescriptorV2, OccupiedCore}, + BlockNumber, CandidateDescriptor, GroupRotationInfo, HeadData, Header, PersistedValidationData, + ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; use polkadot_primitives_test_helpers::{ dummy_candidate_receipt_bad_sig, dummy_collator, dummy_collator_signature, @@ -47,10 +47,10 @@ use std::{ time::Duration, }; -mod prospective_parachains; - -const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = - RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; +struct TestLeaf { + activated: ActivatedLeaf, + min_relay_parents: Vec<(ParaId, u32)>, +} fn table_statement_to_primitive(statement: TableStatement) -> Statement { match statement { @@ -69,6 +69,14 @@ fn dummy_pvd() -> PersistedValidationData { } } +#[derive(Default)] +struct PerSessionCacheState { + has_cached_validators: bool, + has_cached_node_features: bool, + has_cached_executor_params: bool, + has_cached_minimum_backing_votes: bool, +} + pub(crate) struct TestState { chain_ids: Vec, keystore: KeystorePtr, @@ -85,6 +93,7 @@ pub(crate) struct TestState { minimum_backing_votes: u32, disabled_validators: Vec, node_features: NodeFeatures, + per_session_cache_state: PerSessionCacheState, } impl TestState { @@ -157,6 +166,7 @@ impl Default for TestState { chain_ids, keystore, validators, + per_session_cache_state: PerSessionCacheState::default(), validator_public, validator_groups: (validator_groups, group_rotation_info), validator_to_group, @@ -180,6 +190,8 @@ fn test_harness>( keystore: KeystorePtr, test: impl FnOnce(VirtualOverseer) -> T, ) { + sp_tracing::init_for_tests(); + let pool = sp_core::testing::TaskExecutor::new(); let (context, virtual_overseer) = @@ -250,176 +262,349 @@ impl TestCandidateBuilder { } } -// Tests that the subsystem performs actions that are required on startup. -async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestState) { - // Start work on some new parent. - virtual_overseer - .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( - new_leaf(test_state.relay_parent, 1), - )))) - .await; - +async fn assert_validation_request( + virtual_overseer: &mut VirtualOverseer, + validation_code: ValidationCode, +) { assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) + ) if hash == validation_code.hash() => { + tx.send(Ok(Some(validation_code))).unwrap(); } ); +} - // Check that subsystem job issues a request for the session index for child. +async fn assert_validate_from_exhaustive( + virtual_overseer: &mut VirtualOverseer, + assert_pvd: &PersistedValidationData, + assert_pov: &PoV, + assert_validation_code: &ValidationCode, + assert_candidate: &CommittedCandidateReceipt, + expected_head_data: &HeadData, + result_validation_data: PersistedValidationData, +) { assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + AllMessages::CandidateValidation( + CandidateValidationMessage::ValidateFromExhaustive { + pov, + validation_data, + validation_code, + candidate_receipt, + exec_kind, + response_sender, + .. + }, + ) if validation_data == *assert_pvd && + validation_code == *assert_validation_code && + *pov == *assert_pov && candidate_receipt.descriptor == assert_candidate.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && + candidate_receipt.commitments_hash == assert_candidate.commitments.hash() => + { + response_sender.send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: expected_head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + result_validation_data, + ))) + .unwrap(); } ); +} - // Check that subsystem job issues a request for a validator set. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.validator_public.clone())).unwrap(); - } - ); +// Activates the initial leaf and returns the `ParaId` used. This function is a prerequisite for all +// tests. +async fn activate_initial_leaf( + virtual_overseer: &mut VirtualOverseer, + test_state: &mut TestState, +) -> ParaId { + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let activated = new_leaf(test_state.relay_parent, LEAF_A_BLOCK_NUMBER - 1); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(virtual_overseer, test_leaf_a, test_state).await; + para_id +} - // Check that subsystem job issues a request for the validator groups. +async fn assert_candidate_is_shared_and_seconded( + virtual_overseer: &mut VirtualOverseer, + relay_parent: &Hash, +) { assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.validator_groups.clone())).unwrap(); - } + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == *relay_parent => {} ); - // Check that subsystem job issues a request for the availability cores. assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(*relay_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); } ); +} - // Node features request from runtime: all features are disabled. +async fn assert_candidate_is_shared_and_backed( + virtual_overseer: &mut VirtualOverseer, + relay_parent: &Hash, + expected_para_id: &ParaId, + expected_candidate_hash: &CandidateHash, +) { assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_parent, RuntimeApiRequest::NodeFeatures(_session_index, tx)) + AllMessages::StatementDistribution( + StatementDistributionMessage::Share(hash, _stmt) ) => { - tx.send(Ok(test_state.node_features.clone())).unwrap(); - } - ); - - // Check if subsystem job issues a request for the minimum backing votes. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - parent, - RuntimeApiRequest::MinimumBackingVotes(session_index, tx), - )) if parent == test_state.relay_parent && session_index == test_state.signing_context.session_index => { - tx.send(Ok(test_state.minimum_backing_votes)).unwrap(); - } - ); - - // Check that subsystem job issues a request for the runtime version. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Version(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT)).unwrap(); + assert_eq!(*relay_parent, hash); } ); - // Check that subsystem job issues a request for the disabled validators. assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::DisabledValidators(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(test_state.disabled_validators.clone())).unwrap(); - } + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked( + candidate_para_id, candidate_hash + ), + ) if *expected_candidate_hash == candidate_hash && candidate_para_id == *expected_para_id ); assert_matches!( virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Version(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)).unwrap(); - } + AllMessages::StatementDistribution(StatementDistributionMessage::Backed ( + candidate_hash + )) if *expected_candidate_hash == candidate_hash ); +} - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ClaimQueue(tx)) - ) if parent == test_state.relay_parent => { - tx.send(Ok( - test_state.claim_queue.clone() - )).unwrap(); - } - ); +fn get_parent_hash(hash: Hash) -> Hash { + Hash::from_low_u64_be(hash.to_low_u64_be() + 1) } -async fn assert_validation_requests( +async fn activate_leaf( virtual_overseer: &mut VirtualOverseer, - validation_code: ValidationCode, + leaf: TestLeaf, + test_state: &mut TestState, ) { - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::ValidationCodeByHash(hash, tx)) - ) if hash == validation_code.hash() => { - tx.send(Ok(Some(validation_code))).unwrap(); + let TestLeaf { activated, min_relay_parents } = leaf; + let leaf_hash = activated.hash; + let leaf_number = activated.number; + // Start work on some new parent. + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( + activated, + )))) + .await; + + let min_min = *min_relay_parents + .iter() + .map(|(_, block_num)| block_num) + .min() + .unwrap_or(&leaf_number); + + let ancestry_len = leaf_number + 1 - min_min; + + let ancestry_hashes = std::iter::successors(Some(leaf_hash), |h| Some(get_parent_hash(*h))) + .take(ancestry_len as usize); + let ancestry_numbers = (min_min..=leaf_number).rev(); + let ancestry_iter = ancestry_hashes.zip(ancestry_numbers).peekable(); + + let mut next_overseer_message = None; + // How many blocks were actually requested. + let mut requested_len = 0; + { + let mut ancestry_iter = ancestry_iter.clone(); + while let Some((hash, number)) = ancestry_iter.next() { + // May be `None` for the last element. + let parent_hash = + ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); + + let msg = virtual_overseer.recv().await; + // It may happen that some blocks were cached by implicit view, + // reuse the message. + if !matches!(&msg, AllMessages::ChainApi(ChainApiMessage::BlockHeader(..))) { + next_overseer_message.replace(msg); + break + } + + assert_matches!( + msg, + AllMessages::ChainApi( + ChainApiMessage::BlockHeader(_hash, tx) + ) if _hash == hash => { + let header = Header { + parent_hash, + number, + state_root: Hash::zero(), + extrinsics_root: Hash::zero(), + digest: Default::default(), + }; + + tx.send(Ok(Some(header))).unwrap(); + } + ); + + if requested_len == 0 { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetMinimumRelayParents(parent, tx) + ) if parent == leaf_hash => { + tx.send(min_relay_parents.clone()).unwrap(); + } + ); + } + + requested_len += 1; } - ); + } - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionIndexForChild(tx)) - ) => { - tx.send(Ok(1u32.into())).unwrap(); + for (hash, number) in ancestry_iter.take(requested_len) { + let msg = match next_overseer_message.take() { + Some(msg) => msg, + None => virtual_overseer.recv().await, + }; + + // Check that subsystem job issues a request for the session index for child. + assert_matches!( + msg, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.signing_context.session_index)).unwrap(); + } + ); + + // Check that subsystem job issues a request for the validator groups. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx)) + ) if parent == hash => { + let (validator_groups, mut group_rotation_info) = test_state.validator_groups.clone(); + group_rotation_info.now = number; + tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ClaimQueue(tx)) + ) if parent == hash => { + tx.send(Ok( + test_state.claim_queue.clone() + )).unwrap(); + } + ); + + // Check that the subsystem job issues a request for the disabled validators. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::DisabledValidators(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.disabled_validators.clone())).unwrap(); + } + ); + + if !test_state.per_session_cache_state.has_cached_validators { + // Check that subsystem job issues a request for a validator set. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) + ) if parent == hash => { + tx.send(Ok(test_state.validator_public.clone())).unwrap(); + } + ); + test_state.per_session_cache_state.has_cached_validators = true; } - ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::SessionExecutorParams(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + if !test_state.per_session_cache_state.has_cached_node_features { + // Node features request from runtime: all features are disabled. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::NodeFeatures(_session_index, tx)) + ) if parent == hash => { + tx.send(Ok(test_state.node_features.clone())).unwrap(); + } + ); + test_state.per_session_cache_state.has_cached_node_features = true; } - ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(sess_idx, tx)) - ) if sess_idx == 1 => { - tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + if !test_state.per_session_cache_state.has_cached_executor_params { + // Check if subsystem job issues a request for the executor parameters. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionExecutorParams(_session_index, tx)) + ) if parent == hash => { + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + test_state.per_session_cache_state.has_cached_executor_params = true; } - ); + + if !test_state.per_session_cache_state.has_cached_minimum_backing_votes { + // Check if subsystem job issues a request for the minimum backing votes. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::MinimumBackingVotes(session_index, tx), + )) if parent == hash && session_index == test_state.signing_context.session_index => { + tx.send(Ok(test_state.minimum_backing_votes)).unwrap(); + } + ); + test_state.per_session_cache_state.has_cached_minimum_backing_votes = true; + } + } } -async fn assert_validate_from_exhaustive( +async fn assert_validate_seconded_candidate( virtual_overseer: &mut VirtualOverseer, - assert_pvd: &PersistedValidationData, + relay_parent: Hash, + candidate: &CommittedCandidateReceipt, assert_pov: &PoV, + assert_pvd: &PersistedValidationData, assert_validation_code: &ValidationCode, - assert_candidate: &CommittedCandidateReceipt, expected_head_data: &HeadData, - result_validation_data: PersistedValidationData, + fetch_pov: bool, ) { + assert_validation_request(virtual_overseer, assert_validation_code.clone()).await; + + if fetch_pov { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::AvailabilityDistribution( + AvailabilityDistributionMessage::FetchPoV { + relay_parent: hash, + tx, + .. + } + ) if hash == relay_parent => { + tx.send(assert_pov.clone()).unwrap(); + } + ); + } + assert_matches!( virtual_overseer.recv().await, AllMessages::CandidateValidation( @@ -434,9 +619,9 @@ async fn assert_validate_from_exhaustive( }, ) if validation_data == *assert_pvd && validation_code == *assert_validation_code && - *pov == *assert_pov && candidate_receipt.descriptor == assert_candidate.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && - candidate_receipt.commitments_hash == assert_candidate.commitments.hash() => + *pov == *assert_pov && candidate_receipt.descriptor == candidate.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && + candidate_receipt.commitments_hash == candidate.commitments.hash() => { response_sender.send(Ok(ValidationResult::Valid( CandidateCommitments { @@ -447,30 +632,79 @@ async fn assert_validate_from_exhaustive( processed_downward_messages: 0, hrmp_watermark: 0, }, - result_validation_data, + assert_pvd.clone(), ))) .unwrap(); } ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::AvailabilityStore( + AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } + ) if candidate_hash == candidate.hash() => { + tx.send(Ok(())).unwrap(); + } + ); +} + +pub(crate) async fn assert_hypothetical_membership_requests( + virtual_overseer: &mut VirtualOverseer, + mut expected_requests: Vec<( + HypotheticalMembershipRequest, + Vec<(HypotheticalCandidate, HypotheticalMembership)>, + )>, +) { + // Requests come with no particular order. + let requests_num = expected_requests.len(); + + for _ in 0..requests_num { + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetHypotheticalMembership(request, tx), + ) => { + let idx = match expected_requests.iter().position(|r| r.0 == request) { + Some(idx) => idx, + None => + panic!( + "unexpected hypothetical membership request, no match found for {:?}", + request + ), + }; + let resp = std::mem::take(&mut expected_requests[idx].1); + tx.send(resp).unwrap(); + + expected_requests.remove(idx); + } + ); + } +} + +pub(crate) fn make_hypothetical_membership_response( + hypothetical_candidate: HypotheticalCandidate, + relay_parent_hash: Hash, +) -> Vec<(HypotheticalCandidate, HypotheticalMembership)> { + vec![(hypothetical_candidate, vec![relay_parent_hash])] } -// Test that a `CandidateBackingMessage::Second` issues validation work -// and in case validation is successful issues a `StatementDistributionMessage`. +// Test that a `CandidateBackingMessage::Second` issues validation work and in case validation is +// successful issues correct messages. #[test] fn backing_second_works() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); let validation_code = ValidationCode(vec![1, 2, 3]); - let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); let pov_hash = pov.hash(); let candidate = TestCandidateBuilder { - para_id: test_state.chain_ids[0], + para_id, relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), @@ -489,46 +723,53 @@ fn backing_second_works() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; - - assert_validate_from_exhaustive( + assert_validate_seconded_candidate( &mut virtual_overseer, - &pvd, + test_state.relay_parent, + &candidate, &pov, + &pvd, &validation_code, - &candidate, expected_head_data, - test_state.validation_data.clone(), + false, ) .await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate.hash() => { - tx.send(Ok(())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == test_state.relay_parent => {} - ); + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(test_state.relay_parent), + }; + let expected_response = + make_hypothetical_membership_response(hypothetical_candidate, test_state.relay_parent); + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![(expected_request, expected_response)], + ) + .await; assert_matches!( virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(test_state.relay_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); } ); + assert_candidate_is_shared_and_seconded(&mut virtual_overseer, &test_state.relay_parent) + .await; + virtual_overseer .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( ActiveLeavesUpdate::stop_work(test_state.relay_parent), @@ -554,7 +795,7 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { } test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_ab = PoV { block_data: BlockData(vec![1, 2, 3]) }; let pvd_ab = dummy_pvd(); @@ -562,10 +803,10 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { let pov_hash = pov_ab.hash(); - let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); let candidate_a = TestCandidateBuilder { - para_id: test_state.chain_ids[0], + para_id, relay_parent: test_state.relay_parent, pov_hash, head_data: expected_head_data.clone(), @@ -576,7 +817,6 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { .build(); let candidate_a_hash = candidate_a.hash(); - let candidate_a_commitments_hash = candidate_a.commitments.hash(); let public1 = Keystore::sr25519_generate_new( &*test_state.keystore, @@ -618,85 +858,40 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_ab.clone()).await; - - // Sending a `Statement::Seconded` for our assignment will start - // validation process. The first thing requested is the PoV. assert_matches!( virtual_overseer.recv().await, - AllMessages::AvailabilityDistribution( - AvailabilityDistributionMessage::FetchPoV { - relay_parent, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, tx, - .. - } - ) if relay_parent == test_state.relay_parent => { - tx.send(pov_ab.clone()).unwrap(); - } - ); - - // The next step is the actual request to Validation subsystem - // to validate the `Seconded` candidate. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { - validation_data, - validation_code, - candidate_receipt, - pov, - exec_kind, - response_sender, - .. - }, - ) if validation_data == pvd_ab && - validation_code == validation_code_ab && - *pov == pov_ab && candidate_receipt.descriptor == candidate_a.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && - candidate_receipt.commitments_hash == candidate_a_commitments_hash => - { - response_sender.send(Ok( - ValidationResult::Valid(CandidateCommitments { - head_data: expected_head_data.clone(), - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, test_state.validation_data.clone()), - )).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate_a.hash() => { - tx.send(Ok(())).unwrap(); + ), + ) if + req.candidate_receipt == candidate_a + && req.candidate_para == para_id + && pvd_ab == req.persisted_validation_data => { + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share(hash, _stmt) - ) => { - assert_eq!(test_state.relay_parent, hash); - } - ); + assert_validate_seconded_candidate( + &mut virtual_overseer, + candidate_a.descriptor.relay_parent(), + &candidate_a, + &pov_ab, + &pvd_ab, + &validation_code_ab, + expected_head_data, + true, + ) + .await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(candidate_receipt) - ) - ) => { - assert_eq!(candidate_receipt, candidate_a.to_plain()); - } - ); + assert_candidate_is_shared_and_backed( + &mut virtual_overseer, + &test_state.relay_parent, + ¶_id, + &candidate_a_hash, + ) + .await; let statement = CandidateBackingMessage::Statement(test_state.relay_parent, signed_b.clone()); @@ -772,7 +967,7 @@ fn get_backed_candidate_preserves_order() { .insert(CoreIndex(2), [test_state.chain_ids[1]].into_iter().collect()); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_a = PoV { block_data: BlockData(vec![1, 2, 3]) }; let pov_b = PoV { block_data: BlockData(vec![3, 4, 5]) }; @@ -881,17 +1076,37 @@ fn get_backed_candidate_preserves_order() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + // Prospective parachains are notified about candidate seconded first. assert_matches!( virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(candidate_receipt) - ) - ) => { - assert_eq!(candidate_receipt, candidate.to_plain()); + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == candidate.descriptor.para_id() + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); } ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked( + candidate_para_id, candidate_hash + ), + ) if candidate.hash() == candidate_hash && candidate_para_id == candidate.descriptor.para_id() + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution(StatementDistributionMessage::Backed ( + candidate_hash + )) if candidate.hash() == candidate_hash + ); } // Happy case, all candidates should be present. @@ -1171,9 +1386,9 @@ fn extract_core_index_from_statement_works() { #[test] fn backing_works_while_validation_ongoing() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_abc = PoV { block_data: BlockData(vec![1, 2, 3]) }; let pvd_abc = dummy_pvd(); @@ -1253,7 +1468,22 @@ fn backing_works_while_validation_ongoing() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_abc.clone()).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate_a + && req.candidate_para == para_id + && pvd_abc == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_validation_request(&mut virtual_overseer, validation_code_abc.clone()).await; // Sending a `Statement::Seconded` for our assignment will start // validation process. The first thing requested is PoV from the @@ -1288,7 +1518,7 @@ fn backing_works_while_validation_ongoing() { ) if validation_data == pvd_abc && validation_code == validation_code_abc && *pov == pov_abc && candidate_receipt.descriptor == candidate_a.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { // we never validate the candidate. our local node @@ -1305,15 +1535,11 @@ fn backing_works_while_validation_ongoing() { // Candidate gets backed entirely by other votes. assert_matches!( virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(CandidateReceipt { - descriptor, - .. - }) - ) - ) if descriptor == candidate_a.descriptor + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked( + candidate_para_id, candidate_hash + ), + ) if candidate_a_hash == candidate_hash && candidate_para_id == para_id ); let statement = @@ -1362,13 +1588,12 @@ fn backing_works_while_validation_ongoing() { }); } -// Issuing conflicting statements on the same candidate should -// be a misbehavior. +// Issuing conflicting statements on the same candidate should be a misbehavior. #[test] fn backing_misbehavior_works() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_a = PoV { block_data: BlockData(vec![1, 2, 3]) }; @@ -1390,8 +1615,6 @@ fn backing_misbehavior_works() { .build(); let candidate_a_hash = candidate_a.hash(); - let candidate_a_commitments_hash = candidate_a.commitments.hash(); - let public2 = Keystore::sr25519_generate_new( &*test_state.keystore, ValidatorId::ID, @@ -1425,85 +1648,41 @@ fn backing_misbehavior_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; - + // Prospective parachains are notified about candidate seconded first. assert_matches!( virtual_overseer.recv().await, - AllMessages::AvailabilityDistribution( - AvailabilityDistributionMessage::FetchPoV { - relay_parent, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, tx, - .. - } - ) if relay_parent == test_state.relay_parent => { - tx.send(pov_a.clone()).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { - validation_data, - validation_code, - candidate_receipt, - pov, - exec_kind, - response_sender, - .. - }, - ) if validation_data == pvd_a && - validation_code == validation_code_a && - *pov == pov_a && candidate_receipt.descriptor == candidate_a.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && - candidate_a_commitments_hash == candidate_receipt.commitments_hash => - { - response_sender.send(Ok( - ValidationResult::Valid(CandidateCommitments { - head_data: expected_head_data.clone(), - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, test_state.validation_data.clone()), - )).unwrap(); + ), + ) if + req.candidate_receipt == candidate_a + && req.candidate_para == para_id + && pvd_a == req.persisted_validation_data => { + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate_a.hash() => { - tx.send(Ok(())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - relay_parent, - signed_statement, - ) - ) if relay_parent == test_state.relay_parent => { - assert_eq!(*signed_statement.payload(), StatementWithPVD::Valid(candidate_a_hash)); - } - ); + assert_validate_seconded_candidate( + &mut virtual_overseer, + test_state.relay_parent, + &candidate_a, + &pov_a, + &pvd_a, + &validation_code_a, + expected_head_data, + true, + ) + .await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(CandidateReceipt { - descriptor, - .. - }) - ) - ) if descriptor == candidate_a.descriptor - ); + assert_candidate_is_shared_and_backed( + &mut virtual_overseer, + &test_state.relay_parent, + ¶_id, + &candidate_a_hash, + ) + .await; // This `Valid` statement is redundant after the `Seconded` statement already sent. let statement = @@ -1548,13 +1727,13 @@ fn backing_misbehavior_works() { }); } -// Test that if we are asked to second an invalid candidate we -// can still second a valid one afterwards. +// Test that if we are asked to second an invalid candidate we can still second a valid one +// afterwards. #[test] -fn backing_dont_second_invalid() { - let test_state = TestState::default(); +fn backing_doesnt_second_invalid() { + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_block_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd_a = dummy_pvd(); @@ -1605,7 +1784,7 @@ fn backing_dont_second_invalid() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; + assert_validation_request(&mut virtual_overseer, validation_code_a.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1622,7 +1801,7 @@ fn backing_dont_second_invalid() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_block_a && candidate_receipt.descriptor == candidate_a.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate_a.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1645,38 +1824,18 @@ fn backing_dont_second_invalid() { virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_b.clone()).await; + assert_validation_request(&mut virtual_overseer, validation_code_b.clone()).await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { - validation_data, - validation_code, - candidate_receipt, - pov, - exec_kind, - response_sender, - .. - }, - ) if validation_data == pvd_b && - validation_code == validation_code_b && - *pov == pov_block_b && candidate_receipt.descriptor == candidate_b.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && - candidate_b.commitments.hash() == candidate_receipt.commitments_hash => - { - response_sender.send(Ok( - ValidationResult::Valid(CandidateCommitments { - head_data: expected_head_data.clone(), - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, pvd_b.clone()), - )).unwrap(); - } - ); + assert_validate_from_exhaustive( + &mut virtual_overseer, + &pvd_b, + &pov_block_b, + &validation_code_b, + &candidate_b, + expected_head_data, + test_state.validation_data.clone(), + ) + .await; assert_matches!( virtual_overseer.recv().await, @@ -1687,15 +1846,42 @@ fn backing_dont_second_invalid() { } ); + let hypothetical_candidate_b = HypotheticalCandidate::Complete { + candidate_hash: candidate_b.hash(), + receipt: Arc::new(candidate_b.clone()), + persisted_validation_data: pvd_a.clone(), // ??? + }; + let expected_request_b = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate_b.clone()], + fragment_chain_relay_parent: Some(test_state.relay_parent), + }; + let expected_response_b = make_hypothetical_membership_response( + hypothetical_candidate_b.clone(), + test_state.relay_parent, + ); + + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![ + // (expected_request_a, expected_response_a), + (expected_request_b, expected_response_b), + ], + ) + .await; + + // Prospective parachains are notified. assert_matches!( virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - signed_statement, - ) - ) if parent_hash == test_state.relay_parent => { - assert_eq!(*signed_statement.payload(), StatementWithPVD::Seconded(candidate_b, pvd_b.clone())); + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) => { + assert_eq!(req.candidate_receipt, candidate_b); + assert_eq!(req.candidate_para, para_id); + assert_eq!(pvd_a, req.persisted_validation_data); // ??? + tx.send(true).unwrap(); } ); @@ -1708,13 +1894,13 @@ fn backing_dont_second_invalid() { }); } -// Test that if we have already issued a statement (in this case `Invalid`) about a -// candidate we will not be issuing a `Seconded` statement on it. +// Test that if we have already issued a statement (in this case `Invalid`) about a candidate we +// will not be issuing a `Seconded` statement on it. #[test] fn backing_second_after_first_fails_works() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd_a = dummy_pvd(); @@ -1757,7 +1943,22 @@ fn backing_second_after_first_fails_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd_a == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_validation_request(&mut virtual_overseer, validation_code_a.clone()).await; // Subsystem requests PoV and requests validation. assert_matches!( @@ -1789,7 +1990,7 @@ fn backing_second_after_first_fails_works() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && candidate_receipt.descriptor == candidate.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1840,7 +2041,7 @@ fn backing_second_after_first_fails_works() { // triggered on the prev step. virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_to_second.clone()).await; + assert_validation_request(&mut virtual_overseer, validation_code_to_second.clone()).await; assert_matches!( virtual_overseer.recv().await, @@ -1854,13 +2055,13 @@ fn backing_second_after_first_fails_works() { }); } -// That that if the validation of the candidate has failed this does not stop -// the work of this subsystem and so it is not fatal to the node. +// Test that if the validation of the candidate has failed this does not stop the work of this +// subsystem and so it is not fatal to the node. #[test] fn backing_works_after_failed_validation() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd_a = dummy_pvd(); @@ -1901,7 +2102,22 @@ fn backing_works_after_failed_validation() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd_a == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_validation_request(&mut virtual_overseer, validation_code_a.clone()).await; // Subsystem requests PoV and requests validation. assert_matches!( @@ -1933,7 +2149,7 @@ fn backing_works_after_failed_validation() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && candidate_receipt.descriptor == candidate.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); @@ -2036,16 +2252,16 @@ fn candidate_backing_reorders_votes() { // Test whether we retry on failed PoV fetching. #[test] fn retry_works() { - // sp_tracing::try_init_simple(); - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd_a = dummy_pvd(); let validation_code_a = ValidationCode(vec![1, 2, 3]); let pov_hash = pov_a.hash(); + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); let candidate = TestCandidateBuilder { para_id: test_state.chain_ids[0], @@ -2054,7 +2270,7 @@ fn retry_works() { erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), persisted_validation_data_hash: pvd_a.hash(), validation_code: validation_code_a.0.clone(), - ..Default::default() + head_data: expected_head_data.clone(), } .build(); @@ -2112,7 +2328,22 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_a.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd_a == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_validation_request(&mut virtual_overseer, validation_code_a.clone()).await; // Subsystem requests PoV and requests validation. // We cancel - should mean retry on next backing statement. @@ -2134,43 +2365,31 @@ fn retry_works() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; // Not deterministic which message comes first: - for _ in 0u32..6 { + for _ in 0u32..3 { match virtual_overseer.recv().await { - AllMessages::Provisioner(ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(CandidateReceipt { descriptor, .. }), - )) => { - assert_eq!(descriptor, candidate.descriptor); + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked( + candidate_para_id, + candidate_hash, + ), + ) if candidate_hash == candidate_hash && candidate_para_id == para_id => { + assert_eq!(candidate_para_id, para_id); + assert_eq!(candidate_hash, candidate.hash()); }, AllMessages::AvailabilityDistribution( AvailabilityDistributionMessage::FetchPoV { relay_parent, tx, .. }, ) if relay_parent == test_state.relay_parent => { std::mem::drop(tx); }, + AllMessages::StatementDistribution(StatementDistributionMessage::Backed( + candidate_hash, + )) if candidate_hash == candidate.hash() => {}, AllMessages::RuntimeApi(RuntimeApiMessage::Request( _, RuntimeApiRequest::ValidationCodeByHash(hash, tx), )) if hash == validation_code_a.hash() => { tx.send(Ok(Some(validation_code_a.clone()))).unwrap(); }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::SessionIndexForChild(tx), - )) => { - tx.send(Ok(1u32.into())).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::SessionExecutorParams(1, tx), - )) => { - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::NodeFeatures(1, tx), - )) => { - tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); - }, msg => { assert!(false, "Unexpected message: {:?}", msg); }, @@ -2181,8 +2400,6 @@ fn retry_works() { CandidateBackingMessage::Statement(test_state.relay_parent, signed_c.clone()); virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - assert_validation_requests(&mut virtual_overseer, validation_code_a.clone()).await; - assert_matches!( virtual_overseer.recv().await, AllMessages::AvailabilityDistribution( @@ -2212,7 +2429,7 @@ fn retry_works() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && candidate_receipt.descriptor == candidate.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate.commitments.hash() == candidate_receipt.commitments_hash ); virtual_overseer @@ -2221,10 +2438,10 @@ fn retry_works() { #[test] fn observes_backing_even_if_not_validator() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); let empty_keystore = Arc::new(sc_keystore::LocalKeystore::in_memory()); test_harness(empty_keystore, |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; let pvd = dummy_pvd(); @@ -2305,6 +2522,22 @@ fn observes_backing_even_if_not_validator() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + // Prospective parachains are notified about candidate seconded first. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate_a + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + let statement = CandidateBackingMessage::Statement(test_state.relay_parent, signed_b.clone()); @@ -2312,14 +2545,11 @@ fn observes_backing_even_if_not_validator() { assert_matches!( virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(candidate_receipt) - ) - ) => { - assert_eq!(candidate_receipt, candidate_a.to_plain()); - } + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked( + candidate_para_id, candidate_hash + ), + ) if candidate_a_hash == candidate_hash && candidate_para_id == para_id ); let statement = @@ -2336,157 +2566,29 @@ fn observes_backing_even_if_not_validator() { }); } -// Tests that it's impossible to second multiple candidates per relay parent -// without prospective parachains. #[test] -fn cannot_second_multiple_candidates_per_parent() { - let test_state = TestState::default(); +fn new_leaf_view_doesnt_clobber_old() { + let mut test_state = TestState::default(); + let relay_parent_2 = Hash::repeat_byte(1); + assert_ne!(test_state.relay_parent, relay_parent_2); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); - - let pov_hash = pov.hash(); - let candidate_builder = TestCandidateBuilder { - para_id: test_state.chain_ids[0], - relay_parent: test_state.relay_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - }; - let candidate = candidate_builder.clone().build(); - - let second = CandidateBackingMessage::Second( - test_state.relay_parent, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; - - assert_validate_from_exhaustive( - &mut virtual_overseer, - &pvd, - &pov, - &validation_code, - &candidate, - expected_head_data, - test_state.validation_data.clone(), - ) - .await; - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate.hash() => { - tx.send(Ok(())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == test_state.relay_parent => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(test_state.relay_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - - // Try to second candidate with the same relay parent again. - - // Make sure the candidate hash is different. - let validation_code = ValidationCode(vec![4, 5, 6]); - let mut candidate_builder = candidate_builder; - candidate_builder.validation_code = validation_code.0.clone(); - let candidate = candidate_builder.build(); - - let second = CandidateBackingMessage::Second( - test_state.relay_parent, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - // The validation is still requested. - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { response_sender, .. }, - ) => { - response_sender.send(Ok(ValidationResult::Valid( - CandidateCommitments { - head_data: expected_head_data.clone(), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, - test_state.validation_data.clone(), - ))) - .unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate.hash() => { - tx.send(Ok(())).unwrap(); - } - ); - - // Validation done, but the candidate is rejected cause of 0-depth being already occupied. - - assert!(virtual_overseer - .recv() - .timeout(std::time::Duration::from_millis(50)) - .await - .is_none()); - - virtual_overseer - }); -} - -#[test] -fn new_leaf_view_doesnt_clobber_old() { - let mut test_state = TestState::default(); - let relay_parent_2 = Hash::repeat_byte(1); - assert_ne!(test_state.relay_parent, relay_parent_2); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; - - // New leaf that doesn't clobber old. - { - let old_relay_parent = test_state.relay_parent; - test_state.relay_parent = relay_parent_2; - test_startup(&mut virtual_overseer, &test_state).await; - test_state.relay_parent = old_relay_parent; - } + activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; + + // New leaf that doesn't clobber old. + { + let old_relay_parent = test_state.relay_parent; + test_state.relay_parent = relay_parent_2; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = 101; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + let activated = new_leaf(test_state.relay_parent, LEAF_B_BLOCK_NUMBER - 1); + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_b, &mut test_state).await; + test_state.relay_parent = old_relay_parent; + } let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -2537,7 +2639,7 @@ fn disabled_validator_doesnt_distribute_statement_on_receiving_second() { test_state.disabled_validators.push(ValidatorIndex(0)); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -2585,7 +2687,7 @@ fn disabled_validator_doesnt_distribute_statement_on_receiving_statement() { test_state.disabled_validators.push(ValidatorIndex(0)); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -2627,6 +2729,21 @@ fn disabled_validator_doesnt_distribute_statement_on_receiving_statement() { virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + // Ensure backing subsystem is not doing any work assert_matches!(virtual_overseer.recv().timeout(Duration::from_secs(1)).await, None); @@ -2647,7 +2764,7 @@ fn validator_ignores_statements_from_disabled_validators() { test_state.disabled_validators.push(ValidatorIndex(2)); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - test_startup(&mut virtual_overseer, &test_state).await; + let para_id = activate_initial_leaf(&mut virtual_overseer, &mut test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -2666,7 +2783,6 @@ fn validator_ignores_statements_from_disabled_validators() { validation_code: validation_code.0.clone(), } .build(); - let candidate_commitments_hash = candidate.commitments.hash(); let public2 = Keystore::sr25519_generate_new( &*test_state.keystore, @@ -2718,93 +2834,1198 @@ fn validator_ignores_statements_from_disabled_validators() { virtual_overseer.send(FromOrchestra::Communication { msg: statement_3 }).await; - assert_validation_requests(&mut virtual_overseer, validation_code.clone()).await; - - // Sending a `Statement::Seconded` for our assignment will start - // validation process. The first thing requested is the PoV. + // Prospective parachains are notified about candidate seconded first. assert_matches!( virtual_overseer.recv().await, - AllMessages::AvailabilityDistribution( - AvailabilityDistributionMessage::FetchPoV { - relay_parent, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, tx, - .. - } - ) if relay_parent == test_state.relay_parent => { - tx.send(pov.clone()).unwrap(); + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); } ); - // The next step is the actual request to Validation subsystem - // to validate the `Seconded` candidate. - let expected_pov = pov; - let expected_validation_code = validation_code; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { - validation_data, - validation_code, - candidate_receipt, - pov, - executor_params: _, - exec_kind, - response_sender, - } - ) if validation_data == pvd && - validation_code == expected_validation_code && - *pov == expected_pov && candidate_receipt.descriptor == candidate.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && - candidate_commitments_hash == candidate_receipt.commitments_hash => - { - response_sender.send(Ok( - ValidationResult::Valid(CandidateCommitments { - head_data: expected_head_data.clone(), - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, test_state.validation_data.clone()), - )).unwrap(); - } - ); + assert_validate_seconded_candidate( + &mut virtual_overseer, + test_state.relay_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + true, + ) + .await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate.hash() => { - tx.send(Ok(())).unwrap(); - } - ); + assert_candidate_is_shared_and_backed( + &mut virtual_overseer, + &test_state.relay_parent, + ¶_id, + &candidate.hash(), + ) + .await; - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share(hash, _stmt) - ) => { - assert_eq!(test_state.relay_parent, hash); - } + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( + ActiveLeavesUpdate::stop_work(test_state.relay_parent), + ))) + .await; + virtual_overseer + }); +} + +// Test that `seconding_sanity_check` works when a candidate is allowed +// for all leaves. +#[test] +fn seconding_sanity_check_allowed_on_all() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + // `a` is grandparent of `b`. + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; + + let leaf_b_hash = Hash::from_low_u64_be(128); + let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + activate_leaf(&mut virtual_overseer, test_leaf_b, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), ); + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }; + let expected_response_a = + make_hypothetical_membership_response(hypothetical_candidate.clone(), leaf_a_hash); + let expected_request_b = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_b_hash), + }; + let expected_response_b = + make_hypothetical_membership_response(hypothetical_candidate, leaf_b_hash); + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![ + (expected_request_a, expected_response_a), + (expected_request_b, expected_response_b), + ], + ) + .await; + // Prospective parachains are notified. assert_matches!( virtual_overseer.recv().await, - AllMessages::Provisioner( - ProvisionerMessage::ProvisionableData( - _, - ProvisionableData::BackedCandidate(candidate_receipt) - ) - ) => { - assert_eq!(candidate_receipt, candidate.to_plain()); + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); } ); + assert_candidate_is_shared_and_seconded(&mut virtual_overseer, &leaf_a_parent).await; + virtual_overseer - .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( - ActiveLeavesUpdate::stop_work(test_state.relay_parent), - ))) - .await; + }); +} + +// Test that `seconding_sanity_check` disallows seconding when a candidate is disallowed +// for all leaves. +#[test] +fn seconding_sanity_check_disallowed() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_b_hash = Hash::from_low_u64_be(128); + // `a` is grandparent of `b`. + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; + + let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap().clone(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + &expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }; + let expected_response_a = + make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash); + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![(expected_request_a, expected_response_a)], + ) + .await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_candidate_is_shared_and_seconded(&mut virtual_overseer, &leaf_a_parent).await; + + activate_leaf(&mut virtual_overseer, test_leaf_b, &mut test_state).await; + let leaf_a_grandparent = get_parent_hash(leaf_a_parent); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_grandparent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_grandparent, + &candidate, + &pov, + &pvd, + &validation_code, + &expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate), + persisted_validation_data: pvd, + }; + let expected_request_a = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }; + let expected_empty_response = vec![(hypothetical_candidate.clone(), vec![])]; + let expected_request_b = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_b_hash), + }; + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![ + (expected_request_a, expected_empty_response.clone()), + (expected_request_b, expected_empty_response), + ], + ) + .await; + + assert!(virtual_overseer + .recv() + .timeout(std::time::Duration::from_millis(50)) + .await + .is_none()); + + virtual_overseer + }); +} + +// Test that `seconding_sanity_check` allows seconding a candidate when it's allowed on at least one +// leaf. +#[test] +fn seconding_sanity_check_allowed_on_at_least_one_leaf() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + // `a` is grandparent of `b`. + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; + + let leaf_b_hash = Hash::from_low_u64_be(128); + let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + activate_leaf(&mut virtual_overseer, test_leaf_b, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }; + let expected_response_a = + make_hypothetical_membership_response(hypothetical_candidate.clone(), leaf_a_hash); + let expected_request_b = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_b_hash), + }; + let expected_response_b = vec![(hypothetical_candidate.clone(), vec![])]; + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![ + (expected_request_a, expected_response_a), + (expected_request_b, expected_response_b), + ], + ) + .await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_candidate_is_shared_and_seconded(&mut virtual_overseer, &leaf_a_parent).await; + + virtual_overseer + }); +} + +// Test that a seconded candidate which is not approved by prospective parachains +// subsystem doesn't change the view. +#[test] +fn prospective_parachains_reject_candidate() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = vec![( + HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }, + make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash), + )]; + assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request_a.clone()) + .await; + + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + // Reject it. + tx.send(false).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Invalid( + relay_parent, + candidate_receipt, + )) if candidate_receipt.descriptor() == &candidate.descriptor && + candidate_receipt.commitments_hash == candidate.commitments.hash() && + relay_parent == leaf_a_parent + ); + + // Try seconding the same candidate. + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request_a).await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_candidate_is_shared_and_seconded(&mut virtual_overseer, &leaf_a_parent).await; + + virtual_overseer + }); +} + +// Test that a validator can second multiple candidates per single relay parent. +#[test] +fn second_multiple_candidates_per_relay_parent() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a parent of the activated `leaf`. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + let leaf_grandparent = get_parent_hash(leaf_parent); + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate_a = TestCandidateBuilder { + para_id, + relay_parent: leaf_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + }; + let mut candidate_b = candidate_a.clone(); + candidate_b.relay_parent = leaf_grandparent; + + let candidate_a = candidate_a.build(); + let candidate_b = candidate_b.build(); + + for candidate in &[candidate_a, candidate_b] { + let second = CandidateBackingMessage::Second( + leaf_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + candidate.descriptor.relay_parent(), + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = vec![( + HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_hash), + }, + make_hypothetical_membership_response(hypothetical_candidate, leaf_hash), + )]; + assert_hypothetical_membership_requests( + &mut virtual_overseer, + expected_request_a.clone(), + ) + .await; + + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + &req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + tx.send(true).unwrap(); + } + ); + + assert_candidate_is_shared_and_seconded( + &mut virtual_overseer, + &candidate.descriptor.relay_parent(), + ) + .await; + } + + virtual_overseer + }); +} + +// Tests that validators start work on consecutive prospective parachain blocks. +#[test] +fn concurrent_dependent_candidates() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a grandparent of the activated `leaf`, + // candidate `b` -- in parent. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + let leaf_grandparent = get_parent_hash(leaf_parent); + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + + let head_data = &[ + HeadData(vec![10, 20, 30]), // Before `a`. + HeadData(vec![11, 21, 31]), // After `a`. + HeadData(vec![12, 22]), // After `b`. + ]; + + let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd_a = PersistedValidationData { + parent_head: head_data[0].clone(), + relay_parent_number: LEAF_BLOCK_NUMBER - 2, + relay_parent_storage_root: Hash::zero(), + max_pov_size: 1024, + }; + + let pov_b = PoV { block_data: BlockData(vec![22, 14, 100]) }; + let pvd_b = PersistedValidationData { + parent_head: head_data[1].clone(), + relay_parent_number: LEAF_BLOCK_NUMBER - 1, + relay_parent_storage_root: Hash::zero(), + max_pov_size: 1024, + }; + let validation_code = ValidationCode(vec![1, 2, 3]); + + let candidate_a = TestCandidateBuilder { + para_id, + relay_parent: leaf_grandparent, + pov_hash: pov_a.hash(), + head_data: head_data[1].clone(), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), + persisted_validation_data_hash: pvd_a.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + let candidate_b = TestCandidateBuilder { + para_id, + relay_parent: leaf_parent, + pov_hash: pov_b.hash(), + head_data: head_data[2].clone(), + erasure_root: make_erasure_root(&test_state, pov_b.clone(), pvd_b.clone()), + persisted_validation_data_hash: pvd_b.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + let candidate_a_hash = candidate_a.hash(); + let candidate_b_hash = candidate_b.hash(); + + let public1 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[5].to_seed()), + ) + .expect("Insert key into keystore"); + let public2 = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[2].to_seed()), + ) + .expect("Insert key into keystore"); + + // Signing context should have a parent hash candidate is based on. + let signing_context = + SigningContext { parent_hash: leaf_grandparent, session_index: test_state.session() }; + let signed_a = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate_a.clone(), pvd_a.clone()), + &signing_context, + ValidatorIndex(2), + &public2.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let signing_context = + SigningContext { parent_hash: leaf_parent, session_index: test_state.session() }; + let signed_b = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate_b.clone(), pvd_b.clone()), + &signing_context, + ValidatorIndex(5), + &public1.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let statement_a = CandidateBackingMessage::Statement(leaf_grandparent, signed_a.clone()); + let statement_b = CandidateBackingMessage::Statement(leaf_parent, signed_b.clone()); + + virtual_overseer.send(FromOrchestra::Communication { msg: statement_a }).await; + + // At this point the subsystem waits for response, the previous message is received, + // send a second one without blocking. + let _ = virtual_overseer + .tx + .start_send_unpin(FromOrchestra::Communication { msg: statement_b }); + + let mut valid_statements = HashSet::new(); + let mut backed_statements = HashSet::new(); + + loop { + let msg = virtual_overseer + .recv() + .timeout(std::time::Duration::from_secs(1)) + .await + .expect("overseer recv timed out"); + + // Order is not guaranteed since we have 2 statements being handled concurrently. + match msg { + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate(_, tx), + ) => { + tx.send(true).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::ValidationCodeByHash(_, tx), + )) => { + tx.send(Ok(Some(validation_code.clone()))).unwrap(); + }, + AllMessages::AvailabilityDistribution( + AvailabilityDistributionMessage::FetchPoV { candidate_hash, tx, .. }, + ) => { + let pov = if candidate_hash == candidate_a_hash { + &pov_a + } else if candidate_hash == candidate_b_hash { + &pov_b + } else { + panic!("unknown candidate hash") + }; + tx.send(pov.clone()).unwrap(); + }, + AllMessages::CandidateValidation( + CandidateValidationMessage::ValidateFromExhaustive { + candidate_receipt, + response_sender, + .. + }, + ) => { + let candidate_hash = candidate_receipt.hash(); + let (head_data, pvd) = if candidate_hash == candidate_a_hash { + (&head_data[1], &pvd_a) + } else if candidate_hash == candidate_b_hash { + (&head_data[2], &pvd_b) + } else { + panic!("unknown candidate hash") + }; + response_sender + .send(Ok(ValidationResult::Valid( + CandidateCommitments { + head_data: head_data.clone(), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }, + pvd.clone(), + ))) + .unwrap(); + }, + AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { + tx, + .. + }) => { + tx.send(Ok(())).unwrap(); + }, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::CandidateBacked(..), + ) => {}, + AllMessages::StatementDistribution(StatementDistributionMessage::Share( + _, + statement, + )) => { + assert_eq!(statement.validator_index(), ValidatorIndex(0)); + let payload = statement.payload(); + assert_matches!( + payload.clone(), + StatementWithPVD::Valid(hash) + if hash == candidate_a_hash || hash == candidate_b_hash => + { + assert!(valid_statements.insert(hash)); + } + ); + }, + AllMessages::StatementDistribution(StatementDistributionMessage::Backed(hash)) => { + // Ensure that `Share` was received first for the candidate. + assert!(valid_statements.contains(&hash)); + backed_statements.insert(hash); + + if backed_statements.len() == 2 { + break + } + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + tx.send(Ok(1u32.into())).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(sess_idx, tx), + )) => { + assert_eq!(sess_idx, 1); + tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _parent, + RuntimeApiRequest::ValidatorGroups(tx), + )) => { + tx.send(Ok(test_state.validator_groups.clone())).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::NodeFeatures(sess_idx, tx), + )) => { + assert_eq!(sess_idx, 1); + tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _parent, + RuntimeApiRequest::AvailabilityCores(tx), + )) => { + tx.send(Ok(test_state.availability_cores.clone())).unwrap(); + }, + _ => panic!("unexpected message received from overseer: {:?}", msg), + } + } + + assert!(valid_statements.contains(&candidate_a_hash)); + assert!(valid_statements.contains(&candidate_b_hash)); + assert!(backed_statements.contains(&candidate_a_hash)); + assert!(backed_statements.contains(&candidate_b_hash)); + + virtual_overseer + }); +} + +// Test that multiple candidates from different paras can occupy the same depth +// in a given relay parent. +#[test] +fn seconding_sanity_check_occupy_same_depth() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate `a` is seconded in a parent of the activated `leaf`. + const LEAF_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_ANCESTRY_LEN: BlockNumber = 3; + + let para_id_a = test_state.chain_ids[0]; + let para_id_b = test_state.chain_ids[1]; + + let leaf_hash = Hash::from_low_u64_be(130); + let leaf_parent = get_parent_hash(leaf_hash); + + let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); + let min_block_number = LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN; + let min_relay_parents = vec![(para_id_a, min_block_number), (para_id_b, min_block_number)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data_a = test_state.head_data.get(¶_id_a).unwrap(); + let expected_head_data_b = test_state.head_data.get(¶_id_b).unwrap(); + + let pov_hash = pov.hash(); + let candidate_a = TestCandidateBuilder { + para_id: para_id_a, + relay_parent: leaf_parent, + pov_hash, + head_data: expected_head_data_a.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + }; + + let mut candidate_b = candidate_a.clone(); + candidate_b.para_id = para_id_b; + candidate_b.head_data = expected_head_data_b.clone(); + // A rotation happens, test validator is assigned to second para here. + candidate_b.relay_parent = leaf_hash; + + let candidate_a = (candidate_a.build(), expected_head_data_a, para_id_a); + let candidate_b = (candidate_b.build(), expected_head_data_b, para_id_b); + + for candidate in &[candidate_a, candidate_b] { + let (candidate, expected_head_data, para_id) = candidate; + let second = CandidateBackingMessage::Second( + leaf_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + candidate.descriptor.relay_parent(), + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = vec![( + HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_hash), + }, + // Send the same membership for both candidates. + make_hypothetical_membership_response(hypothetical_candidate, leaf_hash), + )]; + + assert_hypothetical_membership_requests( + &mut virtual_overseer, + expected_request_a.clone(), + ) + .await; + + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + &req.candidate_receipt == candidate + && &req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + tx.send(true).unwrap(); + } + ); + + assert_candidate_is_shared_and_seconded( + &mut virtual_overseer, + &candidate.descriptor.relay_parent(), + ) + .await; + } + + virtual_overseer + }); +} + +// Test that the subsystem doesn't skip occupied cores assignments. +#[test] +fn occupied_core_assignment() { + let mut test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + let previous_para_id = test_state.chain_ids[1]; + + // Set the core state to occupied. + let mut candidate_descriptor = + polkadot_primitives_test_helpers::dummy_candidate_descriptor(Hash::zero()); + candidate_descriptor.para_id = previous_para_id; + test_state.availability_cores[0] = CoreState::Occupied(OccupiedCore { + group_responsible: Default::default(), + next_up_on_available: Some(ScheduledCore { para_id, collator: None }), + occupied_since: 100_u32, + time_out_at: 200_u32, + next_up_on_time_out: None, + availability: Default::default(), + candidate_descriptor: candidate_descriptor.into(), + candidate_hash: Default::default(), + }); + + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &mut test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request = vec![( + HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }, + make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash), + )]; + assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request).await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + tx.send(true).unwrap(); + } + ); + + assert_candidate_is_shared_and_seconded(&mut virtual_overseer, &leaf_a_parent).await; + virtual_overseer }); } diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs deleted file mode 100644 index caddd2408057..000000000000 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ /dev/null @@ -1,1742 +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 . - -//! Tests for the backing subsystem with enabled prospective parachains. - -use polkadot_node_subsystem::{ - messages::{ChainApiMessage, HypotheticalMembership}, - ActivatedLeaf, TimeoutExt, -}; -use polkadot_primitives::{vstaging::OccupiedCore, AsyncBackingParams, BlockNumber, Header}; - -use super::*; - -const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = - AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; - -struct TestLeaf { - activated: ActivatedLeaf, - min_relay_parents: Vec<(ParaId, u32)>, -} - -fn get_parent_hash(hash: Hash) -> Hash { - Hash::from_low_u64_be(hash.to_low_u64_be() + 1) -} - -async fn activate_leaf( - virtual_overseer: &mut VirtualOverseer, - leaf: TestLeaf, - test_state: &TestState, -) { - let TestLeaf { activated, min_relay_parents } = leaf; - let leaf_hash = activated.hash; - let leaf_number = activated.number; - // Start work on some new parent. - virtual_overseer - .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work( - activated, - )))) - .await; - - // Prospective parachains mode is temporarily defined by the Runtime API version. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AsyncBackingParams(tx)) - ) if parent == leaf_hash => { - tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); - } - ); - - let min_min = *min_relay_parents - .iter() - .map(|(_, block_num)| block_num) - .min() - .unwrap_or(&leaf_number); - - let ancestry_len = leaf_number + 1 - min_min; - - let ancestry_hashes = std::iter::successors(Some(leaf_hash), |h| Some(get_parent_hash(*h))) - .take(ancestry_len as usize); - let ancestry_numbers = (min_min..=leaf_number).rev(); - let ancestry_iter = ancestry_hashes.zip(ancestry_numbers).peekable(); - - let mut next_overseer_message = None; - // How many blocks were actually requested. - let mut requested_len = 0; - { - let mut ancestry_iter = ancestry_iter.clone(); - while let Some((hash, number)) = ancestry_iter.next() { - // May be `None` for the last element. - let parent_hash = - ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); - - let msg = virtual_overseer.recv().await; - // It may happen that some blocks were cached by implicit view, - // reuse the message. - if !matches!(&msg, AllMessages::ChainApi(ChainApiMessage::BlockHeader(..))) { - next_overseer_message.replace(msg); - break - } - - assert_matches!( - msg, - AllMessages::ChainApi( - ChainApiMessage::BlockHeader(_hash, tx) - ) if _hash == hash => { - let header = Header { - parent_hash, - number, - state_root: Hash::zero(), - extrinsics_root: Hash::zero(), - digest: Default::default(), - }; - - tx.send(Ok(Some(header))).unwrap(); - } - ); - - if requested_len == 0 { - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetMinimumRelayParents(parent, tx) - ) if parent == leaf_hash => { - tx.send(min_relay_parents.clone()).unwrap(); - } - ); - } - - requested_len += 1; - } - } - - for (hash, number) in ancestry_iter.take(requested_len) { - let msg = match next_overseer_message.take() { - Some(msg) => msg, - None => virtual_overseer.recv().await, - }; - - // Check that subsystem job issues a request for the session index for child. - assert_matches!( - msg, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx)) - ) if parent == hash => { - tx.send(Ok(test_state.signing_context.session_index)).unwrap(); - } - ); - - // Check that subsystem job issues a request for a validator set. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) - ) if parent == hash => { - tx.send(Ok(test_state.validator_public.clone())).unwrap(); - } - ); - - // Check that subsystem job issues a request for the validator groups. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx)) - ) if parent == hash => { - let (validator_groups, mut group_rotation_info) = test_state.validator_groups.clone(); - group_rotation_info.now = number; - tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); - } - ); - - // Check that subsystem job issues a request for the availability cores. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) - ) if parent == hash => { - tx.send(Ok(test_state.availability_cores.clone())).unwrap(); - } - ); - - // Node features request from runtime: all features are disabled. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::NodeFeatures(_session_index, tx)) - ) if parent == hash => { - tx.send(Ok(Default::default())).unwrap(); - } - ); - - // Check if subsystem job issues a request for the minimum backing votes. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - parent, - RuntimeApiRequest::MinimumBackingVotes(session_index, tx), - )) if parent == hash && session_index == test_state.signing_context.session_index => { - tx.send(Ok(test_state.minimum_backing_votes)).unwrap(); - } - ); - - // Check that subsystem job issues a request for the runtime version. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Version(tx)) - ) if parent == hash => { - tx.send(Ok(RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT)).unwrap(); - } - ); - - // Check that the subsystem job issues a request for the disabled validators. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::DisabledValidators(tx)) - ) if parent == hash => { - tx.send(Ok(Vec::new())).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Version(tx)) - ) if parent == hash => { - tx.send(Ok(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ClaimQueue(tx)) - ) if parent == hash => { - tx.send(Ok( - test_state.claim_queue.clone() - )).unwrap(); - } - ); - } -} - -async fn assert_validate_seconded_candidate( - virtual_overseer: &mut VirtualOverseer, - relay_parent: Hash, - candidate: &CommittedCandidateReceipt, - assert_pov: &PoV, - assert_pvd: &PersistedValidationData, - assert_validation_code: &ValidationCode, - expected_head_data: &HeadData, - fetch_pov: bool, -) { - assert_validation_requests(virtual_overseer, assert_validation_code.clone()).await; - - if fetch_pov { - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityDistribution( - AvailabilityDistributionMessage::FetchPoV { - relay_parent: hash, - tx, - .. - } - ) if hash == relay_parent => { - tx.send(assert_pov.clone()).unwrap(); - } - ); - } - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive { - validation_data, - validation_code, - candidate_receipt, - pov, - exec_kind, - response_sender, - .. - }) if &validation_data == assert_pvd && - &validation_code == assert_validation_code && - &*pov == assert_pov && - candidate_receipt.descriptor == candidate.descriptor && - exec_kind == PvfExecKind::BackingSystemParas && - candidate.commitments.hash() == candidate_receipt.commitments_hash => - { - response_sender.send(Ok(ValidationResult::Valid( - CandidateCommitments { - head_data: expected_head_data.clone(), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, - assert_pvd.clone(), - ))) - .unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::AvailabilityStore( - AvailabilityStoreMessage::StoreAvailableData { candidate_hash, tx, .. } - ) if candidate_hash == candidate.hash() => { - tx.send(Ok(())).unwrap(); - } - ); -} - -async fn assert_hypothetical_membership_requests( - virtual_overseer: &mut VirtualOverseer, - mut expected_requests: Vec<( - HypotheticalMembershipRequest, - Vec<(HypotheticalCandidate, HypotheticalMembership)>, - )>, -) { - // Requests come with no particular order. - let requests_num = expected_requests.len(); - - for _ in 0..requests_num { - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetHypotheticalMembership(request, tx), - ) => { - let idx = match expected_requests.iter().position(|r| r.0 == request) { - Some(idx) => idx, - None => - panic!( - "unexpected hypothetical membership request, no match found for {:?}", - request - ), - }; - let resp = std::mem::take(&mut expected_requests[idx].1); - tx.send(resp).unwrap(); - - expected_requests.remove(idx); - } - ); - } -} - -fn make_hypothetical_membership_response( - hypothetical_candidate: HypotheticalCandidate, - relay_parent_hash: Hash, -) -> Vec<(HypotheticalCandidate, HypotheticalMembership)> { - vec![(hypothetical_candidate, vec![relay_parent_hash])] -} - -// Test that `seconding_sanity_check` works when a candidate is allowed -// for all leaves. -#[test] -fn seconding_sanity_check_allowed_on_all() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate is seconded in a parent of the activated `leaf_a`. - const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - // `a` is grandparent of `b`. - let leaf_a_hash = Hash::from_low_u64_be(130); - let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; - const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; - - let leaf_b_hash = Hash::from_low_u64_be(128); - let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; - let test_leaf_b = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - let candidate = TestCandidateBuilder { - para_id, - relay_parent: leaf_a_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_parent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request_a = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_a_hash), - }; - let expected_response_a = - make_hypothetical_membership_response(hypothetical_candidate.clone(), leaf_a_hash); - let expected_request_b = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_b_hash), - }; - let expected_response_b = - make_hypothetical_membership_response(hypothetical_candidate, leaf_b_hash); - assert_hypothetical_membership_requests( - &mut virtual_overseer, - vec![ - (expected_request_a, expected_response_a), - (expected_request_b, expected_response_b), - ], - ) - .await; - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == leaf_a_parent => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(leaf_a_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - - virtual_overseer - }); -} - -// Test that `seconding_sanity_check` disallows seconding when a candidate is disallowed -// for all leaves. -#[test] -fn seconding_sanity_check_disallowed() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate is seconded in a parent of the activated `leaf_a`. - const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - let leaf_b_hash = Hash::from_low_u64_be(128); - // `a` is grandparent of `b`. - let leaf_a_hash = Hash::from_low_u64_be(130); - let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; - const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; - - let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; - let test_leaf_b = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - let candidate = TestCandidateBuilder { - para_id, - relay_parent: leaf_a_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_parent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request_a = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_a_hash), - }; - let expected_response_a = - make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash); - assert_hypothetical_membership_requests( - &mut virtual_overseer, - vec![(expected_request_a, expected_response_a)], - ) - .await; - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == leaf_a_parent => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(leaf_a_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - - activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state).await; - let leaf_a_grandparent = get_parent_hash(leaf_a_parent); - let candidate = TestCandidateBuilder { - para_id, - relay_parent: leaf_a_grandparent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_grandparent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate), - persisted_validation_data: pvd, - }; - let expected_request_a = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_a_hash), - }; - let expected_empty_response = vec![(hypothetical_candidate.clone(), vec![])]; - let expected_request_b = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_b_hash), - }; - assert_hypothetical_membership_requests( - &mut virtual_overseer, - vec![ - (expected_request_a, expected_empty_response.clone()), - (expected_request_b, expected_empty_response), - ], - ) - .await; - - assert!(virtual_overseer - .recv() - .timeout(std::time::Duration::from_millis(50)) - .await - .is_none()); - - virtual_overseer - }); -} - -// Test that `seconding_sanity_check` allows seconding a candidate when it's allowed on at least one -// leaf. -#[test] -fn seconding_sanity_check_allowed_on_at_least_one_leaf() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate is seconded in a parent of the activated `leaf_a`. - const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - // `a` is grandparent of `b`. - let leaf_a_hash = Hash::from_low_u64_be(130); - let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; - const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; - - let leaf_b_hash = Hash::from_low_u64_be(128); - let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; - let test_leaf_b = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - let candidate = TestCandidateBuilder { - para_id, - relay_parent: leaf_a_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_parent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request_a = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_a_hash), - }; - let expected_response_a = - make_hypothetical_membership_response(hypothetical_candidate.clone(), leaf_a_hash); - let expected_request_b = HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_b_hash), - }; - let expected_response_b = vec![(hypothetical_candidate.clone(), vec![])]; - assert_hypothetical_membership_requests( - &mut virtual_overseer, - vec![ - (expected_request_a, expected_response_a), - (expected_request_b, expected_response_b), - ], - ) - .await; - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == leaf_a_parent => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(leaf_a_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - - virtual_overseer - }); -} - -// Test that a seconded candidate which is not approved by prospective parachains -// subsystem doesn't change the view. -#[test] -fn prospective_parachains_reject_candidate() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate is seconded in a parent of the activated `leaf_a`. - const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - let leaf_a_hash = Hash::from_low_u64_be(130); - let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - let candidate = TestCandidateBuilder { - para_id, - relay_parent: leaf_a_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_parent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request_a = vec![( - HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_a_hash), - }, - make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash), - )]; - assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request_a.clone()) - .await; - - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data => { - // Reject it. - tx.send(false).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Invalid( - relay_parent, - candidate_receipt, - )) if candidate_receipt.descriptor == candidate.descriptor && - candidate_receipt.commitments_hash == candidate.commitments.hash() && - relay_parent == leaf_a_parent - ); - - // Try seconding the same candidate. - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_parent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request_a).await; - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == leaf_a_parent => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(leaf_a_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - - virtual_overseer - }); -} - -// Test that a validator can second multiple candidates per single relay parent. -#[test] -fn second_multiple_candidates_per_relay_parent() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate `a` is seconded in a parent of the activated `leaf`. - const LEAF_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - let leaf_hash = Hash::from_low_u64_be(130); - let leaf_parent = get_parent_hash(leaf_hash); - let leaf_grandparent = get_parent_hash(leaf_parent); - let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - let candidate_a = TestCandidateBuilder { - para_id, - relay_parent: leaf_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - }; - let mut candidate_b = candidate_a.clone(); - candidate_b.relay_parent = leaf_grandparent; - - let candidate_a = candidate_a.build(); - let candidate_b = candidate_b.build(); - - for candidate in &[candidate_a, candidate_b] { - let second = CandidateBackingMessage::Second( - leaf_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - candidate.descriptor.relay_parent(), - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request_a = vec![( - HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_hash), - }, - make_hypothetical_membership_response(hypothetical_candidate, leaf_hash), - )]; - assert_hypothetical_membership_requests( - &mut virtual_overseer, - expected_request_a.clone(), - ) - .await; - - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - &req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data - => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == candidate.descriptor.relay_parent() => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(candidate.descriptor.relay_parent(), hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - } - - virtual_overseer - }); -} - -// Test that the candidate reaches quorum successfully. -#[test] -fn backing_works() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate `a` is seconded in a parent of the activated `leaf`. - const LEAF_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - let leaf_hash = Hash::from_low_u64_be(130); - let leaf_parent = get_parent_hash(leaf_hash); - let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - - let candidate_a = TestCandidateBuilder { - para_id, - relay_parent: leaf_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - validation_code: validation_code.0.clone(), - persisted_validation_data_hash: pvd.hash(), - } - .build(); - - let candidate_a_hash = candidate_a.hash(); - - let public1 = Keystore::sr25519_generate_new( - &*test_state.keystore, - ValidatorId::ID, - Some(&test_state.validators[5].to_seed()), - ) - .expect("Insert key into keystore"); - let public2 = Keystore::sr25519_generate_new( - &*test_state.keystore, - ValidatorId::ID, - Some(&test_state.validators[2].to_seed()), - ) - .expect("Insert key into keystore"); - - // Signing context should have a parent hash candidate is based on. - let signing_context = - SigningContext { parent_hash: leaf_parent, session_index: test_state.session() }; - let signed_a = SignedFullStatementWithPVD::sign( - &test_state.keystore, - StatementWithPVD::Seconded(candidate_a.clone(), pvd.clone()), - &signing_context, - ValidatorIndex(2), - &public2.into(), - ) - .ok() - .flatten() - .expect("should be signed"); - - let signed_b = SignedFullStatementWithPVD::sign( - &test_state.keystore, - StatementWithPVD::Valid(candidate_a_hash), - &signing_context, - ValidatorIndex(5), - &public1.into(), - ) - .ok() - .flatten() - .expect("should be signed"); - - let statement = CandidateBackingMessage::Statement(leaf_parent, signed_a.clone()); - - virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - - // Prospective parachains are notified about candidate seconded first. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate_a - && req.candidate_para == para_id - && pvd == req.persisted_validation_data => { - tx.send(true).unwrap(); - } - ); - - assert_validate_seconded_candidate( - &mut virtual_overseer, - candidate_a.descriptor.relay_parent(), - &candidate_a, - &pov, - &pvd, - &validation_code, - expected_head_data, - true, - ) - .await; - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share(hash, _stmt) - ) => { - assert_eq!(leaf_parent, hash); - } - ); - - // Prospective parachains and collator protocol are notified about candidate backed. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::CandidateBacked( - candidate_para_id, candidate_hash - ), - ) if candidate_a_hash == candidate_hash && candidate_para_id == para_id - ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution(StatementDistributionMessage::Backed ( - candidate_hash - )) if candidate_a_hash == candidate_hash - ); - - let statement = CandidateBackingMessage::Statement(leaf_parent, signed_b.clone()); - - virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; - - virtual_overseer - }); -} - -// Tests that validators start work on consecutive prospective parachain blocks. -#[test] -fn concurrent_dependent_candidates() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate `a` is seconded in a grandparent of the activated `leaf`, - // candidate `b` -- in parent. - const LEAF_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - - let leaf_hash = Hash::from_low_u64_be(130); - let leaf_parent = get_parent_hash(leaf_hash); - let leaf_grandparent = get_parent_hash(leaf_parent); - let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let head_data = &[ - HeadData(vec![10, 20, 30]), // Before `a`. - HeadData(vec![11, 21, 31]), // After `a`. - HeadData(vec![12, 22]), // After `b`. - ]; - - let pov_a = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd_a = PersistedValidationData { - parent_head: head_data[0].clone(), - relay_parent_number: LEAF_BLOCK_NUMBER - 2, - relay_parent_storage_root: Hash::zero(), - max_pov_size: 1024, - }; - - let pov_b = PoV { block_data: BlockData(vec![22, 14, 100]) }; - let pvd_b = PersistedValidationData { - parent_head: head_data[1].clone(), - relay_parent_number: LEAF_BLOCK_NUMBER - 1, - relay_parent_storage_root: Hash::zero(), - max_pov_size: 1024, - }; - let validation_code = ValidationCode(vec![1, 2, 3]); - - let candidate_a = TestCandidateBuilder { - para_id, - relay_parent: leaf_grandparent, - pov_hash: pov_a.hash(), - head_data: head_data[1].clone(), - erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), - persisted_validation_data_hash: pvd_a.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - let candidate_b = TestCandidateBuilder { - para_id, - relay_parent: leaf_parent, - pov_hash: pov_b.hash(), - head_data: head_data[2].clone(), - erasure_root: make_erasure_root(&test_state, pov_b.clone(), pvd_b.clone()), - persisted_validation_data_hash: pvd_b.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - let candidate_a_hash = candidate_a.hash(); - let candidate_b_hash = candidate_b.hash(); - - let public1 = Keystore::sr25519_generate_new( - &*test_state.keystore, - ValidatorId::ID, - Some(&test_state.validators[5].to_seed()), - ) - .expect("Insert key into keystore"); - let public2 = Keystore::sr25519_generate_new( - &*test_state.keystore, - ValidatorId::ID, - Some(&test_state.validators[2].to_seed()), - ) - .expect("Insert key into keystore"); - - // Signing context should have a parent hash candidate is based on. - let signing_context = - SigningContext { parent_hash: leaf_grandparent, session_index: test_state.session() }; - let signed_a = SignedFullStatementWithPVD::sign( - &test_state.keystore, - StatementWithPVD::Seconded(candidate_a.clone(), pvd_a.clone()), - &signing_context, - ValidatorIndex(2), - &public2.into(), - ) - .ok() - .flatten() - .expect("should be signed"); - - let signing_context = - SigningContext { parent_hash: leaf_parent, session_index: test_state.session() }; - let signed_b = SignedFullStatementWithPVD::sign( - &test_state.keystore, - StatementWithPVD::Seconded(candidate_b.clone(), pvd_b.clone()), - &signing_context, - ValidatorIndex(5), - &public1.into(), - ) - .ok() - .flatten() - .expect("should be signed"); - - let statement_a = CandidateBackingMessage::Statement(leaf_grandparent, signed_a.clone()); - let statement_b = CandidateBackingMessage::Statement(leaf_parent, signed_b.clone()); - - virtual_overseer.send(FromOrchestra::Communication { msg: statement_a }).await; - - // At this point the subsystem waits for response, the previous message is received, - // send a second one without blocking. - let _ = virtual_overseer - .tx - .start_send_unpin(FromOrchestra::Communication { msg: statement_b }); - - let mut valid_statements = HashSet::new(); - let mut backed_statements = HashSet::new(); - - loop { - let msg = virtual_overseer - .recv() - .timeout(std::time::Duration::from_secs(1)) - .await - .expect("overseer recv timed out"); - - // Order is not guaranteed since we have 2 statements being handled concurrently. - match msg { - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate(_, tx), - ) => { - tx.send(true).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::ValidationCodeByHash(_, tx), - )) => { - tx.send(Ok(Some(validation_code.clone()))).unwrap(); - }, - AllMessages::AvailabilityDistribution( - AvailabilityDistributionMessage::FetchPoV { candidate_hash, tx, .. }, - ) => { - let pov = if candidate_hash == candidate_a_hash { - &pov_a - } else if candidate_hash == candidate_b_hash { - &pov_b - } else { - panic!("unknown candidate hash") - }; - tx.send(pov.clone()).unwrap(); - }, - AllMessages::CandidateValidation( - CandidateValidationMessage::ValidateFromExhaustive { - candidate_receipt, - response_sender, - .. - }, - ) => { - let candidate_hash = candidate_receipt.hash(); - let (head_data, pvd) = if candidate_hash == candidate_a_hash { - (&head_data[1], &pvd_a) - } else if candidate_hash == candidate_b_hash { - (&head_data[2], &pvd_b) - } else { - panic!("unknown candidate hash") - }; - response_sender - .send(Ok(ValidationResult::Valid( - CandidateCommitments { - head_data: head_data.clone(), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }, - pvd.clone(), - ))) - .unwrap(); - }, - AllMessages::AvailabilityStore(AvailabilityStoreMessage::StoreAvailableData { - tx, - .. - }) => { - tx.send(Ok(())).unwrap(); - }, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::CandidateBacked(..), - ) => {}, - AllMessages::StatementDistribution(StatementDistributionMessage::Share( - _, - statement, - )) => { - assert_eq!(statement.validator_index(), ValidatorIndex(0)); - let payload = statement.payload(); - assert_matches!( - payload.clone(), - StatementWithPVD::Valid(hash) - if hash == candidate_a_hash || hash == candidate_b_hash => - { - assert!(valid_statements.insert(hash)); - } - ); - }, - AllMessages::StatementDistribution(StatementDistributionMessage::Backed(hash)) => { - // Ensure that `Share` was received first for the candidate. - assert!(valid_statements.contains(&hash)); - backed_statements.insert(hash); - - if backed_statements.len() == 2 { - break - } - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::SessionIndexForChild(tx), - )) => { - tx.send(Ok(1u32.into())).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::SessionExecutorParams(sess_idx, tx), - )) => { - assert_eq!(sess_idx, 1); - tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _parent, - RuntimeApiRequest::ValidatorGroups(tx), - )) => { - tx.send(Ok(test_state.validator_groups.clone())).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::NodeFeatures(sess_idx, tx), - )) => { - assert_eq!(sess_idx, 1); - tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); - }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _parent, - RuntimeApiRequest::AvailabilityCores(tx), - )) => { - tx.send(Ok(test_state.availability_cores.clone())).unwrap(); - }, - _ => panic!("unexpected message received from overseer: {:?}", msg), - } - } - - assert!(valid_statements.contains(&candidate_a_hash)); - assert!(valid_statements.contains(&candidate_b_hash)); - assert!(backed_statements.contains(&candidate_a_hash)); - assert!(backed_statements.contains(&candidate_b_hash)); - - virtual_overseer - }); -} - -// Test that multiple candidates from different paras can occupy the same depth -// in a given relay parent. -#[test] -fn seconding_sanity_check_occupy_same_depth() { - let test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate `a` is seconded in a parent of the activated `leaf`. - const LEAF_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_ANCESTRY_LEN: BlockNumber = 3; - - let para_id_a = test_state.chain_ids[0]; - let para_id_b = test_state.chain_ids[1]; - - let leaf_hash = Hash::from_low_u64_be(130); - let leaf_parent = get_parent_hash(leaf_hash); - - let activated = new_leaf(leaf_hash, LEAF_BLOCK_NUMBER); - let min_block_number = LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN; - let min_relay_parents = vec![(para_id_a, min_block_number), (para_id_b, min_block_number)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data_a = test_state.head_data.get(¶_id_a).unwrap(); - let expected_head_data_b = test_state.head_data.get(¶_id_b).unwrap(); - - let pov_hash = pov.hash(); - let candidate_a = TestCandidateBuilder { - para_id: para_id_a, - relay_parent: leaf_parent, - pov_hash, - head_data: expected_head_data_a.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - }; - - let mut candidate_b = candidate_a.clone(); - candidate_b.para_id = para_id_b; - candidate_b.head_data = expected_head_data_b.clone(); - // A rotation happens, test validator is assigned to second para here. - candidate_b.relay_parent = leaf_hash; - - let candidate_a = (candidate_a.build(), expected_head_data_a, para_id_a); - let candidate_b = (candidate_b.build(), expected_head_data_b, para_id_b); - - for candidate in &[candidate_a, candidate_b] { - let (candidate, expected_head_data, para_id) = candidate; - let second = CandidateBackingMessage::Second( - leaf_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - candidate.descriptor.relay_parent(), - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request_a = vec![( - HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_hash), - }, - // Send the same membership for both candidates. - make_hypothetical_membership_response(hypothetical_candidate, leaf_hash), - )]; - - assert_hypothetical_membership_requests( - &mut virtual_overseer, - expected_request_a.clone(), - ) - .await; - - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - &req.candidate_receipt == candidate - && &req.candidate_para == para_id - && pvd == req.persisted_validation_data - => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == candidate.descriptor.relay_parent() => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(candidate.descriptor.relay_parent(), hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - } - - virtual_overseer - }); -} - -// Test that the subsystem doesn't skip occupied cores assignments. -#[test] -fn occupied_core_assignment() { - let mut test_state = TestState::default(); - test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { - // Candidate is seconded in a parent of the activated `leaf_a`. - const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; - const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; - let para_id = test_state.chain_ids[0]; - let previous_para_id = test_state.chain_ids[1]; - - // Set the core state to occupied. - let mut candidate_descriptor = - polkadot_primitives_test_helpers::dummy_candidate_descriptor(Hash::zero()); - candidate_descriptor.para_id = previous_para_id; - test_state.availability_cores[0] = CoreState::Occupied(OccupiedCore { - group_responsible: Default::default(), - next_up_on_available: Some(ScheduledCore { para_id, collator: None }), - occupied_since: 100_u32, - time_out_at: 200_u32, - next_up_on_time_out: None, - availability: Default::default(), - candidate_descriptor: candidate_descriptor.into(), - candidate_hash: Default::default(), - }); - - let leaf_a_hash = Hash::from_low_u64_be(130); - let leaf_a_parent = get_parent_hash(leaf_a_hash); - let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); - let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; - let test_leaf_a = TestLeaf { activated, min_relay_parents }; - - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; - - let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; - let pvd = dummy_pvd(); - let validation_code = ValidationCode(vec![1, 2, 3]); - - let expected_head_data = test_state.head_data.get(¶_id).unwrap(); - - let pov_hash = pov.hash(); - let candidate = TestCandidateBuilder { - para_id, - relay_parent: leaf_a_parent, - pov_hash, - head_data: expected_head_data.clone(), - erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), - persisted_validation_data_hash: pvd.hash(), - validation_code: validation_code.0.clone(), - } - .build(); - - let second = CandidateBackingMessage::Second( - leaf_a_hash, - candidate.to_plain(), - pvd.clone(), - pov.clone(), - ); - - virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; - - assert_validate_seconded_candidate( - &mut virtual_overseer, - leaf_a_parent, - &candidate, - &pov, - &pvd, - &validation_code, - expected_head_data, - false, - ) - .await; - - // `seconding_sanity_check` - let hypothetical_candidate = HypotheticalCandidate::Complete { - candidate_hash: candidate.hash(), - receipt: Arc::new(candidate.clone()), - persisted_validation_data: pvd.clone(), - }; - let expected_request = vec![( - HypotheticalMembershipRequest { - candidates: vec![hypothetical_candidate.clone()], - fragment_chain_relay_parent: Some(leaf_a_hash), - }, - make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash), - )]; - assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request).await; - // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceSecondedCandidate( - req, - tx, - ), - ) if - req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data - => { - tx.send(true).unwrap(); - } - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::StatementDistribution( - StatementDistributionMessage::Share( - parent_hash, - _signed_statement, - ) - ) if parent_hash == leaf_a_parent => {} - ); - - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { - assert_eq!(leaf_a_parent, hash); - assert_matches!(statement.payload(), Statement::Seconded(_)); - } - ); - - virtual_overseer - }); -} diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index 126a18a14166..e75404729dbd 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Bitfield signing subsystem for the Polkadot node" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -12,12 +14,12 @@ workspace = true [dependencies] futures = { workspace = true } gum = { workspace = true, default-features = true } -polkadot-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 } sp-keystore = { workspace = true, default-features = true } -wasm-timer = { workspace = true } thiserror = { workspace = true } +wasm-timer = { workspace = true } [dev-dependencies] polkadot-node-subsystem-test-helpers = { workspace = true } diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index 87855dbce415..e92976609f9e 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -15,28 +17,28 @@ futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -sp-keystore = { workspace = true } -sp-application-crypto = { workspace = true } codec = { features = ["bit-vec", "derive"], workspace = true } +sp-application-crypto = { workspace = true } +sp-keystore = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } 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-node-metrics = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } [target.'cfg(not(any(target_os = "android", target_os = "unknown")))'.dependencies] polkadot-node-core-pvf = { workspace = true, default-features = true } [dev-dependencies] -sp-keyring = { workspace = true, default-features = true } -futures = { features = ["thread-pool"], workspace = true } assert_matches = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } -sp-maybe-compressed-blob = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, features = ["test"] } polkadot-primitives-test-helpers = { workspace = true } rstest = { workspace = true } -polkadot-primitives = { workspace = true, features = ["test"] } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 1e732e2f1f03..25614349486e 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -31,13 +31,16 @@ use polkadot_node_primitives::{InvalidCandidate, PoV, ValidationResult}; use polkadot_node_subsystem::{ errors::RuntimeApiError, messages::{ - CandidateValidationMessage, PreCheckOutcome, PvfExecKind, RuntimeApiMessage, - RuntimeApiRequest, ValidationFailed, + CandidateValidationMessage, ChainApiMessage, PreCheckOutcome, PvfExecKind, + RuntimeApiMessage, RuntimeApiRequest, ValidationFailed, }, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, SubsystemSender, }; -use polkadot_node_subsystem_util::{self as util, runtime::ClaimQueueSnapshot}; +use polkadot_node_subsystem_util::{ + self as util, + runtime::{prospective_parachains_mode, ClaimQueueSnapshot, ProspectiveParachainsMode}, +}; use polkadot_overseer::ActiveLeavesUpdate; use polkadot_parachain_primitives::primitives::ValidationResult as WasmValidationResult; use polkadot_primitives::{ @@ -279,6 +282,7 @@ async fn run( comm = ctx.recv().fuse() => { match comm { Ok(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update))) => { + update_active_leaves(ctx.sender(), validation_host.clone(), update.clone()).await; maybe_prepare_validation(ctx.sender(), keystore.clone(), validation_host.clone(), update, &mut prepare_state).await; }, Ok(FromOrchestra::Signal(OverseerSignal::BlockFinalized(..))) => {}, @@ -551,6 +555,66 @@ where Some(processed_code_hashes) } +async fn update_active_leaves( + sender: &mut Sender, + mut validation_backend: impl ValidationBackend, + update: ActiveLeavesUpdate, +) where + Sender: SubsystemSender + SubsystemSender, +{ + let ancestors = get_block_ancestors(sender, update.activated.as_ref().map(|x| x.hash)).await; + if let Err(err) = validation_backend.update_active_leaves(update, ancestors).await { + gum::warn!( + target: LOG_TARGET, + ?err, + "cannot update active leaves in validation backend", + ); + }; +} + +async fn get_allowed_ancestry_len(sender: &mut Sender, relay_parent: Hash) -> Option +where + Sender: SubsystemSender + SubsystemSender, +{ + match prospective_parachains_mode(sender, relay_parent).await { + Ok(ProspectiveParachainsMode::Enabled { allowed_ancestry_len, .. }) => + Some(allowed_ancestry_len), + res => { + gum::warn!(target: LOG_TARGET, ?res, "async backing is disabled"); + None + }, + } +} + +async fn get_block_ancestors( + sender: &mut Sender, + maybe_relay_parent: Option, +) -> Vec +where + Sender: SubsystemSender + SubsystemSender, +{ + let Some(relay_parent) = maybe_relay_parent else { return vec![] }; + let Some(allowed_ancestry_len) = get_allowed_ancestry_len(sender, relay_parent).await else { + return vec![] + }; + + let (tx, rx) = oneshot::channel(); + sender + .send_message(ChainApiMessage::Ancestors { + hash: relay_parent, + k: allowed_ancestry_len, + response_channel: tx, + }) + .await; + match rx.await { + Ok(Ok(x)) => x, + res => { + gum::warn!(target: LOG_TARGET, ?res, "cannot request ancestors"); + vec![] + }, + } +} + struct RuntimeRequestFailed; async fn runtime_api_request( @@ -698,7 +762,7 @@ async fn validate_candidate_exhaustive( // We only check the session index for backing. match (exec_kind, candidate_receipt.descriptor.session_index()) { - (PvfExecKind::Backing | PvfExecKind::BackingSystemParas, Some(session_index)) => { + (PvfExecKind::Backing(_) | PvfExecKind::BackingSystemParas(_), Some(session_index)) => { let Some(expected_session_index) = maybe_expected_session_index else { let error = "cannot fetch session index from the runtime"; gum::warn!( @@ -731,7 +795,7 @@ async fn validate_candidate_exhaustive( let result = match exec_kind { // Retry is disabled to reduce the chance of nondeterministic blocks getting backed and // honest backers getting slashed. - PvfExecKind::Backing | PvfExecKind::BackingSystemParas => { + PvfExecKind::Backing(_) | PvfExecKind::BackingSystemParas(_) => { let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind.into()); let pvf = PvfPrepData::from_code( @@ -809,6 +873,15 @@ async fn validate_candidate_exhaustive( ); Err(ValidationFailed(e.to_string())) }, + Err(e @ ValidationError::ExecutionDeadline) => { + gum::warn!( + target: LOG_TARGET, + ?para_id, + ?e, + "Job assigned too late, execution queue probably overloaded", + ); + Err(ValidationFailed(e.to_string())) + }, Ok(res) => if res.head_data.hash() != candidate_receipt.descriptor.para_head() { gum::info!(target: LOG_TARGET, ?para_id, "Invalid candidate (para_head)"); @@ -846,7 +919,7 @@ async fn validate_candidate_exhaustive( // descriptor core index. ( Some(_core_index), - PvfExecKind::Backing | PvfExecKind::BackingSystemParas, + PvfExecKind::Backing(_) | PvfExecKind::BackingSystemParas(_), ) => { let Some(claim_queue) = maybe_claim_queue else { let error = "cannot fetch the claim queue from the runtime"; @@ -994,7 +1067,12 @@ trait ValidationBackend { retry_immediately = true; }, - Ok(_) | Err(ValidationError::Invalid(_) | ValidationError::Preparation(_)) => break, + Ok(_) | + Err( + ValidationError::Invalid(_) | + ValidationError::Preparation(_) | + ValidationError::ExecutionDeadline, + ) => break, } // If we got a possibly transient error, retry once after a brief delay, on the @@ -1035,6 +1113,12 @@ trait ValidationBackend { async fn precheck_pvf(&mut self, pvf: PvfPrepData) -> Result<(), PrepareError>; async fn heads_up(&mut self, active_pvfs: Vec) -> Result<(), String>; + + async fn update_active_leaves( + &mut self, + update: ActiveLeavesUpdate, + ancestors: Vec, + ) -> Result<(), String>; } #[async_trait] @@ -1085,6 +1169,14 @@ impl ValidationBackend for ValidationHost { async fn heads_up(&mut self, active_pvfs: Vec) -> Result<(), String> { self.heads_up(active_pvfs).await } + + async fn update_active_leaves( + &mut self, + update: ActiveLeavesUpdate, + ancestors: Vec, + ) -> Result<(), String> { + self.update_active_leaves(update, ancestors).await + } } /// Does basic checks of a candidate. Provide the encoded PoV-block. Returns `Ok` if basic checks diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 391247858ed6..98e34a1cb4c1 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -473,6 +473,14 @@ impl ValidationBackend for MockValidateCandidateBackend { async fn heads_up(&mut self, _active_pvfs: Vec) -> Result<(), String> { unreachable!() } + + async fn update_active_leaves( + &mut self, + _update: ActiveLeavesUpdate, + _ancestors: Vec, + ) -> Result<(), String> { + unreachable!() + } } #[test] @@ -531,7 +539,7 @@ fn session_index_checked_only_in_backing() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )) @@ -670,7 +678,7 @@ fn candidate_validation_ok_is_ok(#[case] v2_descriptor: bool) { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Some(ClaimQueueSnapshot(cq)), )) @@ -748,7 +756,7 @@ fn invalid_session_or_core_index() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )) @@ -764,7 +772,7 @@ fn invalid_session_or_core_index() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::BackingSystemParas, + PvfExecKind::BackingSystemParas(dummy_hash()), &Default::default(), Default::default(), )) @@ -782,7 +790,7 @@ fn invalid_session_or_core_index() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Some(Default::default()), )) @@ -797,7 +805,7 @@ fn invalid_session_or_core_index() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::BackingSystemParas, + PvfExecKind::BackingSystemParas(dummy_hash()), &Default::default(), Some(Default::default()), )) @@ -866,7 +874,7 @@ fn invalid_session_or_core_index() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Some(ClaimQueueSnapshot(cq.clone())), )) @@ -889,7 +897,7 @@ fn invalid_session_or_core_index() { candidate_receipt.clone(), Arc::new(pov.clone()), ExecutorParams::default(), - PvfExecKind::BackingSystemParas, + PvfExecKind::BackingSystemParas(dummy_hash()), &Default::default(), Some(ClaimQueueSnapshot(cq)), )) @@ -944,7 +952,7 @@ fn candidate_validation_bad_return_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )) @@ -1102,7 +1110,7 @@ fn candidate_validation_retry_internal_errors() { #[test] fn candidate_validation_dont_retry_internal_errors() { let v = candidate_validation_retry_on_error_helper( - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), vec![ Err(InternalValidationError::HostCommunication("foo".into()).into()), // Throw an AWD error, we should still retry again. @@ -1136,7 +1144,7 @@ fn candidate_validation_retry_panic_errors() { #[test] fn candidate_validation_dont_retry_panic_errors() { let v = candidate_validation_retry_on_error_helper( - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), vec![ Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError("foo".into()))), // Throw an AWD error, we should still retry again. @@ -1233,7 +1241,7 @@ fn candidate_validation_timeout_is_internal_error() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )); @@ -1282,7 +1290,7 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )) @@ -1337,7 +1345,7 @@ fn candidate_validation_code_mismatch_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )) @@ -1397,7 +1405,7 @@ fn compressed_code_works() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), Default::default(), )); @@ -1436,6 +1444,14 @@ impl ValidationBackend for MockPreCheckBackend { async fn heads_up(&mut self, _active_pvfs: Vec) -> Result<(), String> { unreachable!() } + + async fn update_active_leaves( + &mut self, + _update: ActiveLeavesUpdate, + _ancestors: Vec, + ) -> Result<(), String> { + unreachable!() + } } #[test] @@ -1592,6 +1608,14 @@ impl ValidationBackend for MockHeadsUp { let _ = self.heads_up_call_count.fetch_add(1, Ordering::SeqCst); Ok(()) } + + async fn update_active_leaves( + &mut self, + _update: ActiveLeavesUpdate, + _ancestors: Vec, + ) -> Result<(), String> { + unreachable!() + } } fn alice_keystore() -> KeystorePtr { diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index a8e911e0c5c9..0689a41233c7 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "The Chain API subsystem provides access to chain related utility functions like block number to hash conversions." +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -19,11 +21,11 @@ sc-client-api = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } [dev-dependencies] +codec = { workspace = true, default-features = true } futures = { features = ["thread-pool"], workspace = true } maplit = { workspace = true } -codec = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } -sp-core = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 755d5cadeaaf..e425b9f862a5 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -5,25 +5,27 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +codec = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +kvdb = { workspace = true } 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 } -kvdb = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } thiserror = { workspace = true } -codec = { workspace = true, default-features = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { workspace = true } -sp-core = { workspace = true, default-features = true } -parking_lot = { workspace = true, default-features = true } assert_matches = { workspace = true } kvdb-memorydb = { workspace = true } +parking_lot = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 344b66af1933..6eb3020a0432 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -5,39 +5,41 @@ description = "The node-side components that participate in disputes" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +codec = { workspace = true, default-features = true } +fatality = { workspace = true } futures = { workspace = true } gum = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } kvdb = { workspace = true } -thiserror = { workspace = true } schnellru = { workspace = true } -fatality = { workspace = true } +thiserror = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } 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 } sc-keystore = { workspace = true, default-features = true } [dev-dependencies] +assert_matches = { workspace = true } +futures-timer = { workspace = true } kvdb-memorydb = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } -sp-keyring = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -assert_matches = { workspace = true } +polkadot-primitives = { workspace = true, features = ["test"] } polkadot-primitives-test-helpers = { workspace = true } -futures-timer = { workspace = true } sp-application-crypto = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, features = ["test"] } [features] # If not enabled, the dispute coordinator will do nothing. diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 1e4953f40d0b..264b8da2b44d 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -5,18 +5,20 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Parachains inherent data provider for Polkadot node" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +async-trait = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -thiserror = { workspace = true } -async-trait = { workspace = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } +thiserror = { workspace = true } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 5629e4ef7fbe..0d0ede8d1d9b 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -5,26 +5,28 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "The Prospective Parachains subsystem. Tracks and handles prospective parachain fragments." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +fatality = { workspace = true } futures = { workspace = true } gum = { workspace = true, default-features = true } thiserror = { workspace = true } -fatality = { workspace = true } -polkadot-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 } [dev-dependencies] assert_matches = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } polkadot-primitives = { workspace = true, features = ["test"] } -sp-tracing = { workspace = true } -sp-core = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } rand = { workspace = true } rstest = { workspace = true } +sp-core = { workspace = true, default-features = true } +sp-tracing = { workspace = true } diff --git a/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs index 265d1498ee96..ded0a3ab73b2 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs @@ -630,7 +630,7 @@ impl BackedChain { ) -> impl Iterator + 'a { let mut found_index = None; for index in 0..self.chain.len() { - let node = &self.chain[0]; + let node = &self.chain[index]; if found_index.is_some() { self.by_parent_head.remove(&node.parent_head_data_hash); 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 9708b0871c2a..624dd74132c1 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs @@ -71,7 +71,7 @@ fn make_committed_candidate( persisted_validation_data_hash: persisted_validation_data.hash(), pov_hash: Hash::repeat_byte(1), erasure_root: Hash::repeat_byte(1), - signature: test_helpers::dummy_collator_signature(), + signature: test_helpers::zero_collator_signature(), para_head: para_head.hash(), validation_code_hash: Hash::repeat_byte(42).into(), } @@ -1165,8 +1165,9 @@ fn test_populate_and_check_potential() { Err(Error::CandidateAlreadyKnown) ); - // Simulate a best chain reorg by backing a2. + // Simulate some best chain reorgs. { + // Back A2. The reversion should happen right at the root. let mut chain = chain.clone(); chain.candidate_backed(&candidate_a2_hash); assert_eq!(chain.best_chain_vec(), vec![candidate_a2_hash, candidate_b2_hash]); @@ -1185,6 +1186,66 @@ fn test_populate_and_check_potential() { chain.can_add_candidate_as_potential(&candidate_a_entry), Err(Error::ForkChoiceRule(_)) ); + + // Simulate a more complex chain reorg. + // A2 points to B2, which is backed. + // A2 has underneath a subtree A2 -> B2 -> C3 and A2 -> B2 -> C4. B2 and C3 are backed. C4 + // is kept because it has a lower candidate hash than C3. Backing C4 will cause a chain + // reorg. + + // Candidate C3. + let (pvd_c3, candidate_c3) = make_committed_candidate( + para_id, + relay_parent_y_info.hash, + relay_parent_y_info.number, + vec![0xb4].into(), + vec![0xc2].into(), + relay_parent_y_info.number, + ); + let candidate_c3_hash = candidate_c3.hash(); + let candidate_c3_entry = + CandidateEntry::new(candidate_c3_hash, candidate_c3, pvd_c3, CandidateState::Seconded) + .unwrap(); + + // Candidate C4. + let (pvd_c4, candidate_c4) = make_committed_candidate( + para_id, + relay_parent_y_info.hash, + relay_parent_y_info.number, + vec![0xb4].into(), + vec![0xc3].into(), + relay_parent_y_info.number, + ); + let candidate_c4_hash = candidate_c4.hash(); + // C4 should have a lower candidate hash than C3. + assert_eq!(fork_selection_rule(&candidate_c4_hash, &candidate_c3_hash), Ordering::Less); + let candidate_c4_entry = + CandidateEntry::new(candidate_c4_hash, candidate_c4, pvd_c4, CandidateState::Seconded) + .unwrap(); + + let mut storage = storage.clone(); + storage.add_candidate_entry(candidate_c3_entry).unwrap(); + storage.add_candidate_entry(candidate_c4_entry).unwrap(); + let mut chain = populate_chain_from_previous_storage(&scope, &storage); + chain.candidate_backed(&candidate_a2_hash); + chain.candidate_backed(&candidate_c3_hash); + + assert_eq!( + chain.best_chain_vec(), + vec![candidate_a2_hash, candidate_b2_hash, candidate_c3_hash] + ); + + // Backing C4 will cause a reorg. + chain.candidate_backed(&candidate_c4_hash); + assert_eq!( + chain.best_chain_vec(), + vec![candidate_a2_hash, candidate_b2_hash, candidate_c4_hash] + ); + + assert_eq!( + chain.unconnected().map(|c| c.candidate_hash).collect::>(), + [candidate_f_hash].into_iter().collect() + ); } // Candidate F has an invalid hrmp watermark. however, it was not checked beforehand as we don't diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index 34c1d8823bfc..92aea8509f8c 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -524,7 +524,7 @@ async fn handle_introduce_seconded_candidate( }, }; - let mut added = false; + let mut added = Vec::with_capacity(view.per_relay_parent.len()); let mut para_scheduled = false; // We don't iterate only through the active leaves. We also update the deactivated parents in // the implicit view, so that their upcoming children may see these candidates. @@ -536,18 +536,10 @@ async fn handle_introduce_seconded_candidate( match chain.try_adding_seconded_candidate(&candidate_entry) { Ok(()) => { - gum::debug!( - target: LOG_TARGET, - ?para, - ?relay_parent, - ?is_active_leaf, - "Added seconded candidate {:?}", - candidate_hash - ); - added = true; + added.push(*relay_parent); }, Err(FragmentChainError::CandidateAlreadyKnown) => { - gum::debug!( + gum::trace!( target: LOG_TARGET, ?para, ?relay_parent, @@ -555,10 +547,10 @@ async fn handle_introduce_seconded_candidate( "Attempting to introduce an already known candidate: {:?}", candidate_hash ); - added = true; + added.push(*relay_parent); }, Err(err) => { - gum::debug!( + gum::trace!( target: LOG_TARGET, ?para, ?relay_parent, @@ -580,16 +572,24 @@ async fn handle_introduce_seconded_candidate( ); } - if !added { + if added.is_empty() { gum::debug!( target: LOG_TARGET, para = ?para, candidate = ?candidate_hash, "Newly-seconded candidate cannot be kept under any relay parent", ); + } else { + gum::debug!( + target: LOG_TARGET, + ?para, + "Added/Kept seconded candidate {:?} on relay parents: {:?}", + candidate_hash, + added + ); } - let _ = tx.send(added); + let _ = tx.send(!added.is_empty()); } async fn handle_candidate_backed( @@ -779,12 +779,12 @@ fn answer_hypothetical_membership_request( membership.push(*active_leaf); }, Err(err) => { - gum::debug!( + gum::trace!( target: LOG_TARGET, para = ?para_id, leaf = ?active_leaf, candidate = ?candidate.candidate_hash(), - "Candidate is not a hypothetical member: {}", + "Candidate is not a hypothetical member on: {}", err ) }, @@ -792,6 +792,19 @@ fn answer_hypothetical_membership_request( } } + for (candidate, membership) in &response { + if membership.is_empty() { + gum::debug!( + target: LOG_TARGET, + para = ?candidate.candidate_para(), + active_leaves = ?view.active_leaves, + ?required_active_leaf, + candidate = ?candidate.candidate_hash(), + "Candidate is not a hypothetical member on any of the active leaves", + ) + } + } + let _ = tx.send(response); } diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 64a598b420f7..a3880d5a0f13 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -5,28 +5,30 @@ description = "Responsible for assembling a relay chain block from a set of avai authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] bitvec = { features = ["alloc"], workspace = true } +fatality = { workspace = true } futures = { workspace = true } +futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -thiserror = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } 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 } -futures-timer = { workspace = true } -fatality = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } schnellru = { workspace = true } +thiserror = { workspace = true } [dev-dependencies] -sp-application-crypto = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } polkadot-primitives = { workspace = true, features = ["test"] } +polkadot-primitives-test-helpers = { workspace = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } rstest = { workspace = true } diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index 73ef17a2843a..fac5f85b6b56 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -5,29 +5,31 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] futures = { workspace = true } -thiserror = { workspace = true } gum = { workspace = true, default-features = true } +thiserror = { workspace = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } -polkadot-primitives = { 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 } sp-keystore = { workspace = true, default-features = true } [dev-dependencies] -sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } +futures-timer = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } +sc-keystore = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } -futures-timer = { workspace = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 13fcdc69a99a..f47f7b734285 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -21,27 +23,28 @@ is_executable = { optional = true, workspace = true } pin-project = { workspace = true } rand = { workspace = true, default-features = true } slotmap = { workspace = true } +strum = { features = ["derive"], workspace = true, default-features = true } tempfile = { workspace = true } thiserror = { workspace = true } tokio = { features = ["fs", "process"], workspace = true, default-features = true } -strum = { features = ["derive"], workspace = true, default-features = true } codec = { features = [ "derive", ], workspace = true } -polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-core-primitives = { workspace = true, default-features = true } polkadot-node-core-pvf-common = { workspace = true, default-features = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-core-pvf-execute-worker = { optional = true, workspace = true, default-features = true } +polkadot-node-core-pvf-prepare-worker = { optional = true, workspace = true, default-features = true } +sc-tracing = { workspace = true } sp-core = { workspace = true, default-features = true } sp-maybe-compressed-blob = { optional = true, workspace = true, default-features = true } -polkadot-node-core-pvf-prepare-worker = { optional = true, workspace = true, default-features = true } -polkadot-node-core-pvf-execute-worker = { optional = true, workspace = true, default-features = true } [dev-dependencies] assert_matches = { workspace = true } @@ -52,6 +55,7 @@ criterion = { features = [ hex-literal = { workspace = true, default-features = true } polkadot-node-core-pvf-common = { features = ["test-utils"], workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } # For benches and integration tests, depend on ourselves with the test-utils # feature. polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 903c8dd1af29..d058d582fc26 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 6ad340d25612..4df425dfd199 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -5,16 +5,18 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +cfg-if = { workspace = true } cpu-time = { workspace = true } gum = { workspace = true, default-features = true } -cfg-if = { workspace = true } -nix = { features = ["process", "resource", "sched"], workspace = true } libc = { workspace = true } +nix = { features = ["process", "resource", "sched"], workspace = true } codec = { features = ["derive"], workspace = true } diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 56235bd82192..aa551c196c37 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,11 +16,11 @@ blake3 = { workspace = true } cfg-if = { workspace = true } gum = { workspace = true, default-features = true } libc = { workspace = true } +nix = { features = ["process", "resource", "sched"], workspace = true } rayon = { workspace = true } -tracking-allocator = { workspace = true, default-features = true } tikv-jemalloc-ctl = { optional = true, workspace = true } tikv-jemallocator = { optional = true, workspace = true } -nix = { features = ["process", "resource", "sched"], workspace = true } +tracking-allocator = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true } diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index a0634106052d..e68ba595ef5a 100644 --- a/polkadot/node/core/pvf/src/error.rs +++ b/polkadot/node/core/pvf/src/error.rs @@ -39,6 +39,11 @@ pub enum ValidationError { /// Preparation or execution issue caused by an internal condition. Should not vote against. #[error("candidate validation: internal: {0}")] Internal(#[from] InternalValidationError), + /// The execution deadline of allowed_ancestry_len + 1 has been reached. Jobs like backing have + /// a limited time to execute. Once the deadline is reached, the current candidate cannot be + /// backed, regardless of its validity. + #[error("candidate validation: execution deadline has been reached.")] + ExecutionDeadline, } /// A description of an error raised during executing a PVF and can be attributed to the combination diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index 2ac5116912eb..69355b8fd55d 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -35,8 +35,8 @@ use polkadot_node_core_pvf_common::{ SecurityStatus, }; use polkadot_node_primitives::PoV; -use polkadot_node_subsystem::messages::PvfExecKind; -use polkadot_primitives::{ExecutorParams, ExecutorParamsHash, PersistedValidationData}; +use polkadot_node_subsystem::{messages::PvfExecKind, ActiveLeavesUpdate}; +use polkadot_primitives::{ExecutorParams, ExecutorParamsHash, Hash, PersistedValidationData}; use slotmap::HopSlotMap; use std::{ collections::{HashMap, VecDeque}, @@ -45,7 +45,7 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; -use strum::IntoEnumIterator; +use strum::{EnumIter, IntoEnumIterator}; /// The amount of time a job for which the queue does not have a compatible worker may wait in the /// queue. After that time passes, the queue will kill the first worker which becomes idle to @@ -58,6 +58,7 @@ slotmap::new_key_type! { struct Worker; } #[derive(Debug)] pub enum ToQueue { + UpdateActiveLeaves { update: ActiveLeavesUpdate, ancestors: Vec }, Enqueue { artifact: ArtifactPathId, pending_execution_request: PendingExecutionRequest }, } @@ -82,6 +83,7 @@ pub struct PendingExecutionRequest { struct ExecuteJob { artifact: ArtifactPathId, exec_timeout: Duration, + exec_kind: PvfExecKind, pvd: Arc, pov: Arc, executor_params: ExecutorParams, @@ -172,6 +174,9 @@ struct Queue { unscheduled: Unscheduled, workers: Workers, mux: Mux, + + /// Active leaves and their ancestors to check the viability of backing jobs. + active_leaves: HashMap>, } impl Queue { @@ -202,6 +207,7 @@ impl Queue { spawn_inflight: 0, capacity: worker_capacity, }, + active_leaves: Default::default(), } } @@ -278,15 +284,72 @@ impl Queue { } let job = queue.remove(job_index).expect("Job is just checked to be in queue; qed"); + let exec_kind = job.exec_kind; if let Some(worker) = worker { assign(self, worker, job); } else { spawn_extra_worker(self, job); } - self.metrics.on_execute_kind(priority); + self.metrics.on_execute_kind(exec_kind); self.unscheduled.mark_scheduled(priority); } + + fn update_active_leaves(&mut self, update: ActiveLeavesUpdate, ancestors: Vec) { + self.prune_deactivated_leaves(&update); + self.insert_active_leaf(update, ancestors); + self.prune_old_jobs(); + } + + fn prune_deactivated_leaves(&mut self, update: &ActiveLeavesUpdate) { + for hash in &update.deactivated { + let _ = self.active_leaves.remove(&hash); + } + } + + fn insert_active_leaf(&mut self, update: ActiveLeavesUpdate, ancestors: Vec) { + let Some(leaf) = update.activated else { return }; + let _ = self.active_leaves.insert(leaf.hash, ancestors); + } + + fn prune_old_jobs(&mut self) { + for &priority in &[Priority::Backing, Priority::BackingSystemParas] { + let Some(queue) = self.unscheduled.get_mut(priority) else { continue }; + let to_remove: Vec = queue + .iter() + .enumerate() + .filter_map(|(index, job)| { + let relay_parent = match job.exec_kind { + PvfExecKind::Backing(x) | PvfExecKind::BackingSystemParas(x) => x, + _ => return None, + }; + let in_active_fork = self.active_leaves.iter().any(|(hash, ancestors)| { + *hash == relay_parent || ancestors.contains(&relay_parent) + }); + if in_active_fork { + None + } else { + Some(index) + } + }) + .collect(); + + for &index in to_remove.iter().rev() { + if index > queue.len() { + continue + } + + let Some(job) = queue.remove(index) else { continue }; + let _ = job.result_tx.send(Err(ValidationError::ExecutionDeadline)); + gum::warn!( + target: LOG_TARGET, + ?priority, + exec_kind = ?job.exec_kind, + "Job exceeded its deadline and was dropped without execution", + ); + } + } + } } async fn purge_dead(metrics: &Metrics, workers: &mut Workers) { @@ -305,27 +368,40 @@ async fn purge_dead(metrics: &Metrics, workers: &mut Workers) { } fn handle_to_queue(queue: &mut Queue, to_queue: ToQueue) { - let ToQueue::Enqueue { artifact, pending_execution_request } = to_queue; - let PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx, exec_kind } = - pending_execution_request; - gum::debug!( - target: LOG_TARGET, - validation_code_hash = ?artifact.id.code_hash, - "enqueueing an artifact for execution", - ); - queue.metrics.observe_pov_size(pov.block_data.0.len(), true); - queue.metrics.execute_enqueued(); - let job = ExecuteJob { - artifact, - exec_timeout, - pvd, - pov, - executor_params, - result_tx, - waiting_since: Instant::now(), - }; - queue.unscheduled.add(job, exec_kind); - queue.try_assign_next_job(None); + match to_queue { + ToQueue::UpdateActiveLeaves { update, ancestors } => { + queue.update_active_leaves(update, ancestors); + }, + ToQueue::Enqueue { artifact, pending_execution_request } => { + let PendingExecutionRequest { + exec_timeout, + pvd, + pov, + executor_params, + result_tx, + exec_kind, + } = pending_execution_request; + gum::debug!( + target: LOG_TARGET, + validation_code_hash = ?artifact.id.code_hash, + "enqueueing an artifact for execution", + ); + queue.metrics.observe_pov_size(pov.block_data.0.len(), true); + queue.metrics.execute_enqueued(); + let job = ExecuteJob { + artifact, + exec_timeout, + exec_kind, + pvd, + pov, + executor_params, + result_tx, + waiting_since: Instant::now(), + }; + queue.unscheduled.add(job, exec_kind.into()); + queue.try_assign_next_job(None); + }, + } } async fn handle_mux(queue: &mut Queue, event: QueueEvent) { @@ -648,9 +724,32 @@ pub fn start( (to_queue_tx, from_queue_rx, run) } +/// Priority of execution jobs based on PvfExecKind. +/// +/// The order is important, because we iterate through the values and assume it is going from higher +/// to lowest priority. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumIter)] +enum Priority { + Dispute, + Approval, + BackingSystemParas, + Backing, +} + +impl From for Priority { + fn from(kind: PvfExecKind) -> Self { + match kind { + PvfExecKind::Dispute => Priority::Dispute, + PvfExecKind::Approval => Priority::Approval, + PvfExecKind::BackingSystemParas(_) => Priority::BackingSystemParas, + PvfExecKind::Backing(_) => Priority::Backing, + } + } +} + struct Unscheduled { - unscheduled: HashMap>, - counter: HashMap, + unscheduled: HashMap>, + counter: HashMap, } impl Unscheduled { @@ -677,34 +776,34 @@ impl Unscheduled { /// approvals could not exceed 24%, even if there are no disputes. /// - We cannot fully prioritize backing system parachains over backing other parachains based /// on the distribution of the original 100%. - const PRIORITY_ALLOCATION_THRESHOLDS: &'static [(PvfExecKind, usize)] = &[ - (PvfExecKind::Dispute, 70), - (PvfExecKind::Approval, 80), - (PvfExecKind::BackingSystemParas, 100), - (PvfExecKind::Backing, 100), + const PRIORITY_ALLOCATION_THRESHOLDS: &'static [(Priority, usize)] = &[ + (Priority::Dispute, 70), + (Priority::Approval, 80), + (Priority::BackingSystemParas, 100), + (Priority::Backing, 100), ]; fn new() -> Self { Self { - unscheduled: PvfExecKind::iter().map(|priority| (priority, VecDeque::new())).collect(), - counter: PvfExecKind::iter().map(|priority| (priority, 0)).collect(), + unscheduled: Priority::iter().map(|priority| (priority, VecDeque::new())).collect(), + counter: Priority::iter().map(|priority| (priority, 0)).collect(), } } - fn select_next_priority(&self) -> PvfExecKind { + fn select_next_priority(&self) -> Priority { gum::debug!( target: LOG_TARGET, - unscheduled = ?self.unscheduled.iter().map(|(p, q)| (*p, q.len())).collect::>(), + unscheduled = ?self.unscheduled.iter().map(|(p, q)| (*p, q.len())).collect::>(), counter = ?self.counter, "Selecting next execution priority...", ); - let priority = PvfExecKind::iter() + let priority = Priority::iter() .find(|priority| self.has_pending(priority) && !self.has_reached_threshold(priority)) .unwrap_or_else(|| { - PvfExecKind::iter() + Priority::iter() .find(|priority| self.has_pending(priority)) - .unwrap_or(PvfExecKind::Backing) + .unwrap_or(Priority::Backing) }); gum::debug!( @@ -716,19 +815,19 @@ impl Unscheduled { priority } - fn get_mut(&mut self, priority: PvfExecKind) -> Option<&mut VecDeque> { + fn get_mut(&mut self, priority: Priority) -> Option<&mut VecDeque> { self.unscheduled.get_mut(&priority) } - fn add(&mut self, job: ExecuteJob, priority: PvfExecKind) { + fn add(&mut self, job: ExecuteJob, priority: Priority) { self.unscheduled.entry(priority).or_default().push_back(job); } - fn has_pending(&self, priority: &PvfExecKind) -> bool { + fn has_pending(&self, priority: &Priority) -> bool { !self.unscheduled.get(priority).unwrap_or(&VecDeque::new()).is_empty() } - fn priority_allocation_threshold(priority: &PvfExecKind) -> Option { + fn priority_allocation_threshold(priority: &Priority) -> Option { Self::PRIORITY_ALLOCATION_THRESHOLDS.iter().find_map(|&(p, value)| { if p == *priority { Some(value) @@ -740,7 +839,7 @@ impl Unscheduled { /// Checks if a given priority has reached its allocated threshold /// The thresholds are defined in `PRIORITY_ALLOCATION_THRESHOLDS`. - fn has_reached_threshold(&self, priority: &PvfExecKind) -> bool { + fn has_reached_threshold(&self, priority: &Priority) -> bool { let Some(threshold) = Self::priority_allocation_threshold(priority) else { return false }; let Some(count) = self.counter.get(&priority) else { return false }; // Every time we iterate by lower level priorities @@ -769,22 +868,28 @@ impl Unscheduled { has_reached_threshold } - fn mark_scheduled(&mut self, priority: PvfExecKind) { + fn mark_scheduled(&mut self, priority: Priority) { *self.counter.entry(priority).or_default() += 1; if self.counter.values().sum::() >= Self::SCHEDULING_WINDOW_SIZE { self.reset_counter(); } + gum::debug!( + target: LOG_TARGET, + ?priority, + "Job marked as scheduled", + ); } fn reset_counter(&mut self) { - self.counter = PvfExecKind::iter().map(|kind| (kind, 0)).collect(); + self.counter = Priority::iter().map(|kind| (kind, 0)).collect(); } } #[cfg(test)] mod tests { use polkadot_node_primitives::BlockData; + use polkadot_node_subsystem_test_helpers::mock::new_leaf; use sp_core::H256; use super::*; @@ -803,6 +908,7 @@ mod tests { ExecuteJob { artifact: ArtifactPathId { id: artifact_id(0), path: PathBuf::new() }, exec_timeout: Duration::from_secs(10), + exec_kind: PvfExecKind::Approval, pvd, pov, executor_params: ExecutorParams::default(), @@ -815,11 +921,11 @@ mod tests { fn test_unscheduled_add() { let mut unscheduled = Unscheduled::new(); - PvfExecKind::iter().for_each(|priority| { + Priority::iter().for_each(|priority| { unscheduled.add(create_execution_job(), priority); }); - PvfExecKind::iter().for_each(|priority| { + Priority::iter().for_each(|priority| { let queue = unscheduled.unscheduled.get(&priority).unwrap(); assert_eq!(queue.len(), 1); }); @@ -827,7 +933,7 @@ mod tests { #[test] fn test_unscheduled_priority_distribution() { - use PvfExecKind::*; + use Priority::*; let mut priorities = vec![]; @@ -852,7 +958,7 @@ mod tests { #[test] fn test_unscheduled_priority_distribution_without_backing_system_paras() { - use PvfExecKind::*; + use Priority::*; let mut priorities = vec![]; @@ -876,7 +982,7 @@ mod tests { #[test] fn test_unscheduled_priority_distribution_without_disputes() { - use PvfExecKind::*; + use Priority::*; let mut priorities = vec![]; @@ -900,7 +1006,7 @@ mod tests { #[test] fn test_unscheduled_priority_distribution_without_disputes_and_only_one_backing() { - use PvfExecKind::*; + use Priority::*; let mut priorities = vec![]; @@ -922,7 +1028,7 @@ mod tests { #[test] fn test_unscheduled_does_not_postpone_backing() { - use PvfExecKind::*; + use Priority::*; let mut priorities = vec![]; @@ -940,4 +1046,67 @@ mod tests { assert_eq!(&priorities[..4], &[Approval, Backing, Approval, Approval]); } + + #[tokio::test] + async fn test_prunes_old_jobs_on_active_leaves_update() { + // Set up a queue, but without a real worker, we won't execute any jobs. + let (_, to_queue_rx) = mpsc::channel(1); + let (from_queue_tx, _) = mpsc::unbounded(); + let mut queue = Queue::new( + Metrics::default(), + PathBuf::new(), + PathBuf::new(), + 1, + Duration::from_secs(1), + None, + SecurityStatus::default(), + to_queue_rx, + from_queue_tx, + ); + let old_relay_parent = Hash::random(); + let relevant_relay_parent = Hash::random(); + + assert_eq!(queue.unscheduled.unscheduled.values().map(|x| x.len()).sum::(), 0); + let mut result_rxs = vec![]; + let (result_tx, _result_rx) = oneshot::channel(); + let relevant_job = ExecuteJob { + artifact: ArtifactPathId { id: artifact_id(0), path: PathBuf::new() }, + exec_timeout: Duration::from_secs(1), + exec_kind: PvfExecKind::Backing(relevant_relay_parent), + pvd: Arc::new(PersistedValidationData::default()), + pov: Arc::new(PoV { block_data: BlockData(Vec::new()) }), + executor_params: ExecutorParams::default(), + result_tx, + waiting_since: Instant::now(), + }; + queue.unscheduled.add(relevant_job, Priority::Backing); + for _ in 0..10 { + let (result_tx, result_rx) = oneshot::channel(); + let expired_job = ExecuteJob { + artifact: ArtifactPathId { id: artifact_id(0), path: PathBuf::new() }, + exec_timeout: Duration::from_secs(1), + exec_kind: PvfExecKind::Backing(old_relay_parent), + pvd: Arc::new(PersistedValidationData::default()), + pov: Arc::new(PoV { block_data: BlockData(Vec::new()) }), + executor_params: ExecutorParams::default(), + result_tx, + waiting_since: Instant::now(), + }; + queue.unscheduled.add(expired_job, Priority::Backing); + result_rxs.push(result_rx); + } + assert_eq!(queue.unscheduled.unscheduled.values().map(|x| x.len()).sum::(), 11); + + // Add an active leaf + queue.update_active_leaves( + ActiveLeavesUpdate::start_work(new_leaf(Hash::random(), 1)), + vec![relevant_relay_parent], + ); + + // It prunes all old jobs and drops them with an `ExecutionDeadline` error. + for rx in result_rxs { + assert!(matches!(rx.await, Ok(Err(ValidationError::ExecutionDeadline)))); + } + assert_eq!(queue.unscheduled.unscheduled.values().map(|x| x.len()).sum::(), 1); + } } diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 37cd6fcbf74a..8252904095b3 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -37,9 +37,11 @@ use polkadot_node_core_pvf_common::{ pvf::PvfPrepData, }; use polkadot_node_primitives::PoV; -use polkadot_node_subsystem::{messages::PvfExecKind, SubsystemError, SubsystemResult}; +use polkadot_node_subsystem::{ + messages::PvfExecKind, ActiveLeavesUpdate, SubsystemError, SubsystemResult, +}; use polkadot_parachain_primitives::primitives::ValidationResult; -use polkadot_primitives::PersistedValidationData; +use polkadot_primitives::{Hash, PersistedValidationData}; use std::{ collections::HashMap, path::PathBuf, @@ -143,12 +145,27 @@ impl ValidationHost { .await .map_err(|_| "the inner loop hung up".to_string()) } + + /// Sends a signal to the validation host requesting to update best block. + /// + /// Returns an error if the request cannot be sent to the validation host, i.e. if it shut down. + pub async fn update_active_leaves( + &mut self, + update: ActiveLeavesUpdate, + ancestors: Vec, + ) -> Result<(), String> { + self.to_host_tx + .send(ToHost::UpdateActiveLeaves { update, ancestors }) + .await + .map_err(|_| "the inner loop hung up".to_string()) + } } enum ToHost { PrecheckPvf { pvf: PvfPrepData, result_tx: PrecheckResultSender }, ExecutePvf(ExecutePvfInputs), HeadsUp { active_pvfs: Vec }, + UpdateActiveLeaves { update: ActiveLeavesUpdate, ancestors: Vec }, } struct ExecutePvfInputs { @@ -488,6 +505,8 @@ async fn handle_to_host( }, ToHost::HeadsUp { active_pvfs } => handle_heads_up(artifacts, prepare_queue, active_pvfs).await?, + ToHost::UpdateActiveLeaves { update, ancestors } => + handle_update_active_leaves(execute_queue, update, ancestors).await?, } Ok(()) @@ -855,6 +874,14 @@ async fn handle_prepare_done( Ok(()) } +async fn handle_update_active_leaves( + execute_queue: &mut mpsc::Sender, + update: ActiveLeavesUpdate, + ancestors: Vec, +) -> Result<(), Fatal> { + send_execute(execute_queue, execute::ToQueue::UpdateActiveLeaves { update, ancestors }).await +} + async fn send_prepare( prepare_queue: &mut mpsc::Sender, to_queue: prepare::ToQueue, @@ -1255,7 +1282,7 @@ pub(crate) mod tests { pvd.clone(), pov1.clone(), Priority::Normal, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1268,7 +1295,7 @@ pub(crate) mod tests { pvd.clone(), pov1, Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1281,7 +1308,7 @@ pub(crate) mod tests { pvd, pov2, Priority::Normal, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1431,7 +1458,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1480,7 +1507,7 @@ pub(crate) mod tests { pvd, pov, Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1591,7 +1618,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1623,7 +1650,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx_2, ) .await @@ -1647,7 +1674,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx_3, ) .await @@ -1706,7 +1733,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1738,7 +1765,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx_2, ) .await @@ -1762,7 +1789,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx_3, ) .await @@ -1837,7 +1864,7 @@ pub(crate) mod tests { pvd, pov, Priority::Normal, - PvfExecKind::Backing, + PvfExecKind::Backing(H256::default()), result_tx, ) .await diff --git a/polkadot/node/core/pvf/src/priority.rs b/polkadot/node/core/pvf/src/priority.rs index 7aaeacf36220..5a58fbc8ade3 100644 --- a/polkadot/node/core/pvf/src/priority.rs +++ b/polkadot/node/core/pvf/src/priority.rs @@ -43,8 +43,8 @@ impl From for Priority { match priority { PvfExecKind::Dispute => Priority::Critical, PvfExecKind::Approval => Priority::Critical, - PvfExecKind::BackingSystemParas => Priority::Normal, - PvfExecKind::Backing => Priority::Normal, + PvfExecKind::BackingSystemParas(_) => Priority::Normal, + PvfExecKind::Backing(_) => Priority::Normal, } } } diff --git a/polkadot/node/core/pvf/src/worker_interface.rs b/polkadot/node/core/pvf/src/worker_interface.rs index e63778d4692f..f279fbb53544 100644 --- a/polkadot/node/core/pvf/src/worker_interface.rs +++ b/polkadot/node/core/pvf/src/worker_interface.rs @@ -237,10 +237,8 @@ impl WorkerHandle { // Clear all env vars from the spawned process. let mut command = process::Command::new(program.as_ref()); command.env_clear(); - // Add back any env vars we want to keep. - if let Ok(value) = std::env::var("RUST_LOG") { - command.env("RUST_LOG", value); - } + + command.env("RUST_LOG", sc_tracing::logging::get_directives().join(",")); let mut child = command .args(extra_args) diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index 1a95a28fe077..924ea7166702 100644 --- a/polkadot/node/core/pvf/tests/it/adder.rs +++ b/polkadot/node/core/pvf/tests/it/adder.rs @@ -46,6 +46,7 @@ async fn execute_good_block_on_parent() { pvd, pov, Default::default(), + H256::default(), ) .await .unwrap(); @@ -82,6 +83,7 @@ async fn execute_good_chain_on_parent() { pvd, pov, Default::default(), + H256::default(), ) .await .unwrap(); @@ -120,6 +122,7 @@ async fn execute_bad_block_on_parent() { pvd, pov, Default::default(), + H256::default(), ) .await .unwrap_err(); @@ -145,6 +148,7 @@ async fn stress_spawn() { pvd, pov, Default::default(), + H256::default(), ) .await .unwrap(); @@ -185,6 +189,7 @@ async fn execute_can_run_serially() { pvd, pov, Default::default(), + H256::default(), ) .await .unwrap(); diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 4cbc6fb04a8e..cfb78fd530d2 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -28,8 +28,8 @@ use polkadot_node_primitives::{PoV, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT}; use polkadot_node_subsystem::messages::PvfExecKind; use polkadot_parachain_primitives::primitives::{BlockData, ValidationResult}; use polkadot_primitives::{ - ExecutorParam, ExecutorParams, PersistedValidationData, PvfExecKind as RuntimePvfExecKind, - PvfPrepKind, + ExecutorParam, ExecutorParams, Hash, PersistedValidationData, + PvfExecKind as RuntimePvfExecKind, PvfPrepKind, }; use sp_core::H256; @@ -108,6 +108,7 @@ impl TestHost { pvd: PersistedValidationData, pov: PoV, executor_params: ExecutorParams, + relay_parent: Hash, ) -> Result { let (result_tx, result_rx) = futures::channel::oneshot::channel(); @@ -125,7 +126,7 @@ impl TestHost { Arc::new(pvd), Arc::new(pov), polkadot_node_core_pvf::Priority::Normal, - PvfExecKind::Backing, + PvfExecKind::Backing(relay_parent), result_tx, ) .await @@ -171,7 +172,13 @@ async fn execute_job_terminates_on_timeout() { let start = std::time::Instant::now(); let result = host - .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) + .validate_candidate( + test_parachain_halt::wasm_binary_unwrap(), + pvd, + pov, + Default::default(), + H256::default(), + ) .await; match result { @@ -201,12 +208,14 @@ async fn ensure_parallel_execution() { pvd.clone(), pov.clone(), Default::default(), + H256::default(), ); let execute_pvf_future_2 = host.validate_candidate( test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default(), + H256::default(), ); let start = std::time::Instant::now(); @@ -254,6 +263,7 @@ async fn execute_queue_doesnt_stall_if_workers_died() { pvd.clone(), pov.clone(), Default::default(), + H256::default(), ) })) .await; @@ -303,6 +313,7 @@ async fn execute_queue_doesnt_stall_with_varying_executor_params() { 0 => executor_params_1.clone(), _ => executor_params_2.clone(), }, + H256::default(), ) })) .await; @@ -359,7 +370,13 @@ async fn deleting_prepared_artifact_does_not_dispute() { // Try to validate, artifact should get recreated. let result = host - .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) + .validate_candidate( + test_parachain_halt::wasm_binary_unwrap(), + pvd, + pov, + Default::default(), + H256::default(), + ) .await; assert_matches!(result, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout))); @@ -410,7 +427,13 @@ async fn corrupted_prepared_artifact_does_not_dispute() { // Try to validate, artifact should get removed because of the corruption. let result = host - .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) + .validate_candidate( + test_parachain_halt::wasm_binary_unwrap(), + pvd, + pov, + Default::default(), + H256::default(), + ) .await; assert_matches!( @@ -684,7 +707,9 @@ async fn invalid_compressed_code_fails_validation() { let validation_code = sp_maybe_compressed_blob::compress(&raw_code, VALIDATION_CODE_BOMB_LIMIT + 1).unwrap(); - let result = host.validate_candidate(&validation_code, pvd, pov, Default::default()).await; + let result = host + .validate_candidate(&validation_code, pvd, pov, Default::default(), H256::default()) + .await; assert_matches!( result, @@ -708,7 +733,13 @@ async fn invalid_compressed_pov_fails_validation() { let pov = PoV { block_data: BlockData(block_data) }; let result = host - .validate_candidate(test_parachain_halt::wasm_binary_unwrap(), pvd, pov, Default::default()) + .validate_candidate( + test_parachain_halt::wasm_binary_unwrap(), + pvd, + pov, + Default::default(), + H256::default(), + ) .await; assert_matches!( diff --git a/polkadot/node/core/pvf/tests/it/process.rs b/polkadot/node/core/pvf/tests/it/process.rs index b3023c8a45c3..353367b394f3 100644 --- a/polkadot/node/core/pvf/tests/it/process.rs +++ b/polkadot/node/core/pvf/tests/it/process.rs @@ -141,6 +141,7 @@ rusty_fork_test! { pvd, pov, Default::default(), + H256::default(), ) .await .unwrap(); @@ -187,6 +188,7 @@ rusty_fork_test! { pvd, pov, Default::default(), + H256::default(), ), // Send a stop signal to pause the worker. async { @@ -242,6 +244,7 @@ rusty_fork_test! { pvd, pov, Default::default(), + H256::default(), ), // Run a future that kills the job while it's running. async { @@ -301,6 +304,7 @@ rusty_fork_test! { pvd, pov, Default::default(), + H256::default(), ), // Run a future that kills the job while it's running. async { @@ -372,6 +376,7 @@ rusty_fork_test! { pvd, pov, Default::default(), + H256::default(), ), // Run a future that tests the thread count while the worker is running. async { diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index 834e4b300b9e..65c92dc5c070 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -5,6 +5,8 @@ description = "Wrapper around the parachain-related runtime APIs" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -16,17 +18,17 @@ schnellru = { workspace = true } sp-consensus-babe = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } [dev-dependencies] -sp-api = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } async-trait = { workspace = true } futures = { features = ["thread-pool"], workspace = true } -polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } +sp-api = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } diff --git a/polkadot/node/gum/Cargo.toml b/polkadot/node/gum/Cargo.toml index 9b2df435a06a..f4c22dd7595e 100644 --- a/polkadot/node/gum/Cargo.toml +++ b/polkadot/node/gum/Cargo.toml @@ -5,12 +5,14 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Stick logs together with the TraceID as provided by tempo" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] coarsetime = { workspace = true } -tracing = { workspace = true, default-features = true } gum-proc-macro = { workspace = true, default-features = true } polkadot-primitives = { features = ["std"], workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index da6364977cae..0b69d8b67cf1 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Generate an overseer including builder pattern and message wrapper from a single annotated struct definition." +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -16,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { features = ["extra-traits", "full"], workspace = true } -quote = { workspace = true } -proc-macro2 = { workspace = true } -proc-macro-crate = { workspace = true } expander = { workspace = true } +proc-macro-crate = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { features = ["extra-traits", "full"], workspace = true } [dev-dependencies] assert_matches = { workspace = true } diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 49434606a61c..84a58f382e20 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -29,27 +29,27 @@ path = "../../src/bin/prepare-worker.rs" doc = false [dependencies] -polkadot-cli = { features = ["malus", "rococo-native", "westend-native"], workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } -polkadot-node-subsystem-types = { workspace = true, default-features = true } -polkadot-node-core-dispute-coordinator = { workspace = true, default-features = true } -polkadot-node-core-candidate-validation = { workspace = true, default-features = true } -polkadot-node-core-backing = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-node-network-protocol = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -color-eyre = { workspace = true } assert_matches = { workspace = true } async-trait = { workspace = true } -sp-keystore = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } clap = { features = ["derive"], workspace = true } +color-eyre = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } +polkadot-cli = { features = ["malus", "rococo-native", "westend-native"], workspace = true, default-features = true } polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-core-backing = { workspace = true, default-features = true } +polkadot-node-core-candidate-validation = { workspace = true, default-features = true } +polkadot-node-core-dispute-coordinator = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } # Required for worker binaries to build. polkadot-node-core-pvf-common = { workspace = true, default-features = true } @@ -57,9 +57,9 @@ polkadot-node-core-pvf-execute-worker = { workspace = true, default-features = t polkadot-node-core-pvf-prepare-worker = { workspace = true, default-features = true } [dev-dependencies] +futures = { features = ["thread-pool"], workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } sp-core = { workspace = true, default-features = true } -futures = { features = ["thread-pool"], workspace = true } [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index 41b08b66e9b4..454337cb63f8 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -16,28 +18,28 @@ gum = { workspace = true, default-features = true } metered = { features = ["futures_channel"], workspace = true } # Both `sc-service` and `sc-cli` are required by runtime metrics `logger_hook()`. -sc-service = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } -sc-tracing = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } bs58 = { features = ["alloc"], workspace = true, default-features = true } +codec = { workspace = true, default-features = true } log = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } [dev-dependencies] assert_cmd = { workspace = true } -tempfile = { workspace = true } -hyper-util = { features = ["client-legacy", "tokio"], workspace = true } -hyper = { workspace = true } http-body-util = { workspace = true } -tokio = { workspace = true, default-features = true } +hyper = { workspace = true } +hyper-util = { features = ["client-legacy", "tokio"], workspace = true } polkadot-test-service = { features = ["runtime-metrics"], workspace = true } -substrate-test-utils = { workspace = true } +prometheus-parse = { workspace = true } sc-service = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } -prometheus-parse = { workspace = true } +substrate-test-utils = { workspace = true } +tempfile = { workspace = true } +tokio = { workspace = true, default-features = true } [features] default = [] diff --git a/polkadot/node/metrics/src/tests.rs b/polkadot/node/metrics/src/tests.rs index 4760138058eb..43dce0ec2ffe 100644 --- a/polkadot/node/metrics/src/tests.rs +++ b/polkadot/node/metrics/src/tests.rs @@ -21,7 +21,7 @@ use hyper::Uri; use hyper_util::{client::legacy::Client, rt::TokioExecutor}; use polkadot_primitives::metric_definitions::PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED; use polkadot_test_service::{node_config, run_validator_node, test_prometheus_config}; -use sp_keyring::AccountKeyring::*; +use sp_keyring::Sr25519Keyring::*; use std::collections::HashMap; const DEFAULT_PROMETHEUS_PORT: u16 = 9616; diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 8d674a733470..d9d3fd8635a6 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -5,11 +5,14 @@ description = "Polkadot Approval Distribution subsystem for the distribution of authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +itertools = { workspace = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } @@ -17,12 +20,11 @@ polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } -itertools = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -bitvec = { features = ["alloc"], workspace = true } [dev-dependencies] sc-keystore = { workspace = true } @@ -36,7 +38,7 @@ polkadot-primitives-test-helpers = { workspace = true } assert_matches = { workspace = true } schnorrkel = { workspace = true } # rand_core should match schnorrkel -rand_core = { workspace = true } +log = { workspace = true, default-features = true } rand_chacha = { workspace = true, default-features = true } +rand_core = { workspace = true } sp-tracing = { workspace = true } -log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index 876cc59b9c28..cefb1d744992 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -163,8 +163,6 @@ enum ApprovalEntryError { InvalidCandidateIndex, DuplicateApproval, UnknownAssignment, - #[allow(dead_code)] - AssignmentsFollowedDifferentPaths(RequiredRouting, RequiredRouting), } impl ApprovalEntry { @@ -318,7 +316,7 @@ impl Default for AggressionConfig { fn default() -> Self { AggressionConfig { l1_threshold: Some(16), - l2_threshold: Some(28), + l2_threshold: Some(64), resend_unfinalized_period: Some(8), } } @@ -514,6 +512,8 @@ struct BlockEntry { vrf_story: RelayVRFStory, /// The block slot. slot: Slot, + /// Backing off from re-sending messages to peers. + last_resent_at_block_number: Option, } impl BlockEntry { @@ -568,7 +568,7 @@ impl BlockEntry { &mut self, approval: IndirectSignedApprovalVoteV2, ) -> Result<(RequiredRouting, HashSet), ApprovalEntryError> { - let mut required_routing = None; + let mut required_routing: Option = None; let mut peers_randomly_routed_to = HashSet::new(); if self.candidates.len() < approval.candidate_indices.len() as usize { @@ -595,16 +595,11 @@ impl BlockEntry { peers_randomly_routed_to .extend(approval_entry.routing_info().peers_randomly_routed.iter()); - if let Some(required_routing) = required_routing { - if required_routing != approval_entry.routing_info().required_routing { - // This shouldn't happen since the required routing is computed based on the - // validator_index, so two assignments from the same validators will have - // the same required routing. - return Err(ApprovalEntryError::AssignmentsFollowedDifferentPaths( - required_routing, - approval_entry.routing_info().required_routing, - )) - } + if let Some(current_required_routing) = required_routing { + required_routing = Some( + current_required_routing + .combine(approval_entry.routing_info().required_routing), + ); } else { required_routing = Some(approval_entry.routing_info().required_routing) } @@ -885,6 +880,7 @@ impl State { candidates_metadata: meta.candidates, vrf_story: meta.vrf_story, slot: meta.slot, + last_resent_at_block_number: None, }); self.topologies.inc_session_refs(meta.session); @@ -1324,6 +1320,33 @@ impl State { self.enable_aggression(network_sender, Resend::No, metrics).await; } + // When finality is lagging as a last resort nodes start sending the messages they have + // multiples times. This means it is safe to accept duplicate messages without punishing the + // peer and reduce the reputation and can end up banning the Peer, which in turn will create + // more no-shows. + fn accept_duplicates_from_validators( + blocks_by_number: &BTreeMap>, + topologies: &SessionGridTopologies, + aggression_config: &AggressionConfig, + entry: &BlockEntry, + peer: PeerId, + ) -> bool { + let topology = topologies.get_topology(entry.session); + let min_age = blocks_by_number.iter().next().map(|(num, _)| num); + let max_age = blocks_by_number.iter().rev().next().map(|(num, _)| num); + + // Return if we don't have at least 1 block. + let (min_age, max_age) = match (min_age, max_age) { + (Some(min), Some(max)) => (*min, *max), + _ => return false, + }; + + let age = max_age.saturating_sub(min_age); + + aggression_config.should_trigger_aggression(age) && + topology.map(|topology| topology.is_validator(&peer)).unwrap_or(false) + } + async fn import_and_circulate_assignment( &mut self, approval_voting_sender: &mut A, @@ -1388,20 +1411,29 @@ impl State { if peer_knowledge.contains(&message_subject, message_kind) { // wasn't included before if !peer_knowledge.received.insert(message_subject.clone(), message_kind) { - gum::debug!( - target: LOG_TARGET, - ?peer_id, - ?message_subject, - "Duplicate assignment", - ); - - modify_reputation( - &mut self.reputation, - network_sender, + if !Self::accept_duplicates_from_validators( + &self.blocks_by_number, + &self.topologies, + &self.aggression_config, + entry, peer_id, - COST_DUPLICATE_MESSAGE, - ) - .await; + ) { + gum::debug!( + target: LOG_TARGET, + ?peer_id, + ?message_subject, + "Duplicate assignment", + ); + + modify_reputation( + &mut self.reputation, + network_sender, + peer_id, + COST_DUPLICATE_MESSAGE, + ) + .await; + } + metrics.on_assignment_duplicate(); } else { gum::trace!( @@ -1717,6 +1749,9 @@ impl State { assignments_knowledge_key: &Vec<(MessageSubject, MessageKind)>, approval_knowledge_key: &(MessageSubject, MessageKind), entry: &mut BlockEntry, + blocks_by_number: &BTreeMap>, + topologies: &SessionGridTopologies, + aggression_config: &AggressionConfig, reputation: &mut ReputationAggregator, peer_id: PeerId, metrics: &Metrics, @@ -1745,20 +1780,27 @@ impl State { .received .insert(approval_knowledge_key.0.clone(), approval_knowledge_key.1) { - gum::trace!( - target: LOG_TARGET, - ?peer_id, - ?approval_knowledge_key, - "Duplicate approval", - ); - - modify_reputation( - reputation, - network_sender, + if !Self::accept_duplicates_from_validators( + blocks_by_number, + topologies, + aggression_config, + entry, peer_id, - COST_DUPLICATE_MESSAGE, - ) - .await; + ) { + gum::trace!( + target: LOG_TARGET, + ?peer_id, + ?approval_knowledge_key, + "Duplicate approval", + ); + modify_reputation( + reputation, + network_sender, + peer_id, + COST_DUPLICATE_MESSAGE, + ) + .await; + } metrics.on_approval_duplicate(); } return false @@ -1850,6 +1892,9 @@ impl State { &assignments_knowledge_keys, &approval_knwowledge_key, entry, + &self.blocks_by_number, + &self.topologies, + &self.aggression_config, &mut self.reputation, peer_id, metrics, @@ -2260,18 +2305,43 @@ impl State { &self.topologies, |block_entry| { let block_age = max_age - block_entry.number; + // We want to resend only for blocks of min_age, there is no point in + // resending for blocks newer than that, because we are just going to create load + // and not gain anything. + let diff_from_min_age = block_entry.number - min_age; + + // We want to back-off on resending for blocks that have been resent recently, to + // give time for nodes to process all the extra messages, if we still have not + // finalized we are going to resend again after unfinalized_period * 2 since the + // last resend. + let blocks_since_last_sent = block_entry + .last_resent_at_block_number + .map(|last_resent_at_block_number| max_age - last_resent_at_block_number); + + let can_resend_at_this_age = blocks_since_last_sent + .zip(config.resend_unfinalized_period) + .map(|(blocks_since_last_sent, unfinalized_period)| { + blocks_since_last_sent >= unfinalized_period * 2 + }) + .unwrap_or(true); if resend == Resend::Yes && - config - .resend_unfinalized_period - .as_ref() - .map_or(false, |p| block_age > 0 && block_age % p == 0) - { + config.resend_unfinalized_period.as_ref().map_or(false, |p| { + block_age > 0 && + block_age % p == 0 && diff_from_min_age == 0 && + can_resend_at_this_age + }) { // Retry sending to all peers. for (_, knowledge) in block_entry.known_by.iter_mut() { knowledge.sent = Knowledge::default(); } - + block_entry.last_resent_at_block_number = Some(max_age); + gum::debug!( + target: LOG_TARGET, + block_number = ?block_entry.number, + ?max_age, + "Aggression enabled with resend for block", + ); true } else { false diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 063e71f2f528..323b2cb08fec 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -1030,6 +1030,141 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { ); } +#[test] +fn peer_sending_us_duplicates_while_aggression_enabled_is_ok() { + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let peers = make_peers_and_authority_ids(8); + let peer_a = peers.first().unwrap().0; + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + let peer = &peer_a; + setup_peer_with_view(overseer, peer, view![], ValidationVersion::V3).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Setup a topology where peer_a is neighbor to current node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), + ) + .await; + + // new block `hash` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex].try_into().unwrap(); + let candidate_bitfields = vec![CoreIndex(0)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_indices.clone(), + ), + ) + .await; + + // update peer view to include the hash + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerViewChange(*peer, view![hash]), + ), + ) + .await; + + // we should send them the assignment + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + // but if someone else is sending it the same assignment + // the peer could send us it as well + let assignments = vec![(cert, candidate_indices)]; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer_v3(overseer, peer, msg.clone()).await; + + assert!( + overseer.recv().timeout(TIMEOUT).await.is_none(), + "we should not punish the peer" + ); + + // send the assignments again + send_message_from_peer_v3(overseer, peer, msg.clone()).await; + + // now we should + expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await; + + // Peers will be continously punished for sending duplicates until approval-distribution + // aggression kicks, at which point they aren't anymore. + let mut parent_hash = hash; + for level in 0..16 { + // As long as the lag is bellow l1 aggression, punish peers for duplicates. + send_message_from_peer_v3(overseer, peer, msg.clone()).await; + expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await; + + let number = 1 + level + 1; // first block had number 1 + let hash = BlakeTwo256::hash_of(&(parent_hash, number)); + let meta = BlockApprovalMeta { + hash, + parent_hash, + number, + candidates: vec![], + slot: (level as u64).into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(level + 1); + overseer_send(overseer, msg).await; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + parent_hash = hash; + } + + // send the assignments again, we should not punish the peer because aggression is + // enabled. + send_message_from_peer_v3(overseer, peer, msg).await; + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); +} + #[test] fn import_approval_happy_path_v1_v2_peers() { let peers = make_peers_and_authority_ids(15); @@ -3892,7 +4027,7 @@ fn resends_messages_periodically() { // Add blocks until resend is done. { let mut parent_hash = hash; - for level in 0..2 { + for level in 0..4 { number = number + 1; let hash = BlakeTwo256::hash_of(&(parent_hash, number)); let meta = BlockApprovalMeta { diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index 8c5574f244e4..7de8cb191599 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -5,40 +5,42 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +codec = { features = ["std"], workspace = true, default-features = true } +derive_more = { workspace = true, default-features = true } +fatality = { workspace = true } futures = { workspace = true } gum = { workspace = true, default-features = true } -codec = { features = ["std"], workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-erasure-coding = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } +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-node-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } +schnellru = { workspace = true } sp-core = { features = ["std"], workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } thiserror = { workspace = true } -rand = { workspace = true, default-features = true } -derive_more = { workspace = true, default-features = true } -schnellru = { workspace = true } -fatality = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } +futures-timer = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +polkadot-subsystem-bench = { workspace = true } +rstest = { workspace = true } +sc-network = { workspace = true, default-features = true } sp-core = { features = ["std"], workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -futures-timer = { workspace = true } -assert_matches = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } -rstest = { workspace = true } -polkadot-subsystem-bench = { workspace = true } [[bench]] diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 41f09b1f7044..8d4e6893b0a5 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -5,40 +5,42 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +async-trait = { workspace = true } +fatality = { workspace = true } futures = { workspace = true } -tokio = { workspace = true, default-features = true } -schnellru = { workspace = true } +gum = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } -fatality = { workspace = true } +schnellru = { workspace = true } thiserror = { workspace = true } -async-trait = { workspace = true } -gum = { workspace = true, default-features = true } +tokio = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } polkadot-erasure-coding = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } 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-node-network-protocol = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true } +polkadot-primitives = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } [dev-dependencies] assert_matches = { workspace = true } futures-timer = { workspace = true } -rstest = { workspace = true } log = { workspace = true, default-features = true } +rstest = { workspace = true } -sp-tracing = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 6d007255c574..74a205276906 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -5,6 +5,8 @@ description = "Polkadot Bitfiled Distribution subsystem, which gossips signed av authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,21 +16,21 @@ always-assert = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } -polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } [dev-dependencies] -polkadot-node-subsystem-test-helpers = { workspace = true } +assert_matches = { workspace = true } bitvec = { features = ["alloc"], workspace = true } -sp-core = { workspace = true, default-features = true } +maplit = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true } +rand_chacha = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } sp-authority-discovery = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } -maplit = { workspace = true } +sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true } -assert_matches = { workspace = true } -rand_chacha = { workspace = true, default-features = true } diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index b4b5743853cd..cdc1bc3f6c1b 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -5,6 +5,8 @@ description = "The Network Bridge Subsystem — protocol multiplexer for Polkado authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -12,26 +14,26 @@ workspace = true [dependencies] always-assert = { workspace = true } async-trait = { workspace = true } +bytes = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +fatality = { workspace = true } futures = { workspace = true } gum = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true } -sc-network = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } -parking_lot = { workspace = true, default-features = true } -bytes = { workspace = true, default-features = true } -fatality = { workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } thiserror = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } +futures-timer = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } sp-core = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } -futures-timer = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index 304cb23bb6aa..a02b281b6fc4 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -5,6 +5,8 @@ description = "Polkadot Collator Protocol subsystem. Allows collators and valida authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -17,28 +19,28 @@ gum = { workspace = true, default-features = true } schnellru.workspace = true sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +fatality = { workspace = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } -fatality = { workspace = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } thiserror = { workspace = true } tokio-util = { workspace = true } [dev-dependencies] -sp-tracing = { workspace = true } assert_matches = { workspace = true } rstest = { workspace = true } +sp-tracing = { workspace = true } -sp-core = { features = ["std"], workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } +codec = { features = ["std"], workspace = true, default-features = true } sc-keystore = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } -codec = { features = ["std"], workspace = true, default-features = true } +sp-core = { features = ["std"], workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index 504b0d716043..d77480272cb4 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -899,7 +899,7 @@ async fn process_msg( ); } }, - msg @ (ReportCollator(..) | Invalid(..) | Seconded(..)) => { + msg @ (Invalid(..) | Seconded(..)) => { gum::warn!( target: LOG_TARGET, "{:?} message is not expected on the collator side of the protocol", diff --git a/polkadot/node/network/collator-protocol/src/error.rs b/polkadot/node/network/collator-protocol/src/error.rs index 0f5e0699d85c..97fd4076bb8f 100644 --- a/polkadot/node/network/collator-protocol/src/error.rs +++ b/polkadot/node/network/collator-protocol/src/error.rs @@ -23,6 +23,7 @@ use polkadot_node_network_protocol::request_response::incoming; use polkadot_node_primitives::UncheckedSignedFullStatement; use polkadot_node_subsystem::{errors::SubsystemError, RuntimeApiError}; use polkadot_node_subsystem_util::{backing_implicit_view, runtime}; +use polkadot_primitives::vstaging::CandidateDescriptorVersion; use crate::LOG_TARGET; @@ -63,6 +64,15 @@ pub enum Error { #[error("CollationSeconded contained statement with invalid signature")] InvalidStatementSignature(UncheckedSignedFullStatement), + + #[error("Response receiver for session index request cancelled")] + CancelledSessionIndex(oneshot::Canceled), + + #[error("Response receiver for claim queue request cancelled")] + CancelledClaimQueue(oneshot::Canceled), + + #[error("No state for the relay parent")] + RelayParentStateNotFound, } /// An error happened on the validator side of the protocol when attempting @@ -87,11 +97,23 @@ pub enum SecondingError { #[error("Candidate hash doesn't match the advertisement")] CandidateHashMismatch, + #[error("Relay parent hash doesn't match the advertisement")] + RelayParentMismatch, + #[error("Received duplicate collation from the peer")] Duplicate, #[error("The provided parent head data does not match the hash")] ParentHeadDataMismatch, + + #[error("Core index {0} present in descriptor is different than the assigned core {1}")] + InvalidCoreIndex(u32, u32), + + #[error("Session index {0} present in descriptor is different than the expected one {1}")] + InvalidSessionIndex(u32, u32), + + #[error("Invalid candidate receipt version {0:?}")] + InvalidReceiptVersion(CandidateDescriptorVersion), } impl SecondingError { @@ -102,7 +124,11 @@ impl SecondingError { self, PersistedValidationDataMismatch | CandidateHashMismatch | - Duplicate | ParentHeadDataMismatch + RelayParentMismatch | + ParentHeadDataMismatch | + InvalidCoreIndex(_, _) | + InvalidSessionIndex(_, _) | + InvalidReceiptVersion(_) ) } } diff --git a/polkadot/node/network/collator-protocol/src/validator_side/claim_queue_state.rs b/polkadot/node/network/collator-protocol/src/validator_side/claim_queue_state.rs new file mode 100644 index 000000000000..3a34cf52fec6 --- /dev/null +++ b/polkadot/node/network/collator-protocol/src/validator_side/claim_queue_state.rs @@ -0,0 +1,1055 @@ +// 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 . + +//! `ClaimQueueState` tracks the state of the claim queue over a set of relay blocks. Refer to +//! [`ClaimQueueState`] for more details. + +use std::collections::VecDeque; + +use crate::LOG_TARGET; +use polkadot_primitives::{Hash, Id as ParaId}; + +/// Represents a single claim from the claim queue, mapped to the relay chain block where it could +/// be backed on-chain. +#[derive(Debug, PartialEq)] +struct ClaimInfo { + // Hash of the relay chain block. Can be `None` if it is still not known (a future block). + hash: Option, + /// Represents the `ParaId` scheduled for the block. Can be `None` if nothing is scheduled. + claim: Option, + /// The length of the claim queue at the block. It is used to determine the 'block window' + /// where a claim can be made. + claim_queue_len: usize, + /// A flag that indicates if the slot is claimed or not. + claimed: bool, +} + +/// Tracks the state of the claim queue over a set of relay blocks. +/// +/// Generally the claim queue represents the `ParaId` that should be scheduled at the current block +/// (the first element of the claim queue) and N other `ParaId`s which are supposed to be scheduled +/// on the next relay blocks. In other words the claim queue is a rolling window giving a hint what +/// should be built/fetched/accepted (depending on the context) at each block. +/// +/// Since the claim queue peeks into the future blocks there is a relation between the claim queue +/// state between the current block and the future blocks. +/// Let's see an example with 2 co-scheduled parachains: +/// - relay parent 1; Claim queue: [A, B, A] +/// - relay parent 2; Claim queue: [B, A, B] +/// - relay parent 3; Claim queue: [A, B, A] +/// - and so on +/// +/// Note that at rp1 the second element in the claim queue is equal to the first one in rp2. Also +/// the third element of the claim queue at rp1 is equal to the second one in rp2 and the first one +/// in rp3. +/// +/// So if we want to claim the third slot at rp 1 we are also claiming the second at rp2 and first +/// at rp3. To track this in a simple way we can project the claim queue onto the relay blocks like +/// this: +/// [A] [B] [A] -> this is the claim queue at rp3 +/// [B] [A] [B] -> this is the claim queue at rp2 +/// [A] [B] [A] -> this is the claim queue at rp1 +/// [RP 1][RP 2][RP 3][RP X][RP Y] -> relay blocks, RP x and RP Y are future blocks +/// +/// Note that the claims at each column are the same so we can simplify this by just projecting a +/// single claim over a block: +/// [A] [B] [A] [B] [A] -> claims effectively are the same +/// [RP 1][RP 2][RP 3][RP X][RP Y] -> relay blocks, RP x and RP Y are future blocks +/// +/// Basically this is how `ClaimQueueState` works. It keeps track of claims at each block by mapping +/// claims to relay blocks. +/// +/// How making a claim works? +/// At each relay block we keep track how long is the claim queue. This is a 'window' where we can +/// make a claim. So adding a claim just looks for a free spot at this window and claims it. +/// +/// Note on adding a new leaf. +/// When a new leaf is added we check if the first element in its claim queue matches with the +/// projection on the first element in 'future blocks'. If yes - the new relay block inherits this +/// claim. If not - this means that the claim queue changed for some reason so the claim can't be +/// inherited. This should not happen under normal circumstances. But if it happens it means that we +/// have got one claim which won't be satisfied in the worst case scenario. +pub(crate) struct ClaimQueueState { + block_state: VecDeque, + future_blocks: VecDeque, +} + +impl ClaimQueueState { + pub(crate) fn new() -> Self { + Self { block_state: VecDeque::new(), future_blocks: VecDeque::new() } + } + + // Appends a new leaf + pub(crate) fn add_leaf(&mut self, hash: &Hash, claim_queue: &Vec) { + if self.block_state.iter().any(|s| s.hash == Some(*hash)) { + return + } + + // First check if our view for the future blocks is consistent with the one in the claim + // queue of the new block. If not - the claim queue has changed for some reason and we need + // to readjust our view. + for (idx, expected_claim) in claim_queue.iter().enumerate() { + match self.future_blocks.get_mut(idx) { + Some(future_block) => + if future_block.claim.as_ref() != Some(expected_claim) { + // There is an inconsistency. Update our view with the one from the claim + // queue. `claimed` can't be true anymore since the `ParaId` has changed. + future_block.claimed = false; + future_block.claim = Some(*expected_claim); + }, + None => { + self.future_blocks.push_back(ClaimInfo { + hash: None, + claim: Some(*expected_claim), + // For future blocks we don't know the size of the claim queue. + // `claim_queue_len` could be an option but there is not much benefit from + // the extra boilerplate code to handle it. We set it to one since we + // usually know about one claim at each future block but this value is not + // used anywhere in the code. + claim_queue_len: 1, + claimed: false, + }); + }, + } + } + + // Now pop the first future block and add it as a leaf + let claim_info = if let Some(new_leaf) = self.future_blocks.pop_front() { + ClaimInfo { + hash: Some(*hash), + claim: claim_queue.first().copied(), + claim_queue_len: claim_queue.len(), + claimed: new_leaf.claimed, + } + } else { + // maybe the claim queue was empty but we still need to add a leaf + ClaimInfo { + hash: Some(*hash), + claim: claim_queue.first().copied(), + claim_queue_len: claim_queue.len(), + claimed: false, + } + }; + + // `future_blocks` can't be longer than the length of the claim queue at the last block - 1. + // For example this can happen if at relay block N we have got a claim queue of a length 4 + // and it's shrunk to 2. + self.future_blocks.truncate(claim_queue.len().saturating_sub(1)); + + self.block_state.push_back(claim_info); + } + + fn get_window<'a>( + &'a mut self, + relay_parent: &'a Hash, + ) -> impl Iterator + 'a { + let mut window = self + .block_state + .iter_mut() + .skip_while(|b| b.hash != Some(*relay_parent)) + .peekable(); + let cq_len = window.peek().map_or(0, |b| b.claim_queue_len); + window.chain(self.future_blocks.iter_mut()).take(cq_len) + } + + pub(crate) fn claim_at(&mut self, relay_parent: &Hash, para_id: &ParaId) -> bool { + gum::trace!( + target: LOG_TARGET, + ?para_id, + ?relay_parent, + "claim_at" + ); + self.find_a_claim(relay_parent, para_id, true) + } + + pub(crate) fn can_claim_at(&mut self, relay_parent: &Hash, para_id: &ParaId) -> bool { + gum::trace!( + target: LOG_TARGET, + ?para_id, + ?relay_parent, + "can_claim_at" + ); + + self.find_a_claim(relay_parent, para_id, false) + } + + // Returns `true` if there is a claim within `relay_parent`'s view of the claim queue for + // `para_id`. If `claim_it` is set to `true` the slot is claimed. Otherwise the function just + // reports the availability of the slot. + fn find_a_claim(&mut self, relay_parent: &Hash, para_id: &ParaId, claim_it: bool) -> bool { + let window = self.get_window(relay_parent); + + for w in window { + gum::trace!( + target: LOG_TARGET, + ?para_id, + ?relay_parent, + claim_info=?w, + ?claim_it, + "Checking claim" + ); + + if !w.claimed && w.claim == Some(*para_id) { + w.claimed = claim_it; + return true + } + } + + false + } + + pub(crate) fn unclaimed_at(&mut self, relay_parent: &Hash) -> Vec { + let window = self.get_window(relay_parent); + + window.filter(|b| !b.claimed).filter_map(|b| b.claim).collect() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn sane_initial_state() { + let mut state = ClaimQueueState::new(); + let relay_parent = Hash::from_low_u64_be(1); + let para_id = ParaId::new(1); + + assert!(!state.can_claim_at(&relay_parent, ¶_id)); + assert!(!state.claim_at(&relay_parent, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent), vec![]); + } + + #[test] + fn add_leaf_works() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id = ParaId::new(1); + let claim_queue = vec![para_id, para_id, para_id]; + + state.add_leaf(&relay_parent_a, &claim_queue); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id, para_id, para_id]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: false, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false } + ]) + ); + + // should be no op + state.add_leaf(&relay_parent_a, &claim_queue); + assert_eq!(state.block_state.len(), 1); + assert_eq!(state.future_blocks.len(), 2); + + // add another leaf + let relay_parent_b = Hash::from_low_u64_be(2); + state.add_leaf(&relay_parent_b, &claim_queue); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: false, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id), + claim_queue_len: 3, + claimed: false, + } + ]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false } + ]) + ); + + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id, para_id, para_id]); + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![para_id, para_id, para_id]); + } + + #[test] + fn claims_at_separate_relay_parents_work() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let relay_parent_b = Hash::from_low_u64_be(2); + let para_id = ParaId::new(1); + let claim_queue = vec![para_id, para_id, para_id]; + + state.add_leaf(&relay_parent_a, &claim_queue); + state.add_leaf(&relay_parent_b, &claim_queue); + + // add one claim for a + assert!(state.can_claim_at(&relay_parent_a, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id, para_id, para_id]); + assert!(state.claim_at(&relay_parent_a, ¶_id)); + + // and one for b + assert!(state.can_claim_at(&relay_parent_b, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![para_id, para_id, para_id]); + assert!(state.claim_at(&relay_parent_b, ¶_id)); + + // a should have one claim since the one for b was claimed + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id]); + // and two more for b + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![para_id, para_id]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + } + ]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false } + ]) + ); + } + + #[test] + fn claims_are_transferred_to_next_slot() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id = ParaId::new(1); + let claim_queue = vec![para_id, para_id, para_id]; + + state.add_leaf(&relay_parent_a, &claim_queue); + + // add two claims, 2nd should be transferred to a new leaf + assert!(state.can_claim_at(&relay_parent_a, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id, para_id, para_id]); + assert!(state.claim_at(&relay_parent_a, ¶_id)); + + assert!(state.can_claim_at(&relay_parent_a, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id, para_id]); + assert!(state.claim_at(&relay_parent_a, ¶_id)); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false } + ]) + ); + + // one more + assert!(state.can_claim_at(&relay_parent_a, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id]); + assert!(state.claim_at(&relay_parent_a, ¶_id)); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true } + ]) + ); + + // no more claims + assert!(!state.can_claim_at(&relay_parent_a, ¶_id)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + } + + #[test] + fn claims_are_transferred_to_new_leaves() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id = ParaId::new(1); + let claim_queue = vec![para_id, para_id, para_id]; + + state.add_leaf(&relay_parent_a, &claim_queue); + + for _ in 0..3 { + assert!(state.can_claim_at(&relay_parent_a, ¶_id)); + assert!(state.claim_at(&relay_parent_a, ¶_id)); + } + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true } + ]) + ); + + // no more claims + assert!(!state.can_claim_at(&relay_parent_a, ¶_id)); + + // new leaf + let relay_parent_b = Hash::from_low_u64_be(2); + state.add_leaf(&relay_parent_b, &claim_queue); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + } + ]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: false } + ]) + ); + + // still no claims for a + assert!(!state.can_claim_at(&relay_parent_a, ¶_id)); + + // but can accept for b + assert!(state.can_claim_at(&relay_parent_b, ¶_id)); + assert!(state.claim_at(&relay_parent_b, ¶_id)); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id), + claim_queue_len: 3, + claimed: true, + } + ]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id), claim_queue_len: 1, claimed: true } + ]) + ); + } + + #[test] + fn two_paras() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id_a = ParaId::new(1); + let para_id_b = ParaId::new(2); + let claim_queue = vec![para_id_a, para_id_b, para_id_a]; + + state.add_leaf(&relay_parent_a, &claim_queue); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_b)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_a, para_id_b, para_id_a]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: false, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + } + ]) + ); + + assert!(state.claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_b)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_b, para_id_a]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + } + ]) + ); + + assert!(state.claim_at(&relay_parent_a, ¶_id_a)); + assert!(!state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_b)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_b]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { hash: None, claim: Some(para_id_a), claim_queue_len: 1, claimed: true } + ]) + ); + + assert!(state.claim_at(&relay_parent_a, ¶_id_b)); + assert!(!state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(!state.can_claim_at(&relay_parent_a, ¶_id_b)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id_b), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id_a), claim_queue_len: 1, claimed: true } + ]) + ); + } + + #[test] + fn claim_queue_changes_unexpectedly() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id_a = ParaId::new(1); + let para_id_b = ParaId::new(2); + let claim_queue_a = vec![para_id_a, para_id_b, para_id_a]; + + state.add_leaf(&relay_parent_a, &claim_queue_a); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_b)); + assert!(state.claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.claim_at(&relay_parent_a, ¶_id_b)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id_b), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id_a), claim_queue_len: 1, claimed: true } + ]) + ); + + let relay_parent_b = Hash::from_low_u64_be(2); + let claim_queue_b = vec![para_id_a, para_id_a, para_id_a]; // should be [b, a, ...] + state.add_leaf(&relay_parent_b, &claim_queue_b); + + // because of the unexpected change in claim queue we lost the claim for paraB and have one + // unclaimed for paraA + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_a]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: false, + } + ]) + ); + assert_eq!( + state.future_blocks, + // since the 3rd slot of the claim queue at rp1 is equal to the second one in rp2, this + // claim still exists + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id_a), claim_queue_len: 1, claimed: true }, + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + } + ]) + ); + } + + #[test] + fn claim_queue_changes_unexpectedly_with_two_blocks() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id_a = ParaId::new(1); + let para_id_b = ParaId::new(2); + let claim_queue_a = vec![para_id_a, para_id_b, para_id_b]; + + state.add_leaf(&relay_parent_a, &claim_queue_a); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.can_claim_at(&relay_parent_a, ¶_id_b)); + assert!(state.claim_at(&relay_parent_a, ¶_id_a)); + assert!(state.claim_at(&relay_parent_a, ¶_id_b)); + assert!(state.claim_at(&relay_parent_a, ¶_id_b)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { hash: None, claim: Some(para_id_b), claim_queue_len: 1, claimed: true }, + ClaimInfo { hash: None, claim: Some(para_id_b), claim_queue_len: 1, claimed: true } + ]) + ); + + let relay_parent_b = Hash::from_low_u64_be(2); + let claim_queue_b = vec![para_id_a, para_id_a, para_id_a]; // should be [b, b, ...] + state.add_leaf(&relay_parent_b, &claim_queue_b); + + // because of the unexpected change in claim queue we lost both claims for paraB and have + // two unclaimed for paraA + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_a, para_id_a]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: true, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: false, + } + ]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + } + ]) + ); + } + + #[test] + fn empty_claim_queue() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id_a = ParaId::new(1); + let claim_queue_a = vec![]; + + state.add_leaf(&relay_parent_a, &claim_queue_a); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: None, + claim_queue_len: 0, + claimed: false, + },]) + ); + // no claim queue so we know nothing about future blocks + assert!(state.future_blocks.is_empty()); + + assert!(!state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(!state.claim_at(&relay_parent_a, ¶_id_a)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + let relay_parent_b = Hash::from_low_u64_be(2); + let claim_queue_b = vec![para_id_a]; + state.add_leaf(&relay_parent_b, &claim_queue_b); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: None, + claim_queue_len: 0, + claimed: false, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false, + }, + ]) + ); + // claim queue with length 1 doesn't say anything about future blocks + assert!(state.future_blocks.is_empty()); + + assert!(!state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(!state.claim_at(&relay_parent_a, ¶_id_a)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + assert!(state.can_claim_at(&relay_parent_b, ¶_id_a)); + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![para_id_a]); + assert!(state.claim_at(&relay_parent_b, ¶_id_a)); + + let relay_parent_c = Hash::from_low_u64_be(3); + let claim_queue_c = vec![para_id_a, para_id_a]; + state.add_leaf(&relay_parent_c, &claim_queue_c); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: None, + claim_queue_len: 0, + claimed: false, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: true, + }, + ClaimInfo { + hash: Some(relay_parent_c), + claim: Some(para_id_a), + claim_queue_len: 2, + claimed: false, + }, + ]) + ); + // claim queue with length 2 fills only one future block + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false, + },]) + ); + + assert!(!state.can_claim_at(&relay_parent_a, ¶_id_a)); + assert!(!state.claim_at(&relay_parent_a, ¶_id_a)); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![]); + + // already claimed + assert!(!state.can_claim_at(&relay_parent_b, ¶_id_a)); + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![]); + assert!(!state.claim_at(&relay_parent_b, ¶_id_a)); + + assert!(state.can_claim_at(&relay_parent_c, ¶_id_a)); + assert_eq!(state.unclaimed_at(&relay_parent_c), vec![para_id_a, para_id_a]); + } + + #[test] + fn claim_queue_becomes_shorter() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id_a = ParaId::new(1); + let para_id_b = ParaId::new(2); + let claim_queue_a = vec![para_id_a, para_id_b, para_id_a]; + + state.add_leaf(&relay_parent_a, &claim_queue_a); + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_a, para_id_b, para_id_a]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: false, + },]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + } + ]) + ); + + let relay_parent_b = Hash::from_low_u64_be(2); + let claim_queue_b = vec![para_id_a, para_id_b]; // should be [b, a] + state.add_leaf(&relay_parent_b, &claim_queue_b); + + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![para_id_a, para_id_b]); + // claims for `relay_parent_a` has changed. + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_a, para_id_a, para_id_b]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 3, + claimed: false, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id_a), + claim_queue_len: 2, + claimed: false, + } + ]) + ); + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + },]) + ); + } + + #[test] + fn claim_queue_becomes_shorter_and_drops_future_claims() { + let mut state = ClaimQueueState::new(); + let relay_parent_a = Hash::from_low_u64_be(1); + let para_id_a = ParaId::new(1); + let para_id_b = ParaId::new(2); + let claim_queue_a = vec![para_id_a, para_id_b, para_id_a, para_id_b]; + + state.add_leaf(&relay_parent_a, &claim_queue_a); + + assert_eq!( + state.unclaimed_at(&relay_parent_a), + vec![para_id_a, para_id_b, para_id_a, para_id_b] + ); + + // We start with claim queue len 4. + assert_eq!( + state.block_state, + VecDeque::from(vec![ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 4, + claimed: false, + },]) + ); + // we have got three future blocks + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ + ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + }, + ClaimInfo { + hash: None, + claim: Some(para_id_b), + claim_queue_len: 1, + claimed: false + } + ]) + ); + + // The next claim len is 2, so we loose one future block + let relay_parent_b = Hash::from_low_u64_be(2); + let para_id_a = ParaId::new(1); + let para_id_b = ParaId::new(2); + let claim_queue_b = vec![para_id_b, para_id_a]; + state.add_leaf(&relay_parent_b, &claim_queue_b); + + assert_eq!(state.unclaimed_at(&relay_parent_a), vec![para_id_a, para_id_b, para_id_a]); + assert_eq!(state.unclaimed_at(&relay_parent_b), vec![para_id_b, para_id_a]); + + assert_eq!( + state.block_state, + VecDeque::from(vec![ + ClaimInfo { + hash: Some(relay_parent_a), + claim: Some(para_id_a), + claim_queue_len: 4, + claimed: false, + }, + ClaimInfo { + hash: Some(relay_parent_b), + claim: Some(para_id_b), + claim_queue_len: 2, + claimed: false, + } + ]) + ); + + assert_eq!( + state.future_blocks, + VecDeque::from(vec![ClaimInfo { + hash: None, + claim: Some(para_id_a), + claim_queue_len: 1, + claimed: false + },]) + ); + } +} diff --git a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs index 0b3e9f4b3431..625140a73966 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -18,16 +18,28 @@ //! //! Usually a path of collations is as follows: //! 1. First, collation must be advertised by collator. -//! 2. If the advertisement was accepted, it's queued for fetch (per relay parent). -//! 3. Once it's requested, the collation is said to be Pending. -//! 4. Pending collation becomes Fetched once received, we send it to backing for validation. -//! 5. If it turns to be invalid or async backing allows seconding another candidate, carry on +//! 2. The validator inspects the claim queue and decides if the collation should be fetched +//! based on the entries there. A parachain can't have more fetched collations than the +//! entries in the claim queue at a specific relay parent. When calculating this limit the +//! validator counts all advertisements within its view not just at the relay parent. +//! 3. If the advertisement was accepted, it's queued for fetch (per relay parent). +//! 4. Once it's requested, the collation is said to be pending fetch +//! (`CollationStatus::Fetching`). +//! 5. Pending fetch collation becomes pending validation +//! (`CollationStatus::WaitingOnValidation`) once received, we send it to backing for +//! validation. +//! 6. If it turns to be invalid or async backing allows seconding another candidate, carry on //! with the next advertisement, otherwise we're done with this relay parent. //! -//! ┌──────────────────────────────────────────┐ -//! └─▶Advertised ─▶ Pending ─▶ Fetched ─▶ Validated - -use std::{collections::VecDeque, future::Future, pin::Pin, task::Poll}; +//! ┌───────────────────────────────────┐ +//! └─▶Waiting ─▶ Fetching ─▶ WaitingOnValidation + +use std::{ + collections::{BTreeMap, VecDeque}, + future::Future, + pin::Pin, + task::Poll, +}; use futures::{future::BoxFuture, FutureExt}; use polkadot_node_network_protocol::{ @@ -36,9 +48,7 @@ use polkadot_node_network_protocol::{ PeerId, }; use polkadot_node_primitives::PoV; -use polkadot_node_subsystem_util::{ - metrics::prometheus::prometheus::HistogramTimer, runtime::ProspectiveParachainsMode, -}; +use polkadot_node_subsystem_util::metrics::prometheus::prometheus::HistogramTimer; use polkadot_primitives::{ vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, CollatorId, Hash, HeadData, Id as ParaId, PersistedValidationData, @@ -129,9 +139,6 @@ pub struct BlockedCollationId { } /// Performs a sanity check between advertised and fetched collations. -/// -/// Since the persisted validation data is constructed using the advertised -/// parent head data hash, the latter doesn't require an additional check. pub fn fetched_collation_sanity_check( advertised: &PendingCollation, fetched: &CandidateReceipt, @@ -139,17 +146,25 @@ pub fn fetched_collation_sanity_check( maybe_parent_head_and_hash: Option<(HeadData, Hash)>, ) -> Result<(), SecondingError> { if persisted_validation_data.hash() != fetched.descriptor().persisted_validation_data_hash() { - Err(SecondingError::PersistedValidationDataMismatch) - } else if advertised + return Err(SecondingError::PersistedValidationDataMismatch) + } + + if advertised .prospective_candidate .map_or(false, |pc| pc.candidate_hash() != fetched.hash()) { - Err(SecondingError::CandidateHashMismatch) - } else if maybe_parent_head_and_hash.map_or(false, |(head, hash)| head.hash() != hash) { - Err(SecondingError::ParentHeadDataMismatch) - } else { - Ok(()) + return Err(SecondingError::CandidateHashMismatch) + } + + if advertised.relay_parent != fetched.descriptor.relay_parent() { + return Err(SecondingError::RelayParentMismatch) } + + if maybe_parent_head_and_hash.map_or(false, |(head, hash)| head.hash() != hash) { + return Err(SecondingError::ParentHeadDataMismatch) + } + + Ok(()) } /// Identifier for a requested collation and the respective collator that advertised it. @@ -182,12 +197,10 @@ pub struct PendingCollationFetch { pub enum CollationStatus { /// We are waiting for a collation to be advertised to us. Waiting, - /// We are currently fetching a collation. - Fetching, + /// We are currently fetching a collation for the specified `ParaId`. + Fetching(ParaId), /// We are waiting that a collation is being validated. WaitingOnValidation, - /// We have seconded a collation. - Seconded, } impl Default for CollationStatus { @@ -197,22 +210,22 @@ impl Default for CollationStatus { } impl CollationStatus { - /// Downgrades to `Waiting`, but only if `self != Seconded`. - fn back_to_waiting(&mut self, relay_parent_mode: ProspectiveParachainsMode) { - match self { - Self::Seconded => - if relay_parent_mode.is_enabled() { - // With async backing enabled it's allowed to - // second more candidates. - *self = Self::Waiting - }, - _ => *self = Self::Waiting, - } + /// Downgrades to `Waiting` + pub fn back_to_waiting(&mut self) { + *self = Self::Waiting } } +/// The number of claims in the claim queue and seconded candidates count for a specific `ParaId`. +#[derive(Default, Debug)] +struct CandidatesStatePerPara { + /// How many collations have been seconded. + pub seconded_per_para: usize, + // Claims in the claim queue for the `ParaId`. + pub claims_per_para: usize, +} + /// Information about collations per relay parent. -#[derive(Default)] pub struct Collations { /// What is the current status in regards to a collation for this relay parent? pub status: CollationStatus, @@ -221,75 +234,89 @@ pub struct Collations { /// This is the currently last started fetch, which did not exceed `MAX_UNSHARED_DOWNLOAD_TIME` /// yet. pub fetching_from: Option<(CollatorId, Option)>, - /// Collation that were advertised to us, but we did not yet fetch. - pub waiting_queue: VecDeque<(PendingCollation, CollatorId)>, - /// How many collations have been seconded. - pub seconded_count: usize, + /// Collation that were advertised to us, but we did not yet request or fetch. Grouped by + /// `ParaId`. + waiting_queue: BTreeMap>, + /// Number of seconded candidates and claims in the claim queue per `ParaId`. + candidates_state: BTreeMap, } impl Collations { + pub(super) fn new(group_assignments: &Vec) -> Self { + let mut candidates_state = BTreeMap::::new(); + + for para_id in group_assignments { + candidates_state.entry(*para_id).or_default().claims_per_para += 1; + } + + Self { + status: Default::default(), + fetching_from: None, + waiting_queue: Default::default(), + candidates_state, + } + } + /// Note a seconded collation for a given para. - pub(super) fn note_seconded(&mut self) { - self.seconded_count += 1 + pub(super) fn note_seconded(&mut self, para_id: ParaId) { + self.candidates_state.entry(para_id).or_default().seconded_per_para += 1; + gum::trace!( + target: LOG_TARGET, + ?para_id, + new_count=self.candidates_state.entry(para_id).or_default().seconded_per_para, + "Note seconded." + ); + self.status.back_to_waiting(); + } + + /// Adds a new collation to the waiting queue for the relay parent. This function doesn't + /// perform any limits check. The caller should assure that the collation limit is respected. + pub(super) fn add_to_waiting_queue(&mut self, collation: (PendingCollation, CollatorId)) { + self.waiting_queue.entry(collation.0.para_id).or_default().push_back(collation); } - /// Returns the next collation to fetch from the `waiting_queue`. + /// Picks a collation to fetch from the waiting queue. + /// When fetching collations we need to ensure that each parachain has got a fair core time + /// share depending on its assignments in the claim queue. This means that the number of + /// collations seconded per parachain should ideally be equal to the number of claims for the + /// particular parachain in the claim queue. /// - /// This will reset the status back to `Waiting` using [`CollationStatus::back_to_waiting`]. + /// To achieve this each seconded collation is mapped to an entry from the claim queue. The next + /// fetch is the first unfulfilled entry from the claim queue for which there is an + /// advertisement. /// - /// Returns `Some(_)` if there is any collation to fetch, the `status` is not `Seconded` and - /// the passed in `finished_one` is the currently `waiting_collation`. - pub(super) fn get_next_collation_to_fetch( + /// `unfulfilled_claim_queue_entries` represents all claim queue entries which are still not + /// fulfilled. + pub(super) fn pick_a_collation_to_fetch( &mut self, - finished_one: &(CollatorId, Option), - relay_parent_mode: ProspectiveParachainsMode, + unfulfilled_claim_queue_entries: Vec, ) -> Option<(PendingCollation, CollatorId)> { - // If finished one does not match waiting_collation, then we already dequeued another fetch - // to replace it. - if let Some((collator_id, maybe_candidate_hash)) = self.fetching_from.as_ref() { - // If a candidate hash was saved previously, `finished_one` must include this too. - if collator_id != &finished_one.0 && - maybe_candidate_hash.map_or(true, |hash| Some(&hash) != finished_one.1.as_ref()) + gum::trace!( + target: LOG_TARGET, + waiting_queue=?self.waiting_queue, + candidates_state=?self.candidates_state, + "Pick a collation to fetch." + ); + + for assignment in unfulfilled_claim_queue_entries { + // if there is an unfulfilled assignment - return it + if let Some(collation) = self + .waiting_queue + .get_mut(&assignment) + .and_then(|collations| collations.pop_front()) { - gum::trace!( - target: LOG_TARGET, - waiting_collation = ?self.fetching_from, - ?finished_one, - "Not proceeding to the next collation - has already been done." - ); - return None + return Some(collation) } } - self.status.back_to_waiting(relay_parent_mode); - - match self.status { - // We don't need to fetch any other collation when we already have seconded one. - CollationStatus::Seconded => None, - CollationStatus::Waiting => - if self.is_seconded_limit_reached(relay_parent_mode) { - None - } else { - self.waiting_queue.pop_front() - }, - CollationStatus::WaitingOnValidation | CollationStatus::Fetching => - unreachable!("We have reset the status above!"), - } + + None } - /// Checks the limit of seconded candidates. - pub(super) fn is_seconded_limit_reached( - &self, - relay_parent_mode: ProspectiveParachainsMode, - ) -> bool { - let seconded_limit = - if let ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } = - relay_parent_mode - { - max_candidate_depth + 1 - } else { - 1 - }; - self.seconded_count >= seconded_limit + pub(super) fn seconded_for_para(&self, para_id: &ParaId) -> usize { + self.candidates_state + .get(¶_id) + .map(|state| state.seconded_per_para) + .unwrap_or_default() } } diff --git a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs index 51e987d59ce8..5f5effcde9a8 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -49,19 +49,25 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, - runtime::{fetch_claim_queue, prospective_parachains_mode, ProspectiveParachainsMode}, + request_async_backing_params, request_claim_queue, request_session_index_for_child, + runtime::{recv_runtime, request_node_features}, }; use polkadot_primitives::{ - vstaging::CoreState, CandidateHash, CollatorId, Hash, HeadData, Id as ParaId, - OccupiedCoreAssumption, PersistedValidationData, + node_features, + vstaging::{CandidateDescriptorV2, CandidateDescriptorVersion}, + AsyncBackingParams, CandidateHash, CollatorId, CoreIndex, Hash, HeadData, Id as ParaId, + OccupiedCoreAssumption, PersistedValidationData, SessionIndex, }; use crate::error::{Error, FetchError, Result, SecondingError}; use self::collation::BlockedCollationId; +use self::claim_queue_state::ClaimQueueState; + use super::{modify_reputation, tick_stream, LOG_TARGET}; +mod claim_queue_state; mod collation; mod metrics; @@ -160,27 +166,19 @@ impl PeerData { fn update_view( &mut self, implicit_view: &ImplicitView, - active_leaves: &HashMap, - per_relay_parent: &HashMap, + active_leaves: &HashMap, new_view: View, ) { let old_view = std::mem::replace(&mut self.view, new_view); if let PeerState::Collating(ref mut peer_state) = self.state { for removed in old_view.difference(&self.view) { - // Remove relay parent advertisements if it went out - // of our (implicit) view. - let keep = per_relay_parent - .get(removed) - .map(|s| { - is_relay_parent_in_implicit_view( - removed, - s.prospective_parachains_mode, - implicit_view, - active_leaves, - peer_state.para_id, - ) - }) - .unwrap_or(false); + // Remove relay parent advertisements if it went out of our (implicit) view. + let keep = is_relay_parent_in_implicit_view( + removed, + implicit_view, + active_leaves, + peer_state.para_id, + ); if !keep { peer_state.advertisements.remove(&removed); @@ -193,8 +191,7 @@ impl PeerData { fn prune_old_advertisements( &mut self, implicit_view: &ImplicitView, - active_leaves: &HashMap, - per_relay_parent: &HashMap, + active_leaves: &HashMap, ) { if let PeerState::Collating(ref mut peer_state) = self.state { peer_state.advertisements.retain(|hash, _| { @@ -202,36 +199,30 @@ impl PeerData { // - Relay parent is an active leaf // - It belongs to allowed ancestry under some leaf // Discard otherwise. - per_relay_parent.get(hash).map_or(false, |s| { - is_relay_parent_in_implicit_view( - hash, - s.prospective_parachains_mode, - implicit_view, - active_leaves, - peer_state.para_id, - ) - }) + is_relay_parent_in_implicit_view( + hash, + implicit_view, + active_leaves, + peer_state.para_id, + ) }); } } - /// Note an advertisement by the collator. Returns `true` if the advertisement was imported - /// successfully. Fails if the advertisement is duplicate, out of view, or the peer has not - /// declared itself a collator. + /// Performs sanity check for an advertisement and notes it as advertised. fn insert_advertisement( &mut self, on_relay_parent: Hash, - relay_parent_mode: ProspectiveParachainsMode, candidate_hash: Option, implicit_view: &ImplicitView, - active_leaves: &HashMap, + active_leaves: &HashMap, + per_relay_parent: &PerRelayParent, ) -> std::result::Result<(CollatorId, ParaId), InsertAdvertisementError> { match self.state { PeerState::Connected(_) => Err(InsertAdvertisementError::UndeclaredCollator), PeerState::Collating(ref mut state) => { if !is_relay_parent_in_implicit_view( &on_relay_parent, - relay_parent_mode, implicit_view, active_leaves, state.para_id, @@ -239,53 +230,41 @@ impl PeerData { return Err(InsertAdvertisementError::OutOfOurView) } - match (relay_parent_mode, candidate_hash) { - (ProspectiveParachainsMode::Disabled, candidate_hash) => { - if state.advertisements.contains_key(&on_relay_parent) { - return Err(InsertAdvertisementError::Duplicate) - } - state - .advertisements - .insert(on_relay_parent, HashSet::from_iter(candidate_hash)); - }, - ( - ProspectiveParachainsMode::Enabled { max_candidate_depth, .. }, - candidate_hash, - ) => { - if let Some(candidate_hash) = candidate_hash { - if state - .advertisements - .get(&on_relay_parent) - .map_or(false, |candidates| candidates.contains(&candidate_hash)) - { - return Err(InsertAdvertisementError::Duplicate) - } - - let candidates = - state.advertisements.entry(on_relay_parent).or_default(); - - if candidates.len() > max_candidate_depth { - return Err(InsertAdvertisementError::PeerLimitReached) - } - candidates.insert(candidate_hash); - } else { - if self.version != CollationVersion::V1 { - gum::error!( - target: LOG_TARGET, - "Programming error, `candidate_hash` can not be `None` \ - for non `V1` networking.", - ); - } - - if state.advertisements.contains_key(&on_relay_parent) { - return Err(InsertAdvertisementError::Duplicate) - } - state - .advertisements - .insert(on_relay_parent, HashSet::from_iter(candidate_hash)); - }; - }, - } + if let Some(candidate_hash) = candidate_hash { + if state + .advertisements + .get(&on_relay_parent) + .map_or(false, |candidates| candidates.contains(&candidate_hash)) + { + return Err(InsertAdvertisementError::Duplicate) + } + + let candidates = state.advertisements.entry(on_relay_parent).or_default(); + + // Current assignments is equal to the length of the claim queue. No honest + // collator should send that many advertisements. + if candidates.len() > per_relay_parent.assignment.current.len() { + return Err(InsertAdvertisementError::PeerLimitReached) + } + + candidates.insert(candidate_hash); + } else { + if self.version != CollationVersion::V1 { + gum::error!( + target: LOG_TARGET, + "Programming error, `candidate_hash` can not be `None` \ + for non `V1` networking.", + ); + } + + if state.advertisements.contains_key(&on_relay_parent) { + return Err(InsertAdvertisementError::Duplicate) + } + + state + .advertisements + .insert(on_relay_parent, HashSet::from_iter(candidate_hash)); + }; state.last_active = Instant::now(); Ok((state.collator_id.clone(), state.para_id)) @@ -366,19 +345,11 @@ struct GroupAssignments { } struct PerRelayParent { - prospective_parachains_mode: ProspectiveParachainsMode, assignment: GroupAssignments, collations: Collations, -} - -impl PerRelayParent { - fn new(mode: ProspectiveParachainsMode) -> Self { - Self { - prospective_parachains_mode: mode, - assignment: GroupAssignments { current: vec![] }, - collations: Collations::default(), - } - } + v2_receipts: bool, + current_core: CoreIndex, + session_index: SessionIndex, } /// All state relevant for the validator side of the protocol lives here. @@ -394,11 +365,10 @@ struct State { /// ancestry of some active leaf, then it does support prospective parachains. implicit_view: ImplicitView, - /// All active leaves observed by us, including both that do and do not - /// support prospective parachains. This mapping works as a replacement for + /// All active leaves observed by us. This mapping works as a replacement for /// [`polkadot_node_network_protocol::View`] and can be dropped once the transition /// to asynchronous backing is done. - active_leaves: HashMap, + active_leaves: HashMap, /// State tracked per relay parent. per_relay_parent: HashMap, @@ -441,33 +411,79 @@ struct State { reputation: ReputationAggregator, } +impl State { + // Returns the number of seconded and pending collations for a specific `ParaId`. Pending + // collations are: + // 1. Collations being fetched from a collator. + // 2. Collations waiting for validation from backing subsystem. + // 3. Collations blocked from seconding due to parent not being known by backing subsystem. + fn seconded_and_pending_for_para(&self, relay_parent: &Hash, para_id: &ParaId) -> usize { + let seconded = self + .per_relay_parent + .get(relay_parent) + .map_or(0, |per_relay_parent| per_relay_parent.collations.seconded_for_para(para_id)); + + let pending_fetch = self.per_relay_parent.get(relay_parent).map_or(0, |rp_state| { + match rp_state.collations.status { + CollationStatus::Fetching(pending_para_id) if pending_para_id == *para_id => 1, + _ => 0, + } + }); + + let waiting_for_validation = self + .fetched_candidates + .keys() + .filter(|fc| fc.relay_parent == *relay_parent && fc.para_id == *para_id) + .count(); + + let blocked_from_seconding = + self.blocked_from_seconding.values().fold(0, |acc, blocked_collations| { + acc + blocked_collations + .iter() + .filter(|pc| { + pc.candidate_receipt.descriptor.para_id() == *para_id && + pc.candidate_receipt.descriptor.relay_parent() == *relay_parent + }) + .count() + }); + + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?para_id, + seconded, + pending_fetch, + waiting_for_validation, + blocked_from_seconding, + "Seconded and pending collations for para", + ); + + seconded + pending_fetch + waiting_for_validation + blocked_from_seconding + } +} + fn is_relay_parent_in_implicit_view( relay_parent: &Hash, - relay_parent_mode: ProspectiveParachainsMode, implicit_view: &ImplicitView, - active_leaves: &HashMap, + active_leaves: &HashMap, para_id: ParaId, ) -> bool { - match relay_parent_mode { - ProspectiveParachainsMode::Disabled => active_leaves.contains_key(relay_parent), - ProspectiveParachainsMode::Enabled { .. } => active_leaves.iter().any(|(hash, mode)| { - mode.is_enabled() && - implicit_view - .known_allowed_relay_parents_under(hash, Some(para_id)) - .unwrap_or_default() - .contains(relay_parent) - }), - } + active_leaves.iter().any(|(hash, _)| { + implicit_view + .known_allowed_relay_parents_under(hash, Some(para_id)) + .unwrap_or_default() + .contains(relay_parent) + }) } -async fn assign_incoming( +async fn construct_per_relay_parent( sender: &mut Sender, - group_assignment: &mut GroupAssignments, current_assignments: &mut HashMap, keystore: &KeystorePtr, relay_parent: Hash, - relay_parent_mode: ProspectiveParachainsMode, -) -> Result<()> + v2_receipts: bool, + session_index: SessionIndex, +) -> Result> where Sender: CollatorProtocolSenderTrait, { @@ -482,39 +498,24 @@ where .await .map_err(Error::CancelledValidatorGroups)??; - let cores = polkadot_node_subsystem_util::request_availability_cores(relay_parent, sender) - .await - .await - .map_err(Error::CancelledAvailabilityCores)??; - let core_now = if let Some(group) = polkadot_node_subsystem_util::signing_key_and_index(&validators, keystore).and_then( |(_, index)| polkadot_node_subsystem_util::find_validator_group(&groups, index), ) { - rotation_info.core_for_group(group, cores.len()) + rotation_info.core_for_group(group, groups.len()) } else { gum::trace!(target: LOG_TARGET, ?relay_parent, "Not a validator"); - return Ok(()) + return Ok(None) }; - let paras_now = match fetch_claim_queue(sender, relay_parent).await.map_err(Error::Runtime)? { - // Runtime supports claim queue - use it - // - // `relay_parent_mode` is not examined here because if the runtime supports claim queue - // then it supports async backing params too (`ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT` - // < `CLAIM_QUEUE_RUNTIME_REQUIREMENT`). - Some(mut claim_queue) => claim_queue.0.remove(&core_now), - // Claim queue is not supported by the runtime - use availability cores instead. - None => cores.get(core_now.0 as usize).and_then(|c| match c { - CoreState::Occupied(core) if relay_parent_mode.is_enabled() => - core.next_up_on_available.as_ref().map(|c| [c.para_id].into_iter().collect()), - CoreState::Scheduled(core) => Some([core.para_id].into_iter().collect()), - CoreState::Occupied(_) | CoreState::Free => None, - }), - } - .unwrap_or_else(|| VecDeque::new()); + let mut claim_queue = request_claim_queue(relay_parent, sender) + .await + .await + .map_err(Error::CancelledClaimQueue)??; - for para_id in paras_now.iter() { + let assigned_paras = claim_queue.remove(&core_now).unwrap_or_else(|| VecDeque::new()); + + for para_id in assigned_paras.iter() { let entry = current_assignments.entry(*para_id).or_default(); *entry += 1; if *entry == 1 { @@ -527,9 +528,16 @@ where } } - *group_assignment = GroupAssignments { current: paras_now.into_iter().collect() }; + let assignment = GroupAssignments { current: assigned_paras.into_iter().collect() }; + let collations = Collations::new(&assignment.current); - Ok(()) + Ok(Some(PerRelayParent { + assignment, + collations, + v2_receipts, + session_index, + current_core: core_now, + })) } fn remove_outgoing( @@ -653,12 +661,7 @@ fn handle_peer_view_change(state: &mut State, peer_id: PeerId, view: View) { None => return, }; - peer_data.update_view( - &state.implicit_view, - &state.active_leaves, - &state.per_relay_parent, - view, - ); + peer_data.update_view(&state.implicit_view, &state.active_leaves, view); state.collation_requests_cancel_handles.retain(|pc, handle| { let keep = pc.peer_id != peer_id || peer_data.has_advertised(&pc.relay_parent, None); if !keep { @@ -691,7 +694,6 @@ async fn request_collation( .get_mut(&relay_parent) .ok_or(FetchError::RelayParentOutOfView)?; - // Relay parent mode is checked in `handle_advertisement`. let (requests, response_recv) = match (peer_protocol_version, prospective_candidate) { (CollationVersion::V1, _) => { let (req, response_recv) = OutgoingRequest::new( @@ -737,7 +739,7 @@ async fn request_collation( let maybe_candidate_hash = prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); - per_relay_parent.collations.status = CollationStatus::Fetching; + per_relay_parent.collations.status = CollationStatus::Fetching(para_id); per_relay_parent .collations .fetching_from @@ -1048,6 +1050,62 @@ async fn second_unblocked_collations( } } +fn ensure_seconding_limit_is_respected( + relay_parent: &Hash, + para_id: ParaId, + state: &State, +) -> std::result::Result<(), AdvertisementError> { + let paths = state.implicit_view.paths_via_relay_parent(relay_parent); + + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?para_id, + ?paths, + "Checking seconding limit", + ); + + let mut has_claim_at_some_path = false; + for path in paths { + let mut cq_state = ClaimQueueState::new(); + for ancestor in &path { + let seconded_and_pending = state.seconded_and_pending_for_para(&ancestor, ¶_id); + cq_state.add_leaf( + &ancestor, + &state + .per_relay_parent + .get(ancestor) + .ok_or(AdvertisementError::RelayParentUnknown)? + .assignment + .current, + ); + for _ in 0..seconded_and_pending { + cq_state.claim_at(ancestor, ¶_id); + } + } + + if cq_state.can_claim_at(relay_parent, ¶_id) { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + ?para_id, + ?path, + "Seconding limit respected at path", + ); + has_claim_at_some_path = true; + break + } + } + + // If there is a place in the claim queue for the candidate at at least one path we will accept + // it. + if has_claim_at_some_path { + Ok(()) + } else { + Err(AdvertisementError::SecondedLimitReached) + } +} + async fn handle_advertisement( sender: &mut Sender, state: &mut State, @@ -1070,7 +1128,6 @@ where .get(&relay_parent) .ok_or(AdvertisementError::RelayParentUnknown)?; - let relay_parent_mode = per_relay_parent.prospective_parachains_mode; let assignment = &per_relay_parent.assignment; let collator_para_id = @@ -1086,32 +1143,29 @@ where let (collator_id, para_id) = peer_data .insert_advertisement( relay_parent, - relay_parent_mode, candidate_hash, &state.implicit_view, &state.active_leaves, + &per_relay_parent, ) .map_err(AdvertisementError::Invalid)?; - if per_relay_parent.collations.is_seconded_limit_reached(relay_parent_mode) { - return Err(AdvertisementError::SecondedLimitReached) - } + ensure_seconding_limit_is_respected(&relay_parent, para_id, state)?; if let Some((candidate_hash, parent_head_data_hash)) = prospective_candidate { // Check if backing subsystem allows to second this candidate. // // This is also only important when async backing or elastic scaling is enabled. - let seconding_not_allowed = relay_parent_mode.is_enabled() && - !can_second( - sender, - collator_para_id, - relay_parent, - candidate_hash, - parent_head_data_hash, - ) - .await; + let can_second = can_second( + sender, + collator_para_id, + relay_parent, + candidate_hash, + parent_head_data_hash, + ) + .await; - if seconding_not_allowed { + if !can_second { return Err(AdvertisementError::BlockedByBacking) } } @@ -1141,8 +1195,8 @@ where Ok(()) } -/// Enqueue collation for fetching. The advertisement is expected to be -/// validated. +/// Enqueue collation for fetching. The advertisement is expected to be validated and the seconding +/// limit checked. async fn enqueue_collation( sender: &mut Sender, state: &mut State, @@ -1177,7 +1231,6 @@ where return Ok(()) }, }; - let relay_parent_mode = per_relay_parent.prospective_parachains_mode; let prospective_candidate = prospective_candidate.map(|(candidate_hash, parent_head_data_hash)| ProspectiveCandidate { candidate_hash, @@ -1185,22 +1238,11 @@ where }); let collations = &mut per_relay_parent.collations; - if collations.is_seconded_limit_reached(relay_parent_mode) { - gum::trace!( - target: LOG_TARGET, - peer_id = ?peer_id, - %para_id, - ?relay_parent, - "Limit of seconded collations reached for valid advertisement", - ); - return Ok(()) - } - let pending_collation = PendingCollation::new(relay_parent, para_id, &peer_id, prospective_candidate); match collations.status { - CollationStatus::Fetching | CollationStatus::WaitingOnValidation => { + CollationStatus::Fetching(_) | CollationStatus::WaitingOnValidation => { gum::trace!( target: LOG_TARGET, peer_id = ?peer_id, @@ -1208,26 +1250,13 @@ where ?relay_parent, "Added collation to the pending list" ); - collations.waiting_queue.push_back((pending_collation, collator_id)); + collations.add_to_waiting_queue((pending_collation, collator_id)); }, CollationStatus::Waiting => { + // We were waiting for a collation to be advertised to us (we were idle) so we can fetch + // the new collation immediately fetch_collation(sender, state, pending_collation, collator_id).await?; }, - CollationStatus::Seconded if relay_parent_mode.is_enabled() => { - // Limit is not reached, it's allowed to second another - // collation. - fetch_collation(sender, state, pending_collation, collator_id).await?; - }, - CollationStatus::Seconded => { - gum::trace!( - target: LOG_TARGET, - peer_id = ?peer_id, - %para_id, - ?relay_parent, - ?relay_parent_mode, - "A collation has already been seconded", - ); - }, } Ok(()) @@ -1249,63 +1278,81 @@ where let added = view.iter().filter(|h| !current_leaves.contains_key(h)); for leaf in added { - let mode = prospective_parachains_mode(sender, *leaf).await?; + let session_index = request_session_index_for_child(*leaf, sender) + .await + .await + .map_err(Error::CancelledSessionIndex)??; - let mut per_relay_parent = PerRelayParent::new(mode); - assign_incoming( + let async_backing_params = + recv_runtime(request_async_backing_params(*leaf, sender).await).await?; + + let v2_receipts = request_node_features(*leaf, session_index, sender) + .await? + .unwrap_or_default() + .get(node_features::FeatureIndex::CandidateReceiptV2 as usize) + .map(|b| *b) + .unwrap_or(false); + + let Some(per_relay_parent) = construct_per_relay_parent( sender, - &mut per_relay_parent.assignment, &mut state.current_assignments, keystore, *leaf, - mode, + v2_receipts, + session_index, ) - .await?; + .await? + else { + continue + }; - state.active_leaves.insert(*leaf, mode); + state.active_leaves.insert(*leaf, async_backing_params); state.per_relay_parent.insert(*leaf, per_relay_parent); - if mode.is_enabled() { - state - .implicit_view - .activate_leaf(sender, *leaf) - .await - .map_err(Error::ImplicitViewFetchError)?; - - // Order is always descending. - let allowed_ancestry = state - .implicit_view - .known_allowed_relay_parents_under(leaf, None) - .unwrap_or_default(); - for block_hash in allowed_ancestry { - if let Entry::Vacant(entry) = state.per_relay_parent.entry(*block_hash) { - let mut per_relay_parent = PerRelayParent::new(mode); - assign_incoming( - sender, - &mut per_relay_parent.assignment, - &mut state.current_assignments, - keystore, - *block_hash, - mode, - ) - .await?; - + state + .implicit_view + .activate_leaf(sender, *leaf) + .await + .map_err(Error::ImplicitViewFetchError)?; + + // Order is always descending. + let allowed_ancestry = state + .implicit_view + .known_allowed_relay_parents_under(leaf, None) + .unwrap_or_default(); + for block_hash in allowed_ancestry { + if let Entry::Vacant(entry) = state.per_relay_parent.entry(*block_hash) { + // Safe to use the same v2 receipts config for the allowed relay parents as well + // as the same session index since they must be in the same session. + if let Some(per_relay_parent) = construct_per_relay_parent( + sender, + &mut state.current_assignments, + keystore, + *block_hash, + v2_receipts, + session_index, + ) + .await? + { entry.insert(per_relay_parent); } } } } - for (removed, mode) in removed { + for (removed, _) in removed { + gum::trace!( + target: LOG_TARGET, + ?view, + ?removed, + "handle_our_view_change - removed", + ); + state.active_leaves.remove(removed); // If the leaf is deactivated it still may stay in the view as a part // of implicit ancestry. Only update the state after the hash is actually // pruned from the block info storage. - let pruned = if mode.is_enabled() { - state.implicit_view.deactivate_leaf(*removed) - } else { - vec![*removed] - }; + let pruned = state.implicit_view.deactivate_leaf(*removed); for removed in pruned { if let Some(per_relay_parent) = state.per_relay_parent.remove(&removed) { @@ -1335,11 +1382,7 @@ where }); for (peer_id, peer_data) in state.peer_data.iter_mut() { - peer_data.prune_old_advertisements( - &state.implicit_view, - &state.active_leaves, - &state.per_relay_parent, - ); + peer_data.prune_old_advertisements(&state.implicit_view, &state.active_leaves); // Disconnect peers who are not relevant to our current or next para. // @@ -1444,9 +1487,6 @@ async fn process_msg( "DistributeCollation message is not expected on the validator side of the protocol", ); }, - ReportCollator(id) => { - report_collator(&mut state.reputation, ctx.sender(), &state.peer_data, id).await; - }, NetworkBridgeUpdate(event) => { if let Err(e) = handle_network_msg(ctx, state, keystore, event).await { gum::warn!( @@ -1475,8 +1515,9 @@ async fn process_msg( if let Some(CollationEvent { collator_id, pending_collation, .. }) = state.fetched_candidates.remove(&fetched_collation) { - let PendingCollation { relay_parent, peer_id, prospective_candidate, .. } = - pending_collation; + let PendingCollation { + relay_parent, peer_id, prospective_candidate, para_id, .. + } = pending_collation; note_good_collation( &mut state.reputation, ctx.sender(), @@ -1496,8 +1537,7 @@ async fn process_msg( } if let Some(rp_state) = state.per_relay_parent.get_mut(&parent) { - rp_state.collations.status = CollationStatus::Seconded; - rp_state.collations.note_seconded(); + rp_state.collations.note_seconded(para_id); } // See if we've unblocked other collations for seconding. @@ -1621,12 +1661,12 @@ async fn run_inner( Ok(FromOrchestra::Signal(OverseerSignal::Conclude)) | Err(_) => break, Ok(FromOrchestra::Signal(_)) => continue, } - } + }, _ = next_inactivity_stream.next() => { disconnect_inactive_peers(ctx.sender(), &eviction_policy, &state.peer_data).await; - } - + }, resp = state.collation_requests.select_next_some() => { + let relay_parent = resp.0.pending_collation.relay_parent; let res = match handle_collation_fetch_response( &mut state, resp, @@ -1635,9 +1675,17 @@ async fn run_inner( ).await { Err(Some((peer_id, rep))) => { modify_reputation(&mut state.reputation, ctx.sender(), peer_id, rep).await; + // Reset the status for the relay parent + state.per_relay_parent.get_mut(&relay_parent).map(|rp| { + rp.collations.status.back_to_waiting(); + }); continue }, Err(None) => { + // Reset the status for the relay parent + state.per_relay_parent.get_mut(&relay_parent).map(|rp| { + rp.collations.status.back_to_waiting(); + }); continue }, Ok(res) => res @@ -1684,7 +1732,7 @@ async fn run_inner( } Ok(true) => {} } - } + }, res = state.collation_fetch_timeouts.select_next_some() => { let (collator_id, maybe_candidate_hash, relay_parent) = res; gum::debug!( @@ -1716,11 +1764,7 @@ async fn dequeue_next_collation_and_fetch( // The collator we tried to fetch from last, optionally which candidate. previous_fetch: (CollatorId, Option), ) { - while let Some((next, id)) = state.per_relay_parent.get_mut(&relay_parent).and_then(|state| { - state - .collations - .get_next_collation_to_fetch(&previous_fetch, state.prospective_parachains_mode) - }) { + while let Some((next, id)) = get_next_collation_to_fetch(&previous_fetch, relay_parent, state) { gum::debug!( target: LOG_TARGET, ?relay_parent, @@ -1814,6 +1858,10 @@ async fn kick_off_seconding( return Ok(false) }, }; + + // Sanity check of the candidate receipt version. + descriptor_version_sanity_check(candidate_receipt.descriptor(), per_relay_parent)?; + let collations = &mut per_relay_parent.collations; let fetched_collation = FetchedCollation::from(&candidate_receipt); @@ -1825,9 +1873,7 @@ async fn kick_off_seconding( collation_event.collator_protocol_version, collation_event.pending_collation.prospective_candidate, ) { - (CollationVersion::V2, Some(ProspectiveCandidate { parent_head_data_hash, .. })) - if per_relay_parent.prospective_parachains_mode.is_enabled() => - { + (CollationVersion::V2, Some(ProspectiveCandidate { parent_head_data_hash, .. })) => { let pvd = request_prospective_validation_data( ctx.sender(), relay_parent, @@ -1839,8 +1885,7 @@ async fn kick_off_seconding( (pvd, maybe_parent_head_data, Some(parent_head_data_hash)) }, - // Support V2 collators without async backing enabled. - (CollationVersion::V2, Some(_)) | (CollationVersion::V1, _) => { + (CollationVersion::V1, _) => { let pvd = request_persisted_validation_data( ctx.sender(), candidate_receipt.descriptor().relay_parent(), @@ -2024,7 +2069,9 @@ async fn handle_collation_fetch_response( }, Ok( request_v1::CollationFetchingResponse::Collation(receipt, _) | - request_v1::CollationFetchingResponse::CollationWithParentHeadData { receipt, .. }, + request_v2::CollationFetchingResponse::Collation(receipt, _) | + request_v1::CollationFetchingResponse::CollationWithParentHeadData { receipt, .. } | + request_v2::CollationFetchingResponse::CollationWithParentHeadData { receipt, .. }, ) if receipt.descriptor().para_id() != pending_collation.para_id => { gum::debug!( target: LOG_TARGET, @@ -2086,3 +2133,135 @@ async fn handle_collation_fetch_response( state.metrics.on_request(metrics_result); result } + +// Returns the claim queue without fetched or pending advertisement. The resulting `Vec` keeps the +// order in the claim queue so the earlier an element is located in the `Vec` the higher its +// priority is. +fn unfulfilled_claim_queue_entries(relay_parent: &Hash, state: &State) -> Result> { + let relay_parent_state = state + .per_relay_parent + .get(relay_parent) + .ok_or(Error::RelayParentStateNotFound)?; + let scheduled_paras = relay_parent_state.assignment.current.iter().collect::>(); + let paths = state.implicit_view.paths_via_relay_parent(relay_parent); + + let mut claim_queue_states = Vec::new(); + for path in paths { + let mut cq_state = ClaimQueueState::new(); + for ancestor in &path { + cq_state.add_leaf( + &ancestor, + &state + .per_relay_parent + .get(&ancestor) + .ok_or(Error::RelayParentStateNotFound)? + .assignment + .current, + ); + + for para_id in &scheduled_paras { + let seconded_and_pending = state.seconded_and_pending_for_para(&ancestor, ¶_id); + for _ in 0..seconded_and_pending { + cq_state.claim_at(&ancestor, ¶_id); + } + } + } + claim_queue_states.push(cq_state); + } + + // From the claim queue state for each leaf we have to return a combined single one. Go for a + // simple solution and return the longest one. In theory we always prefer the earliest entries + // in the claim queue so there is a good chance that the longest path is the one with + // unsatisfied entries in the beginning. This is not guaranteed as we might have fetched 2nd or + // 3rd spot from the claim queue but it should be good enough. + let unfulfilled_entries = claim_queue_states + .iter_mut() + .map(|cq| cq.unclaimed_at(relay_parent)) + .max_by(|a, b| a.len().cmp(&b.len())) + .unwrap_or_default(); + + Ok(unfulfilled_entries) +} + +/// Returns the next collation to fetch from the `waiting_queue` and reset the status back to +/// `Waiting`. +fn get_next_collation_to_fetch( + finished_one: &(CollatorId, Option), + relay_parent: Hash, + state: &mut State, +) -> Option<(PendingCollation, CollatorId)> { + let unfulfilled_entries = match unfulfilled_claim_queue_entries(&relay_parent, &state) { + Ok(entries) => entries, + Err(err) => { + gum::error!( + target: LOG_TARGET, + ?relay_parent, + ?err, + "Failed to get unfulfilled claim queue entries" + ); + return None + }, + }; + let rp_state = match state.per_relay_parent.get_mut(&relay_parent) { + Some(rp_state) => rp_state, + None => { + gum::error!( + target: LOG_TARGET, + ?relay_parent, + "Failed to get relay parent state" + ); + return None + }, + }; + + // If finished one does not match waiting_collation, then we already dequeued another fetch + // to replace it. + if let Some((collator_id, maybe_candidate_hash)) = rp_state.collations.fetching_from.as_ref() { + // If a candidate hash was saved previously, `finished_one` must include this too. + if collator_id != &finished_one.0 && + maybe_candidate_hash.map_or(true, |hash| Some(&hash) != finished_one.1.as_ref()) + { + gum::trace!( + target: LOG_TARGET, + waiting_collation = ?rp_state.collations.fetching_from, + ?finished_one, + "Not proceeding to the next collation - has already been done." + ); + return None + } + } + rp_state.collations.status.back_to_waiting(); + rp_state.collations.pick_a_collation_to_fetch(unfulfilled_entries) +} + +// Sanity check the candidate descriptor version. +fn descriptor_version_sanity_check( + descriptor: &CandidateDescriptorV2, + per_relay_parent: &PerRelayParent, +) -> std::result::Result<(), SecondingError> { + match descriptor.version() { + CandidateDescriptorVersion::V1 => Ok(()), + CandidateDescriptorVersion::V2 if per_relay_parent.v2_receipts => { + if let Some(core_index) = descriptor.core_index() { + if core_index != per_relay_parent.current_core { + return Err(SecondingError::InvalidCoreIndex( + core_index.0, + per_relay_parent.current_core.0, + )) + } + } + + if let Some(session_index) = descriptor.session_index() { + if session_index != per_relay_parent.session_index { + return Err(SecondingError::InvalidSessionIndex( + session_index, + per_relay_parent.session_index, + )) + } + } + + Ok(()) + }, + descriptor_version => Err(SecondingError::InvalidReceiptVersion(descriptor_version)), + } +} diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs index 290c4db901d5..5a2e135419dd 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/mod.rs @@ -28,27 +28,24 @@ use std::{ time::Duration, }; +use self::prospective_parachains::update_view; use polkadot_node_network_protocol::{ - our_view, peer_set::CollationVersion, request_response::{Requests, ResponseSender}, ObservedRole, }; use polkadot_node_primitives::{BlockData, PoV}; -use polkadot_node_subsystem::{ - errors::RuntimeApiError, - messages::{AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest}, +use polkadot_node_subsystem::messages::{ + AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - vstaging::{CandidateReceiptV2 as CandidateReceipt, CoreState, OccupiedCore}, - CollatorPair, CoreIndex, GroupIndex, GroupRotationInfo, HeadData, PersistedValidationData, - ScheduledCore, ValidatorId, ValidatorIndex, -}; -use polkadot_primitives_test_helpers::{ - dummy_candidate_descriptor, dummy_candidate_receipt_bad_sig, dummy_hash, + node_features, vstaging::CandidateReceiptV2 as CandidateReceipt, AsyncBackingParams, + CollatorPair, CoreIndex, GroupRotationInfo, HeadData, NodeFeatures, PersistedValidationData, + ValidatorId, ValidatorIndex, }; +use polkadot_primitives_test_helpers::{dummy_candidate_receipt_bad_sig, dummy_hash}; mod prospective_parachains; @@ -56,9 +53,6 @@ const ACTIVITY_TIMEOUT: Duration = Duration::from_millis(500); const DECLARE_TIMEOUT: Duration = Duration::from_millis(25); const REPUTATION_CHANGE_TEST_INTERVAL: Duration = Duration::from_millis(10); -const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = - RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; - fn dummy_pvd() -> PersistedValidationData { PersistedValidationData { parent_head: HeadData(vec![7, 8, 9]), @@ -76,17 +70,17 @@ struct TestState { validator_public: Vec, validator_groups: Vec>, group_rotation_info: GroupRotationInfo, - cores: Vec, claim_queue: BTreeMap>, + async_backing_params: AsyncBackingParams, + node_features: NodeFeatures, + session_index: SessionIndex, + // Used by `update_view` to keep track of latest requested ancestor + last_known_block: Option, } impl Default for TestState { fn default() -> Self { - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - - let chain_ids = vec![chain_a, chain_b]; - let relay_parent = Hash::repeat_byte(0x05); + let relay_parent = Hash::from_low_u64_be(0x05); let collators = iter::repeat(()).map(|_| CollatorPair::generate().0).take(5).collect(); let validators = vec![ @@ -107,44 +101,103 @@ impl Default for TestState { let group_rotation_info = GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 1, now: 0 }; - let cores = vec![ - CoreState::Scheduled(ScheduledCore { para_id: chain_ids[0], collator: None }), - CoreState::Free, - CoreState::Occupied(OccupiedCore { - next_up_on_available: Some(ScheduledCore { para_id: chain_ids[1], collator: None }), - occupied_since: 0, - time_out_at: 1, - next_up_on_time_out: None, - availability: Default::default(), - group_responsible: GroupIndex(0), - candidate_hash: Default::default(), - candidate_descriptor: { - let mut d = dummy_candidate_descriptor(dummy_hash()); - d.para_id = chain_ids[1]; - - d.into() - }, - }), - ]; - let mut claim_queue = BTreeMap::new(); - claim_queue.insert(CoreIndex(0), [chain_ids[0]].into_iter().collect()); + claim_queue.insert( + CoreIndex(0), + iter::repeat(ParaId::from(Self::CHAIN_IDS[0])) + .take(Self::ASYNC_BACKING_PARAMS.allowed_ancestry_len as usize) + .collect(), + ); claim_queue.insert(CoreIndex(1), VecDeque::new()); - claim_queue.insert(CoreIndex(2), [chain_ids[1]].into_iter().collect()); + claim_queue.insert( + CoreIndex(2), + iter::repeat(ParaId::from(Self::CHAIN_IDS[1])) + .take(Self::ASYNC_BACKING_PARAMS.allowed_ancestry_len as usize) + .collect(), + ); + + let mut node_features = NodeFeatures::EMPTY; + node_features.resize(node_features::FeatureIndex::CandidateReceiptV2 as usize + 1, false); + node_features.set(node_features::FeatureIndex::CandidateReceiptV2 as u8 as usize, true); Self { - chain_ids, + chain_ids: Self::CHAIN_IDS.map(|id| ParaId::from(id)).to_vec(), relay_parent, collators, validator_public, validator_groups, group_rotation_info, - cores, claim_queue, + async_backing_params: Self::ASYNC_BACKING_PARAMS, + node_features, + session_index: 1, + last_known_block: None, } } } +impl TestState { + const CHAIN_IDS: [u32; 2] = [1, 2]; + const ASYNC_BACKING_PARAMS: AsyncBackingParams = + AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; + + fn with_shared_core() -> Self { + let mut state = Self::default(); + + let mut claim_queue = BTreeMap::new(); + claim_queue.insert( + CoreIndex(0), + VecDeque::from_iter( + [ + ParaId::from(Self::CHAIN_IDS[1]), + ParaId::from(Self::CHAIN_IDS[0]), + ParaId::from(Self::CHAIN_IDS[0]), + ] + .into_iter(), + ), + ); + state.validator_groups.truncate(1); + + assert!( + claim_queue.get(&CoreIndex(0)).unwrap().len() == + Self::ASYNC_BACKING_PARAMS.allowed_ancestry_len as usize + ); + + state.claim_queue = claim_queue; + + state + } + + fn with_one_scheduled_para() -> Self { + let mut state = Self::default(); + + let validator_groups = vec![vec![ValidatorIndex(0), ValidatorIndex(1)]]; + + let mut claim_queue = BTreeMap::new(); + claim_queue.insert( + CoreIndex(0), + VecDeque::from_iter( + [ + ParaId::from(Self::CHAIN_IDS[0]), + ParaId::from(Self::CHAIN_IDS[0]), + ParaId::from(Self::CHAIN_IDS[0]), + ] + .into_iter(), + ), + ); + + assert!( + claim_queue.get(&CoreIndex(0)).unwrap().len() == + Self::ASYNC_BACKING_PARAMS.allowed_ancestry_len as usize + ); + + state.validator_groups = validator_groups; + state.claim_queue = claim_queue; + + state + } +} + type VirtualOverseer = polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; @@ -237,64 +290,6 @@ async fn overseer_signal(overseer: &mut VirtualOverseer, signal: OverseerSignal) .expect(&format!("{:?} is more than enough for sending signals.", TIMEOUT)); } -async fn respond_to_core_info_queries( - virtual_overseer: &mut VirtualOverseer, - test_state: &TestState, -) { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::Validators(tx), - )) => { - let _ = tx.send(Ok(test_state.validator_public.clone())); - } - ); - - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::ValidatorGroups(tx), - )) => { - let _ = tx.send(Ok(( - test_state.validator_groups.clone(), - test_state.group_rotation_info.clone(), - ))); - } - ); - - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::AvailabilityCores(tx), - )) => { - let _ = tx.send(Ok(test_state.cores.clone())); - } - ); - - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::Version(tx), - )) => { - let _ = tx.send(Ok(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)); - } - ); - - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::ClaimQueue(tx), - )) => { - let _ = tx.send(Ok(test_state.claim_queue.clone())); - } - ); -} - /// Assert that the next message is a `CandidateBacking(Second())`. async fn assert_candidate_backing_second( virtual_overseer: &mut VirtualOverseer, @@ -470,212 +465,6 @@ async fn advertise_collation( .await; } -async fn assert_async_backing_params_request(virtual_overseer: &mut VirtualOverseer, hash: Hash) { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::AsyncBackingParams(tx) - )) => { - assert_eq!(relay_parent, hash); - tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); - } - ); -} - -// As we receive a relevant advertisement act on it and issue a collation request. -#[test] -fn act_on_advertisement() { - let test_state = TestState::default(); - - test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer, .. } = test_harness; - - let pair = CollatorPair::generate().0; - gum::trace!("activating"); - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - - let peer_b = PeerId::random(); - - connect_and_declare_collator( - &mut virtual_overseer, - peer_b, - pair.clone(), - test_state.chain_ids[0], - CollationVersion::V1, - ) - .await; - - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; - - assert_fetch_collation_request( - &mut virtual_overseer, - test_state.relay_parent, - test_state.chain_ids[0], - None, - ) - .await; - - virtual_overseer - }); -} - -/// Tests that validator side works with v2 network protocol -/// before async backing is enabled. -#[test] -fn act_on_advertisement_v2() { - let test_state = TestState::default(); - - test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer, .. } = test_harness; - - let pair = CollatorPair::generate().0; - gum::trace!("activating"); - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - - let peer_b = PeerId::random(); - - connect_and_declare_collator( - &mut virtual_overseer, - peer_b, - pair.clone(), - test_state.chain_ids[0], - CollationVersion::V2, - ) - .await; - - let pov = PoV { block_data: BlockData(vec![]) }; - let mut candidate_a = - dummy_candidate_receipt_bad_sig(dummy_hash(), Some(Default::default())); - candidate_a.descriptor.para_id = test_state.chain_ids[0]; - candidate_a.descriptor.relay_parent = test_state.relay_parent; - candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); - - let candidate_hash = candidate_a.hash(); - let parent_head_data_hash = Hash::zero(); - // v2 advertisement. - advertise_collation( - &mut virtual_overseer, - peer_b, - test_state.relay_parent, - Some((candidate_hash, parent_head_data_hash)), - ) - .await; - - let response_channel = assert_fetch_collation_request( - &mut virtual_overseer, - test_state.relay_parent, - test_state.chain_ids[0], - Some(candidate_hash), - ) - .await; - - response_channel - .send(Ok(( - request_v1::CollationFetchingResponse::Collation( - candidate_a.clone().into(), - pov.clone(), - ) - .encode(), - ProtocolName::from(""), - ))) - .expect("Sending response should succeed"); - - assert_candidate_backing_second( - &mut virtual_overseer, - test_state.relay_parent, - test_state.chain_ids[0], - &pov, - // Async backing isn't enabled and thus it should do it the old way. - CollationVersion::V1, - ) - .await; - - virtual_overseer - }); -} - -// Test that other subsystems may modify collators' reputations. -#[test] -fn collator_reporting_works() { - let test_state = TestState::default(); - - test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer, .. } = test_harness; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - - let peer_b = PeerId::random(); - let peer_c = PeerId::random(); - - connect_and_declare_collator( - &mut virtual_overseer, - peer_b, - test_state.collators[0].clone(), - test_state.chain_ids[0], - CollationVersion::V1, - ) - .await; - - connect_and_declare_collator( - &mut virtual_overseer, - peer_c, - test_state.collators[1].clone(), - test_state.chain_ids[0], - CollationVersion::V1, - ) - .await; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::ReportCollator(test_state.collators[0].public()), - ) - .await; - - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::NetworkBridgeTx( - NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep)), - ) => { - assert_eq!(peer, peer_b); - assert_eq!(rep.value, COST_REPORT_BAD.cost_or_benefit()); - } - ); - - virtual_overseer - }); -} - // Test that we verify the signatures on `Declare` and `AdvertiseCollation` messages. #[test] fn collator_authentication_verification_works() { @@ -725,32 +514,18 @@ fn collator_authentication_verification_works() { }); } -/// Tests that a validator fetches only one collation at any moment of time -/// per relay parent and ignores other advertisements once a candidate gets -/// seconded. +/// Tests that on a V1 Advertisement a validator fetches only one collation at any moment of time +/// per relay parent and ignores other V1 advertisements once a candidate gets seconded. #[test] -fn fetch_one_collation_at_a_time() { - let test_state = TestState::default(); +fn fetch_one_collation_at_a_time_for_v1_advertisement() { + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; - let second = Hash::random(); - - let our_view = our_view![test_state.relay_parent, second]; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view.clone(), - )), - ) - .await; - - // Iter over view since the order may change due to sorted invariant. - for hash in our_view.iter() { - assert_async_backing_params_request(&mut virtual_overseer, *hash).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - } + let second = Hash::from_low_u64_be(test_state.relay_parent.to_low_u64_be() - 1); + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0), (second, 1)]) + .await; let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -773,8 +548,8 @@ fn fetch_one_collation_at_a_time() { ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; - advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_b, relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_c, relay_parent, None).await; let response_channel = assert_fetch_collation_request( &mut virtual_overseer, @@ -829,27 +604,14 @@ fn fetch_one_collation_at_a_time() { /// timeout and in case of an error. #[test] fn fetches_next_collation() { - let test_state = TestState::default(); + let mut test_state = TestState::with_one_scheduled_para(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; + let first = test_state.relay_parent; let second = Hash::random(); - - let our_view = our_view![test_state.relay_parent, second]; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view.clone(), - )), - ) - .await; - - for hash in our_view.iter() { - assert_async_backing_params_request(&mut virtual_overseer, *hash).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - } + update_view(&mut virtual_overseer, &mut test_state, vec![(first, 0), (second, 1)]).await; let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -959,21 +721,13 @@ fn fetches_next_collation() { #[test] fn reject_connection_to_next_group() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; let peer_b = PeerId::random(); @@ -1006,27 +760,13 @@ fn reject_connection_to_next_group() { // invalid. #[test] fn fetch_next_collation_on_invalid_collation() { - let test_state = TestState::default(); + let mut test_state = TestState::with_one_scheduled_para(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; - let second = Hash::random(); - - let our_view = our_view![test_state.relay_parent, second]; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view.clone(), - )), - ) - .await; - - for hash in our_view.iter() { - assert_async_backing_params_request(&mut virtual_overseer, *hash).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - } + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -1049,12 +789,12 @@ fn fetch_next_collation_on_invalid_collation() { ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; - advertise_collation(&mut virtual_overseer, peer_c, test_state.relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_b, relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_c, relay_parent, None).await; let response_channel = assert_fetch_collation_request( &mut virtual_overseer, - test_state.relay_parent, + relay_parent, test_state.chain_ids[0], None, ) @@ -1064,7 +804,7 @@ fn fetch_next_collation_on_invalid_collation() { let mut candidate_a = dummy_candidate_receipt_bad_sig(dummy_hash(), Some(Default::default())); candidate_a.descriptor.para_id = test_state.chain_ids[0]; - candidate_a.descriptor.relay_parent = test_state.relay_parent; + candidate_a.descriptor.relay_parent = relay_parent; candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); response_channel .send(Ok(( @@ -1079,7 +819,7 @@ fn fetch_next_collation_on_invalid_collation() { let receipt = assert_candidate_backing_second( &mut virtual_overseer, - test_state.relay_parent, + relay_parent, test_state.chain_ids[0], &pov, CollationVersion::V1, @@ -1089,7 +829,7 @@ fn fetch_next_collation_on_invalid_collation() { // Inform that the candidate was invalid. overseer_send( &mut virtual_overseer, - CollatorProtocolMessage::Invalid(test_state.relay_parent, receipt), + CollatorProtocolMessage::Invalid(relay_parent, receipt), ) .await; @@ -1106,7 +846,7 @@ fn fetch_next_collation_on_invalid_collation() { // We should see a request for another collation. assert_fetch_collation_request( &mut virtual_overseer, - test_state.relay_parent, + relay_parent, test_state.chain_ids[0], None, ) @@ -1118,25 +858,15 @@ fn fetch_next_collation_on_invalid_collation() { #[test] fn inactive_disconnected() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; - let hash_a = test_state.relay_parent; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![hash_a], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, hash_a).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; let peer_b = PeerId::random(); @@ -1148,11 +878,11 @@ fn inactive_disconnected() { CollationVersion::V1, ) .await; - advertise_collation(&mut virtual_overseer, peer_b, test_state.relay_parent, None).await; + advertise_collation(&mut virtual_overseer, peer_b, relay_parent, None).await; assert_fetch_collation_request( &mut virtual_overseer, - test_state.relay_parent, + relay_parent, test_state.chain_ids[0], None, ) @@ -1167,32 +897,24 @@ fn inactive_disconnected() { #[test] fn activity_extends_life() { - let test_state = TestState::default(); + let mut test_state = TestState::with_one_scheduled_para(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; let pair = CollatorPair::generate().0; - let hash_a = test_state.relay_parent; - let hash_b = Hash::repeat_byte(1); - let hash_c = Hash::repeat_byte(2); - - let our_view = our_view![hash_a, hash_b, hash_c]; + let hash_a = Hash::from_low_u64_be(12); + let hash_b = Hash::from_low_u64_be(11); + let hash_c = Hash::from_low_u64_be(10); - overseer_send( + update_view( &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view.clone(), - )), + &mut test_state, + vec![(hash_a, 0), (hash_b, 1), (hash_c, 2)], ) .await; - for hash in our_view.iter() { - assert_async_backing_params_request(&mut virtual_overseer, *hash).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - } - let peer_b = PeerId::random(); connect_and_declare_collator( @@ -1250,21 +972,13 @@ fn activity_extends_life() { #[test] fn disconnect_if_no_declare() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; let peer_b = PeerId::random(); @@ -1287,26 +1001,16 @@ fn disconnect_if_no_declare() { #[test] fn disconnect_if_wrong_declare() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; - let pair = CollatorPair::generate().0; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - let peer_b = PeerId::random(); + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; + overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( @@ -1349,26 +1053,16 @@ fn disconnect_if_wrong_declare() { #[test] fn delay_reputation_change() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| false), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; - let pair = CollatorPair::generate().0; - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - let peer_b = PeerId::random(); + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; + overseer_send( &mut virtual_overseer, CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( @@ -1442,43 +1136,24 @@ fn view_change_clears_old_collators() { let pair = CollatorPair::generate().0; - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![test_state.relay_parent], - )), - ) - .await; - - assert_async_backing_params_request(&mut virtual_overseer, test_state.relay_parent).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - - let peer_b = PeerId::random(); + let peer = PeerId::random(); + let relay_parent = test_state.relay_parent; + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent, 0)]).await; connect_and_declare_collator( &mut virtual_overseer, - peer_b, + peer, pair.clone(), test_state.chain_ids[0], CollationVersion::V1, ) .await; - let hash_b = Hash::repeat_byte(69); - - overseer_send( - &mut virtual_overseer, - CollatorProtocolMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![hash_b], - )), - ) - .await; - test_state.group_rotation_info = test_state.group_rotation_info.bump_rotation(); - assert_async_backing_params_request(&mut virtual_overseer, hash_b).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; - assert_collator_disconnect(&mut virtual_overseer, peer_b).await; + update_view(&mut virtual_overseer, &mut test_state, vec![]).await; + + assert_collator_disconnect(&mut virtual_overseer, peer).await; virtual_overseer }) diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index e040163cd905..fac63aeb2097 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -20,19 +20,17 @@ use super::*; use polkadot_node_subsystem::messages::ChainApiMessage; use polkadot_primitives::{ - vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, AsyncBackingParams, + vstaging::{CommittedCandidateReceiptV2 as CommittedCandidateReceipt, MutateDescriptorV2}, BlockNumber, CandidateCommitments, Header, SigningContext, ValidatorId, }; +use polkadot_primitives_test_helpers::dummy_committed_candidate_receipt_v2; use rstest::rstest; -const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = - AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; - fn get_parent_hash(hash: Hash) -> Hash { Hash::from_low_u64_be(hash.to_low_u64_be() + 1) } -async fn assert_assign_incoming( +async fn assert_construct_per_relay_parent( virtual_overseer: &mut VirtualOverseer, test_state: &TestState, hash: Hash, @@ -47,7 +45,8 @@ async fn assert_assign_incoming( msg, AllMessages::RuntimeApi( RuntimeApiMessage::Request(parent, RuntimeApiRequest::Validators(tx)) - ) if parent == hash => { + ) => { + assert_eq!(parent, hash); tx.send(Ok(test_state.validator_public.clone())).unwrap(); } ); @@ -64,25 +63,6 @@ async fn assert_assign_incoming( } ); - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx)) - ) if parent == hash => { - tx.send(Ok(test_state.cores.clone())).unwrap(); - } - ); - - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - parent, - RuntimeApiRequest::Version(tx), - )) if parent == hash => { - let _ = tx.send(Ok(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)); - } - ); - assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( @@ -97,12 +77,11 @@ async fn assert_assign_incoming( /// Handle a view update. pub(super) async fn update_view( virtual_overseer: &mut VirtualOverseer, - test_state: &TestState, + test_state: &mut TestState, new_view: Vec<(Hash, u32)>, // Hash and block number. - activated: u8, // How many new heads does this update contain? ) -> Option { + let last_block_from_view = new_view.last().map(|t| t.1); let new_view: HashMap = HashMap::from_iter(new_view); - let our_view = OurView::new(new_view.keys().map(|hash| *hash), 0); overseer_send( @@ -112,19 +91,44 @@ pub(super) async fn update_view( .await; let mut next_overseer_message = None; - for _ in 0..activated { + for _ in 0..new_view.len() { + let msg = match next_overseer_message.take() { + Some(msg) => msg, + None => overseer_recv(virtual_overseer).await, + }; + let (leaf_hash, leaf_number) = assert_matches!( - overseer_recv(virtual_overseer).await, + msg, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, - RuntimeApiRequest::AsyncBackingParams(tx), + RuntimeApiRequest::SessionIndexForChild(tx) )) => { - tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); + tx.send(Ok(test_state.session_index)).unwrap(); (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) } ); - assert_assign_incoming( + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::AsyncBackingParams(tx), + )) => { + tx.send(Ok(test_state.async_backing_params)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::NodeFeatures(_, tx) + )) => { + tx.send(Ok(test_state.node_features.clone())).unwrap(); + } + ); + + assert_construct_per_relay_parent( virtual_overseer, test_state, leaf_hash, @@ -133,7 +137,8 @@ pub(super) async fn update_view( ) .await; - let min_number = leaf_number.saturating_sub(ASYNC_BACKING_PARAMETERS.allowed_ancestry_len); + let min_number = + leaf_number.saturating_sub(test_state.async_backing_params.allowed_ancestry_len); let ancestry_len = leaf_number + 1 - min_number; let ancestry_hashes = std::iter::successors(Some(leaf_hash), |h| Some(get_parent_hash(*h))) @@ -146,6 +151,10 @@ pub(super) async fn update_view( { let mut ancestry_iter = ancestry_iter.clone(); while let Some((hash, number)) = ancestry_iter.next() { + if Some(number) == test_state.last_known_block { + break; + } + // May be `None` for the last element. let parent_hash = ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); @@ -193,7 +202,10 @@ pub(super) async fn update_view( // Skip the leaf. for (hash, number) in ancestry_iter.skip(1).take(requested_len.saturating_sub(1)) { - assert_assign_incoming( + if Some(number) == test_state.last_known_block { + break; + } + assert_construct_per_relay_parent( virtual_overseer, test_state, hash, @@ -203,6 +215,9 @@ pub(super) async fn update_view( .await; } } + + test_state.last_known_block = last_block_from_view; + next_overseer_message } @@ -326,9 +341,140 @@ async fn assert_persisted_validation_data( } } +// Combines dummy candidate creation, advertisement and fetching in a single call +async fn submit_second_and_assert( + virtual_overseer: &mut VirtualOverseer, + keystore: KeystorePtr, + para_id: ParaId, + relay_parent: Hash, + collator: PeerId, + candidate_head_data: HeadData, +) { + let (candidate, commitments) = + create_dummy_candidate_and_commitments(para_id, candidate_head_data, relay_parent); + + let candidate_hash = candidate.hash(); + let parent_head_data_hash = Hash::zero(); + + assert_advertise_collation( + virtual_overseer, + collator, + relay_parent, + para_id, + (candidate_hash, parent_head_data_hash), + ) + .await; + + let response_channel = assert_fetch_collation_request( + virtual_overseer, + relay_parent, + para_id, + Some(candidate_hash), + ) + .await; + + let pov = PoV { block_data: BlockData(vec![1]) }; + + send_collation_and_assert_processing( + virtual_overseer, + keystore, + relay_parent, + para_id, + collator, + response_channel, + candidate, + commitments, + pov, + ) + .await; +} + +fn create_dummy_candidate_and_commitments( + para_id: ParaId, + candidate_head_data: HeadData, + relay_parent: Hash, +) -> (CandidateReceipt, CandidateCommitments) { + let mut candidate = dummy_candidate_receipt_bad_sig(relay_parent, Some(Default::default())); + candidate.descriptor.para_id = para_id; + candidate.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); + let commitments = CandidateCommitments { + head_data: candidate_head_data, + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate.commitments_hash = commitments.hash(); + + (candidate.into(), commitments) +} + +async fn assert_advertise_collation( + virtual_overseer: &mut VirtualOverseer, + peer: PeerId, + relay_parent: Hash, + expected_para_id: ParaId, + candidate: (CandidateHash, Hash), +) { + advertise_collation(virtual_overseer, peer, relay_parent, Some(candidate)).await; + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate.0); + assert_eq!(request.candidate_para_id, expected_para_id); + assert_eq!(request.parent_head_data_hash, candidate.1); + tx.send(true).expect("receiving side should be alive"); + } + ); +} + +async fn send_collation_and_assert_processing( + virtual_overseer: &mut VirtualOverseer, + keystore: KeystorePtr, + relay_parent: Hash, + expected_para_id: ParaId, + expected_peer_id: PeerId, + response_channel: ResponseSender, + candidate: CandidateReceipt, + commitments: CandidateCommitments, + pov: PoV, +) { + response_channel + .send(Ok(( + request_v2::CollationFetchingResponse::Collation(candidate.clone(), pov.clone()) + .encode(), + ProtocolName::from(""), + ))) + .expect("Sending response should succeed"); + + assert_candidate_backing_second( + virtual_overseer, + relay_parent, + expected_para_id, + &pov, + CollationVersion::V2, + ) + .await; + + let candidate = CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments }; + + send_seconded_statement(virtual_overseer, keystore.clone(), &candidate).await; + + assert_collation_seconded( + virtual_overseer, + relay_parent, + expected_peer_id, + CollationVersion::V2, + ) + .await; +} + #[test] fn v1_advertisement_accepted_and_seconded() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, keystore } = test_harness; @@ -338,7 +484,7 @@ fn v1_advertisement_accepted_and_seconded() { let head_b = Hash::from_low_u64_be(128); let head_b_num: u32 = 0; - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; let peer_a = PeerId::random(); @@ -366,7 +512,7 @@ fn v1_advertisement_accepted_and_seconded() { candidate.descriptor.para_id = test_state.chain_ids[0]; candidate.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); let commitments = CandidateCommitments { - head_data: HeadData(vec![1 as u8]), + head_data: HeadData(vec![1u8]), horizontal_messages: Default::default(), upward_messages: Default::default(), new_validation_code: None, @@ -406,8 +552,8 @@ fn v1_advertisement_accepted_and_seconded() { } #[test] -fn v1_advertisement_rejected_on_non_active_leave() { - let test_state = TestState::default(); +fn v1_advertisement_rejected_on_non_active_leaf() { + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; @@ -417,7 +563,7 @@ fn v1_advertisement_rejected_on_non_active_leave() { let head_b = Hash::from_low_u64_be(128); let head_b_num: u32 = 5; - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; let peer_a = PeerId::random(); @@ -449,7 +595,7 @@ fn v1_advertisement_rejected_on_non_active_leave() { #[test] fn accept_advertisements_from_implicit_view() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; @@ -467,7 +613,7 @@ fn accept_advertisements_from_implicit_view() { let head_d = get_parent_hash(head_c); // Activated leaf is `b`, but the collation will be based on `c`. - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; let peer_a = PeerId::random(); let peer_b = PeerId::random(); @@ -552,24 +698,26 @@ fn accept_advertisements_from_implicit_view() { #[test] fn second_multiple_candidates_per_relay_parent() { - let test_state = TestState::default(); + let mut test_state = TestState::with_one_scheduled_para(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, keystore } = test_harness; let pair = CollatorPair::generate().0; - // Grandparent of head `a`. + let head_a = Hash::from_low_u64_be(130); + let head_a_num: u32 = 0; + let head_b = Hash::from_low_u64_be(128); let head_b_num: u32 = 2; - // Grandparent of head `b`. - // Group rotation frequency is 1 by default, at `c` we're assigned - // to the first para. - let head_c = Hash::from_low_u64_be(130); - - // Activated leaf is `b`, but the collation will be based on `c`. - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + // Activated leaf is `a` and `b`.The collation will be based on `b`. + update_view( + &mut virtual_overseer, + &mut test_state, + vec![(head_a, head_a_num), (head_b, head_b_num)], + ) + .await; let peer_a = PeerId::random(); @@ -582,80 +730,17 @@ fn second_multiple_candidates_per_relay_parent() { ) .await; - for i in 0..(ASYNC_BACKING_PARAMETERS.max_candidate_depth + 1) { - let mut candidate = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); - candidate.descriptor.para_id = test_state.chain_ids[0]; - candidate.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); - let commitments = CandidateCommitments { - head_data: HeadData(vec![i as u8]), - horizontal_messages: Default::default(), - upward_messages: Default::default(), - new_validation_code: None, - processed_downward_messages: 0, - hrmp_watermark: 0, - }; - candidate.commitments_hash = commitments.hash(); - let candidate: CandidateReceipt = candidate.into(); - - let candidate_hash = candidate.hash(); - let parent_head_data_hash = Hash::zero(); - - advertise_collation( - &mut virtual_overseer, - peer_a, - head_c, - Some((candidate_hash, parent_head_data_hash)), - ) - .await; - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidate_hash); - assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); - tx.send(true).expect("receiving side should be alive"); - } - ); - - let response_channel = assert_fetch_collation_request( - &mut virtual_overseer, - head_c, - test_state.chain_ids[0], - Some(candidate_hash), - ) - .await; - - let pov = PoV { block_data: BlockData(vec![1]) }; - - response_channel - .send(Ok(( - request_v2::CollationFetchingResponse::Collation( - candidate.clone(), - pov.clone(), - ) - .encode(), - ProtocolName::from(""), - ))) - .expect("Sending response should succeed"); - - assert_candidate_backing_second( + // `allowed_ancestry_len` equals the size of the claim queue + for i in 0..test_state.async_backing_params.allowed_ancestry_len { + submit_second_and_assert( &mut virtual_overseer, - head_c, + keystore.clone(), test_state.chain_ids[0], - &pov, - CollationVersion::V2, + head_a, + peer_a, + HeadData(vec![i as u8]), ) .await; - - let candidate = - CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments }; - - send_seconded_statement(&mut virtual_overseer, keystore.clone(), &candidate).await; - - assert_collation_seconded(&mut virtual_overseer, head_c, peer_a, CollationVersion::V2) - .await; } // No more advertisements can be made for this relay parent. @@ -663,21 +748,14 @@ fn second_multiple_candidates_per_relay_parent() { advertise_collation( &mut virtual_overseer, peer_a, - head_c, + head_a, Some((candidate_hash, Hash::zero())), ) .await; - // Reported because reached the limit of advertisements per relay parent. - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::NetworkBridgeTx( - NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), - ) => { - assert_eq!(peer_a, peer_id); - assert_eq!(rep.value, COST_UNEXPECTED_MESSAGE.cost_or_benefit()); - } - ); + // Rejected but not reported because reached the limit of advertisements for the para_id + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); // By different peer too (not reported). let pair_b = CollatorPair::generate().0; @@ -696,7 +774,7 @@ fn second_multiple_candidates_per_relay_parent() { advertise_collation( &mut virtual_overseer, peer_b, - head_c, + head_a, Some((candidate_hash, Hash::zero())), ) .await; @@ -710,7 +788,7 @@ fn second_multiple_candidates_per_relay_parent() { #[test] fn fetched_collation_sanity_check() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; @@ -727,7 +805,7 @@ fn fetched_collation_sanity_check() { let head_c = Hash::from_low_u64_be(130); // Activated leaf is `b`, but the collation will be based on `c`. - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; let peer_a = PeerId::random(); @@ -821,7 +899,7 @@ fn fetched_collation_sanity_check() { #[test] fn sanity_check_invalid_parent_head_data() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; @@ -831,7 +909,7 @@ fn sanity_check_invalid_parent_head_data() { let head_c = Hash::from_low_u64_be(130); let head_c_num = 3; - update_view(&mut virtual_overseer, &test_state, vec![(head_c, head_c_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_c, head_c_num)]).await; let peer_a = PeerId::random(); @@ -941,7 +1019,7 @@ fn sanity_check_invalid_parent_head_data() { #[test] fn advertisement_spam_protection() { - let test_state = TestState::default(); + let mut test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, .. } = test_harness; @@ -954,7 +1032,7 @@ fn advertisement_spam_protection() { let head_c = get_parent_hash(head_b); // Activated leaf is `b`, but the collation will be based on `c`. - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; let peer_a = PeerId::random(); connect_and_declare_collator( @@ -1015,7 +1093,7 @@ fn advertisement_spam_protection() { #[case(true)] #[case(false)] fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { - let test_state = TestState::default(); + let mut test_state = TestState::with_one_scheduled_para(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { let TestHarness { mut virtual_overseer, keystore } = test_harness; @@ -1032,7 +1110,7 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { let head_c = Hash::from_low_u64_be(130); // Activated leaf is `b`, but the collation will be based on `c`. - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; let peer_a = PeerId::random(); @@ -1314,3 +1392,1088 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { virtual_overseer }); } + +#[rstest] +#[case(true)] +#[case(false)] +fn v2_descriptor(#[case] v2_feature_enabled: bool) { + let mut test_state = TestState::default(); + + if !v2_feature_enabled { + test_state.node_features = NodeFeatures::EMPTY; + } + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let pair_a = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 0; + + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; + + let peer_a = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::V2, + ) + .await; + + let mut committed_candidate = dummy_committed_candidate_receipt_v2(head_b); + committed_candidate.descriptor.set_para_id(test_state.chain_ids[0]); + committed_candidate + .descriptor + .set_persisted_validation_data_hash(dummy_pvd().hash()); + // First para is assigned to core 0. + committed_candidate.descriptor.set_core_index(CoreIndex(0)); + committed_candidate.descriptor.set_session_index(test_state.session_index); + + let candidate: CandidateReceipt = committed_candidate.clone().to_plain(); + let pov = PoV { block_data: BlockData(vec![1]) }; + + let candidate_hash = candidate.hash(); + let parent_head_data_hash = Hash::zero(); + + advertise_collation( + &mut virtual_overseer, + peer_a, + head_b, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + head_b, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + + response_channel + .send(Ok(( + request_v2::CollationFetchingResponse::Collation(candidate.clone(), pov.clone()) + .encode(), + ProtocolName::from(""), + ))) + .expect("Sending response should succeed"); + + if v2_feature_enabled { + assert_candidate_backing_second( + &mut virtual_overseer, + head_b, + test_state.chain_ids[0], + &pov, + CollationVersion::V2, + ) + .await; + + send_seconded_statement(&mut virtual_overseer, keystore.clone(), &committed_candidate) + .await; + + assert_collation_seconded(&mut virtual_overseer, head_b, peer_a, CollationVersion::V2) + .await; + } else { + // Reported malicious. Used v2 descriptor without the feature being enabled + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), + ) => { + assert_eq!(peer_a, peer_id); + assert_eq!(rep.value, COST_REPORT_BAD.cost_or_benefit()); + } + ); + } + + virtual_overseer + }); +} + +#[test] +fn invalid_v2_descriptor() { + let mut test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair_a = CollatorPair::generate().0; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 0; + + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; + + let peer_a = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::V2, + ) + .await; + + let mut candidates = vec![]; + + let mut committed_candidate = dummy_committed_candidate_receipt_v2(head_b); + committed_candidate.descriptor.set_para_id(test_state.chain_ids[0]); + committed_candidate + .descriptor + .set_persisted_validation_data_hash(dummy_pvd().hash()); + // First para is assigned to core 0, set an invalid core index. + committed_candidate.descriptor.set_core_index(CoreIndex(10)); + committed_candidate.descriptor.set_session_index(test_state.session_index); + + candidates.push(committed_candidate.clone()); + + // Invalid session index. + committed_candidate.descriptor.set_core_index(CoreIndex(0)); + committed_candidate.descriptor.set_session_index(10); + + candidates.push(committed_candidate); + + for committed_candidate in candidates { + let candidate: CandidateReceipt = committed_candidate.clone().to_plain(); + let pov = PoV { block_data: BlockData(vec![1]) }; + + let candidate_hash = candidate.hash(); + let parent_head_data_hash = Hash::zero(); + + advertise_collation( + &mut virtual_overseer, + peer_a, + head_b, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + head_b, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + + response_channel + .send(Ok(( + request_v2::CollationFetchingResponse::Collation( + candidate.clone(), + pov.clone(), + ) + .encode(), + ProtocolName::from(""), + ))) + .expect("Sending response should succeed"); + + // Reported malicious. Invalid core index + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), + ) => { + assert_eq!(peer_a, peer_id); + assert_eq!(rep.value, COST_REPORT_BAD.cost_or_benefit()); + } + ); + } + + virtual_overseer + }); +} + +#[test] +fn fair_collation_fetches() { + let mut test_state = TestState::with_shared_core(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let head_b = Hash::from_low_u64_be(128); + let head_b_num: u32 = 2; + + update_view(&mut virtual_overseer, &mut test_state, vec![(head_b, head_b_num)]).await; + + let peer_a = PeerId::random(); + let pair_a = CollatorPair::generate().0; + + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair_a.clone(), + test_state.chain_ids[0], + CollationVersion::V2, + ) + .await; + + let peer_b = PeerId::random(); + let pair_b = CollatorPair::generate().0; + + connect_and_declare_collator( + &mut virtual_overseer, + peer_b, + pair_b.clone(), + test_state.chain_ids[1], + CollationVersion::V2, + ) + .await; + + // `peer_a` sends two advertisements (its claim queue limit) + for i in 0..2u8 { + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + head_b, + peer_a, + HeadData(vec![i]), + ) + .await; + } + + // `peer_a` sends another advertisement and it is ignored + let candidate_hash = CandidateHash(Hash::repeat_byte(0xAA)); + advertise_collation( + &mut virtual_overseer, + peer_a, + head_b, + Some((candidate_hash, Hash::zero())), + ) + .await; + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // `peer_b` should still be able to advertise its collation + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[1]), + head_b, + peer_b, + HeadData(vec![0u8]), + ) + .await; + + // And no more advertisements can be made for this relay parent. + + // verify for peer_a + let candidate_hash = CandidateHash(Hash::repeat_byte(0xBB)); + advertise_collation( + &mut virtual_overseer, + peer_a, + head_b, + Some((candidate_hash, Hash::zero())), + ) + .await; + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // verify for peer_b + let candidate_hash = CandidateHash(Hash::repeat_byte(0xCC)); + advertise_collation( + &mut virtual_overseer, + peer_b, + head_b, + Some((candidate_hash, Hash::zero())), + ) + .await; + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + +#[test] +fn collation_fetching_prefer_entries_earlier_in_claim_queue() { + let mut test_state = TestState::with_shared_core(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let pair_a = CollatorPair::generate().0; + let collator_a = PeerId::random(); + let para_id_a = test_state.chain_ids[0]; + + let pair_b = CollatorPair::generate().0; + let collator_b = PeerId::random(); + let para_id_b = test_state.chain_ids[1]; + + let head = Hash::from_low_u64_be(128); + let head_num: u32 = 2; + + update_view(&mut virtual_overseer, &mut test_state, vec![(head, head_num)]).await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_a, + pair_a.clone(), + para_id_a, + CollationVersion::V2, + ) + .await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_b, + pair_b.clone(), + para_id_b, + CollationVersion::V2, + ) + .await; + + let (candidate_a1, commitments_a1) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![0u8]), head); + let (candidate_b1, commitments_b1) = + create_dummy_candidate_and_commitments(para_id_b, HeadData(vec![1u8]), head); + let (candidate_a2, commitments_a2) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![2u8]), head); + let (candidate_a3, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![3u8]), head); + let parent_head_data_a1 = HeadData(vec![0u8]); + let parent_head_data_b1 = HeadData(vec![1u8]); + let parent_head_data_a2 = HeadData(vec![2u8]); + let parent_head_data_a3 = HeadData(vec![3u8]); + + // advertise a collation for `para_id_a` but don't send the collation. This will be a + // pending fetch. + assert_advertise_collation( + &mut virtual_overseer, + collator_a, + head, + para_id_a, + (candidate_a1.hash(), parent_head_data_a1.hash()), + ) + .await; + + let response_channel_a1 = assert_fetch_collation_request( + &mut virtual_overseer, + head, + para_id_a, + Some(candidate_a1.hash()), + ) + .await; + + // advertise another collation for `para_id_a`. This one should be fetched last. + assert_advertise_collation( + &mut virtual_overseer, + collator_a, + head, + para_id_a, + (candidate_a2.hash(), parent_head_data_a2.hash()), + ) + .await; + + // There is a pending collation so nothing should be fetched + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // Advertise a collation for `para_id_b`. This should be fetched second + assert_advertise_collation( + &mut virtual_overseer, + collator_b, + head, + para_id_b, + (candidate_b1.hash(), parent_head_data_b1.hash()), + ) + .await; + + // Again - no fetch because of the pending collation + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + //Now send a response for the first fetch and examine the second fetch + send_collation_and_assert_processing( + &mut virtual_overseer, + keystore.clone(), + head, + para_id_a, + collator_a, + response_channel_a1, + candidate_a1, + commitments_a1, + PoV { block_data: BlockData(vec![1]) }, + ) + .await; + + // The next fetch should be for `para_id_b` + let response_channel_b = assert_fetch_collation_request( + &mut virtual_overseer, + head, + para_id_b, + Some(candidate_b1.hash()), + ) + .await; + + send_collation_and_assert_processing( + &mut virtual_overseer, + keystore.clone(), + head, + para_id_b, + collator_b, + response_channel_b, + candidate_b1, + commitments_b1, + PoV { block_data: BlockData(vec![2]) }, + ) + .await; + + // and the final one for `para_id_a` + let response_channel_a2 = assert_fetch_collation_request( + &mut virtual_overseer, + head, + para_id_a, + Some(candidate_a2.hash()), + ) + .await; + + // Advertise another collation for `para_id_a`. This should be rejected as there is no slot + // in the claim queue for it. One is fetched and one is pending. + advertise_collation( + &mut virtual_overseer, + collator_a, + head, + Some((candidate_a3.hash(), parent_head_data_a3.hash())), + ) + .await; + + // `CanSecond` shouldn't be sent as the advertisement should be ignored + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // Fetch the pending collation + send_collation_and_assert_processing( + &mut virtual_overseer, + keystore.clone(), + head, + para_id_a, + collator_a, + response_channel_a2, + candidate_a2, + commitments_a2, + PoV { block_data: BlockData(vec![3]) }, + ) + .await; + + virtual_overseer + }); +} + +#[test] +fn collation_fetching_considers_advertisements_from_the_whole_view() { + let mut test_state = TestState::with_shared_core(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let pair_a = CollatorPair::generate().0; + let collator_a = PeerId::random(); + let para_id_a = test_state.chain_ids[0]; + + let pair_b = CollatorPair::generate().0; + let collator_b = PeerId::random(); + let para_id_b = test_state.chain_ids[1]; + + let relay_parent_2 = Hash::from_low_u64_be(test_state.relay_parent.to_low_u64_be() - 1); + + assert_eq!( + *test_state.claim_queue.get(&CoreIndex(0)).unwrap(), + VecDeque::from([para_id_b, para_id_a, para_id_a]) + ); + + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent_2, 2)]).await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_a, + pair_a.clone(), + para_id_a, + CollationVersion::V2, + ) + .await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_b, + pair_b.clone(), + para_id_b, + CollationVersion::V2, + ) + .await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_a, + relay_parent_2, + collator_a, + HeadData(vec![0u8]), + ) + .await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_b, + relay_parent_2, + collator_b, + HeadData(vec![1u8]), + ) + .await; + + let relay_parent_3 = Hash::from_low_u64_be(relay_parent_2.to_low_u64_be() - 1); + *test_state.claim_queue.get_mut(&CoreIndex(0)).unwrap() = + VecDeque::from([para_id_a, para_id_a, para_id_b]); + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent_3, 3)]).await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_b, + relay_parent_3, + collator_b, + HeadData(vec![3u8]), + ) + .await; + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_a, + relay_parent_3, + collator_a, + HeadData(vec![3u8]), + ) + .await; + + // At this point the claim queue is satisfied and any advertisement at `relay_parent_4` + // must be ignored + + let (candidate_a, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![5u8]), relay_parent_3); + let parent_head_data_a = HeadData(vec![5u8]); + + advertise_collation( + &mut virtual_overseer, + collator_a, + relay_parent_3, + Some((candidate_a.hash(), parent_head_data_a.hash())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + let (candidate_b, _) = + create_dummy_candidate_and_commitments(para_id_b, HeadData(vec![6u8]), relay_parent_3); + let parent_head_data_b = HeadData(vec![6u8]); + + advertise_collation( + &mut virtual_overseer, + collator_b, + relay_parent_3, + Some((candidate_b.hash(), parent_head_data_b.hash())), + ) + .await; + + // `CanSecond` shouldn't be sent as the advertisement should be ignored + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // At `relay_parent_6` the advertisement for `para_id_b` falls out of the view so a new one + // can be accepted + let relay_parent_6 = Hash::from_low_u64_be(relay_parent_3.to_low_u64_be() - 2); + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent_6, 6)]).await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_a, + relay_parent_6, + collator_a, + HeadData(vec![3u8]), + ) + .await; + + virtual_overseer + }); +} + +#[test] +fn collation_fetching_fairness_handles_old_claims() { + let mut test_state = TestState::with_shared_core(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let pair_a = CollatorPair::generate().0; + let collator_a = PeerId::random(); + let para_id_a = test_state.chain_ids[0]; + + let pair_b = CollatorPair::generate().0; + let collator_b = PeerId::random(); + let para_id_b = test_state.chain_ids[1]; + + let relay_parent_2 = Hash::from_low_u64_be(test_state.relay_parent.to_low_u64_be() - 1); + + *test_state.claim_queue.get_mut(&CoreIndex(0)).unwrap() = + VecDeque::from([para_id_a, para_id_b, para_id_a]); + + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent_2, 2)]).await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_a, + pair_a.clone(), + para_id_a, + CollationVersion::V2, + ) + .await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_b, + pair_b.clone(), + para_id_b, + CollationVersion::V2, + ) + .await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_a, + relay_parent_2, + collator_a, + HeadData(vec![0u8]), + ) + .await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_b, + relay_parent_2, + collator_b, + HeadData(vec![1u8]), + ) + .await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_a, + relay_parent_2, + collator_a, + HeadData(vec![2u8]), + ) + .await; + + let relay_parent_3 = Hash::from_low_u64_be(relay_parent_2.to_low_u64_be() - 1); + + *test_state.claim_queue.get_mut(&CoreIndex(0)).unwrap() = + VecDeque::from([para_id_b, para_id_a, para_id_b]); + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent_3, 3)]).await; + + // nothing is advertised here + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + let relay_parent_4 = Hash::from_low_u64_be(relay_parent_3.to_low_u64_be() - 1); + + *test_state.claim_queue.get_mut(&CoreIndex(0)).unwrap() = + VecDeque::from([para_id_a, para_id_b, para_id_a]); + update_view(&mut virtual_overseer, &mut test_state, vec![(relay_parent_4, 4)]).await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_b, + relay_parent_4, + collator_b, + HeadData(vec![3u8]), + ) + .await; + + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + para_id_a, + relay_parent_4, + collator_a, + HeadData(vec![4u8]), + ) + .await; + + // At this point the claim queue is satisfied and any advertisement at `relay_parent_4` + // must be ignored + + // Advertisement for `para_id_a` at `relay_parent_4` which must be ignored + let (candidate_a, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![5u8]), relay_parent_4); + let parent_head_data_a = HeadData(vec![5u8]); + + advertise_collation( + &mut virtual_overseer, + collator_a, + relay_parent_4, + Some((candidate_a.hash(), parent_head_data_a.hash())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // Advertisement for `para_id_b` at `relay_parent_4` which must be ignored + let (candidate_b, _) = + create_dummy_candidate_and_commitments(para_id_b, HeadData(vec![6u8]), relay_parent_4); + let parent_head_data_b = HeadData(vec![6u8]); + + advertise_collation( + &mut virtual_overseer, + collator_b, + relay_parent_4, + Some((candidate_b.hash(), parent_head_data_b.hash())), + ) + .await; + + // `CanSecond` shouldn't be sent as the advertisement should be ignored + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + +#[test] +fn claims_below_are_counted_correctly() { + let mut test_state = TestState::with_one_scheduled_para(); + + // Shorten the claim queue to make the test smaller + let mut claim_queue = BTreeMap::new(); + claim_queue.insert( + CoreIndex(0), + VecDeque::from_iter( + [ParaId::from(test_state.chain_ids[0]), ParaId::from(test_state.chain_ids[0])] + .into_iter(), + ), + ); + test_state.claim_queue = claim_queue; + test_state.async_backing_params.max_candidate_depth = 3; + test_state.async_backing_params.allowed_ancestry_len = 2; + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let hash_a = Hash::from_low_u64_be(test_state.relay_parent.to_low_u64_be() - 1); + let hash_b = Hash::from_low_u64_be(hash_a.to_low_u64_be() - 1); + let hash_c = Hash::from_low_u64_be(hash_b.to_low_u64_be() - 1); + + let pair_a = CollatorPair::generate().0; + let collator_a = PeerId::random(); + let para_id_a = test_state.chain_ids[0]; + + update_view(&mut virtual_overseer, &mut test_state, vec![(hash_c, 2)]).await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_a, + pair_a.clone(), + para_id_a, + CollationVersion::V2, + ) + .await; + + // A collation at hash_a claims the spot at hash_a + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_a, + collator_a, + HeadData(vec![0u8]), + ) + .await; + + // Another collation at hash_a claims the spot at hash_b + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_a, + collator_a, + HeadData(vec![1u8]), + ) + .await; + + // Collation at hash_c claims its own spot + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_c, + collator_a, + HeadData(vec![2u8]), + ) + .await; + + // Collation at hash_b should be ignored because the claim queue is satisfied + let (ignored_candidate, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![3u8]), hash_b); + + advertise_collation( + &mut virtual_overseer, + collator_a, + hash_b, + Some((ignored_candidate.hash(), Hash::random())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + +#[test] +fn claims_above_are_counted_correctly() { + let mut test_state = TestState::with_one_scheduled_para(); + + // Shorten the claim queue to make the test smaller + let mut claim_queue = BTreeMap::new(); + claim_queue.insert( + CoreIndex(0), + VecDeque::from_iter( + [ParaId::from(test_state.chain_ids[0]), ParaId::from(test_state.chain_ids[0])] + .into_iter(), + ), + ); + test_state.claim_queue = claim_queue; + test_state.async_backing_params.max_candidate_depth = 3; + test_state.async_backing_params.allowed_ancestry_len = 2; + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let hash_a = Hash::from_low_u64_be(test_state.relay_parent.to_low_u64_be() - 1); // block 0 + let hash_b = Hash::from_low_u64_be(hash_a.to_low_u64_be() - 1); // block 1 + let hash_c = Hash::from_low_u64_be(hash_b.to_low_u64_be() - 1); // block 2 + + let pair_a = CollatorPair::generate().0; + let collator_a = PeerId::random(); + let para_id_a = test_state.chain_ids[0]; + + update_view(&mut virtual_overseer, &mut test_state, vec![(hash_c, 2)]).await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_a, + pair_a.clone(), + para_id_a, + CollationVersion::V2, + ) + .await; + + // A collation at hash_b claims the spot at hash_b + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_b, + collator_a, + HeadData(vec![0u8]), + ) + .await; + + // Another collation at hash_b claims the spot at hash_c + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_b, + collator_a, + HeadData(vec![1u8]), + ) + .await; + + // Collation at hash_a claims its own spot + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_a, + collator_a, + HeadData(vec![0u8]), + ) + .await; + + // Another Collation at hash_a should be ignored because the claim queue is satisfied + let (ignored_candidate, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![2u8]), hash_a); + + advertise_collation( + &mut virtual_overseer, + collator_a, + hash_a, + Some((ignored_candidate.hash(), Hash::random())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // Same for hash_b + let (ignored_candidate, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![3u8]), hash_b); + + advertise_collation( + &mut virtual_overseer, + collator_a, + hash_b, + Some((ignored_candidate.hash(), Hash::random())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + +#[test] +fn claim_fills_last_free_slot() { + let mut test_state = TestState::with_one_scheduled_para(); + + // Shorten the claim queue to make the test smaller + let mut claim_queue = BTreeMap::new(); + claim_queue.insert( + CoreIndex(0), + VecDeque::from_iter( + [ParaId::from(test_state.chain_ids[0]), ParaId::from(test_state.chain_ids[0])] + .into_iter(), + ), + ); + test_state.claim_queue = claim_queue; + test_state.async_backing_params.max_candidate_depth = 3; + test_state.async_backing_params.allowed_ancestry_len = 2; + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, keystore } = test_harness; + + let hash_a = Hash::from_low_u64_be(test_state.relay_parent.to_low_u64_be() - 1); // block 0 + let hash_b = Hash::from_low_u64_be(hash_a.to_low_u64_be() - 1); // block 1 + let hash_c = Hash::from_low_u64_be(hash_b.to_low_u64_be() - 1); // block 2 + + let pair_a = CollatorPair::generate().0; + let collator_a = PeerId::random(); + let para_id_a = test_state.chain_ids[0]; + + update_view(&mut virtual_overseer, &mut test_state, vec![(hash_c, 2)]).await; + + connect_and_declare_collator( + &mut virtual_overseer, + collator_a, + pair_a.clone(), + para_id_a, + CollationVersion::V2, + ) + .await; + + // A collation at hash_a claims its spot + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_a, + collator_a, + HeadData(vec![0u8]), + ) + .await; + + // Collation at hash_b claims its own spot + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_b, + collator_a, + HeadData(vec![3u8]), + ) + .await; + + // Collation at hash_c claims its own spot + submit_second_and_assert( + &mut virtual_overseer, + keystore.clone(), + ParaId::from(test_state.chain_ids[0]), + hash_c, + collator_a, + HeadData(vec![2u8]), + ) + .await; + + // Another Collation at hash_a should be ignored because the claim queue is satisfied + let (ignored_candidate, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![3u8]), hash_a); + + advertise_collation( + &mut virtual_overseer, + collator_a, + hash_a, + Some((ignored_candidate.hash(), Hash::random())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + // Same for hash_b + let (ignored_candidate, _) = + create_dummy_candidate_and_commitments(para_id_a, HeadData(vec![4u8]), hash_b); + + advertise_collation( + &mut virtual_overseer, + collator_a, + hash_b, + Some((ignored_candidate.hash(), Hash::random())), + ) + .await; + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index b4dcafe09eb6..079a37ca0aff 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -5,37 +5,39 @@ description = "Polkadot Dispute Distribution subsystem, which ensures all concer authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +codec = { features = ["std"], workspace = true, default-features = true } +derive_more = { workspace = true, default-features = true } +fatality = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -derive_more = { workspace = true, default-features = true } -codec = { features = ["std"], workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +indexmap = { workspace = true } polkadot-erasure-coding = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } 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 } sc-network = { workspace = true, default-features = true } +schnellru = { workspace = true } sp-application-crypto = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } thiserror = { workspace = true } -fatality = { workspace = true } -schnellru = { workspace = true } -indexmap = { workspace = true } [dev-dependencies] +assert_matches = { workspace = true } async-channel = { workspace = true } async-trait = { workspace = true } +futures-timer = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +sc-keystore = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -futures-timer = { workspace = true } -assert_matches = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index c8c19e5de070..1ba556fc46b0 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -5,17 +5,19 @@ description = "Polkadot Gossip Support subsystem. Responsible for keeping track authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +sc-network = { workspace = true, default-features = true } +sc-network-common = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -sc-network-common = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } @@ -24,15 +26,15 @@ polkadot-primitives = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } rand = { workspace = true } rand_chacha = { workspace = true } -gum = { workspace = true, default-features = true } [dev-dependencies] -sp-keyring = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -sp-authority-discovery = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 3d51d3c0a565..83a24959f60a 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Primitives types for the Node-side" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -12,22 +14,22 @@ workspace = true [dependencies] async-channel = { workspace = true } async-trait = { workspace = true } +bitvec = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +derive_more = { workspace = true, default-features = true } +fatality = { workspace = true } +futures = { workspace = true } +gum = { workspace = true, default-features = true } hex = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +sc-authority-discovery = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } -sc-authority-discovery = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } strum = { features = ["derive"], workspace = true, default-features = true } -futures = { workspace = true } thiserror = { workspace = true } -fatality = { workspace = true } -rand = { workspace = true, default-features = true } -derive_more = { workspace = true, default-features = true } -gum = { workspace = true, default-features = true } -bitvec = { workspace = true, default-features = true } [dev-dependencies] rand_chacha = { workspace = true, default-features = true } diff --git a/polkadot/node/network/protocol/src/grid_topology.rs b/polkadot/node/network/protocol/src/grid_topology.rs index 4dd7d29fc25c..f4c1a07ba3c2 100644 --- a/polkadot/node/network/protocol/src/grid_topology.rs +++ b/polkadot/node/network/protocol/src/grid_topology.rs @@ -575,6 +575,22 @@ impl RequiredRouting { _ => false, } } + + /// Combine two required routing sets into one that would cover both routing modes. + pub fn combine(self, other: Self) -> Self { + match (self, other) { + (RequiredRouting::All, _) | (_, RequiredRouting::All) => RequiredRouting::All, + (RequiredRouting::GridXY, _) | (_, RequiredRouting::GridXY) => RequiredRouting::GridXY, + (RequiredRouting::GridX, RequiredRouting::GridY) | + (RequiredRouting::GridY, RequiredRouting::GridX) => RequiredRouting::GridXY, + (RequiredRouting::GridX, RequiredRouting::GridX) => RequiredRouting::GridX, + (RequiredRouting::GridY, RequiredRouting::GridY) => RequiredRouting::GridY, + (RequiredRouting::None, RequiredRouting::PendingTopology) | + (RequiredRouting::PendingTopology, RequiredRouting::None) => RequiredRouting::PendingTopology, + (RequiredRouting::None, _) | (RequiredRouting::PendingTopology, _) => other, + (_, RequiredRouting::None) | (_, RequiredRouting::PendingTopology) => self, + } + } } #[cfg(test)] @@ -587,6 +603,50 @@ mod tests { rand_chacha::ChaCha12Rng::seed_from_u64(12345) } + #[test] + fn test_required_routing_combine() { + assert_eq!(RequiredRouting::All.combine(RequiredRouting::None), RequiredRouting::All); + assert_eq!(RequiredRouting::All.combine(RequiredRouting::GridXY), RequiredRouting::All); + assert_eq!(RequiredRouting::GridXY.combine(RequiredRouting::All), RequiredRouting::All); + assert_eq!(RequiredRouting::None.combine(RequiredRouting::All), RequiredRouting::All); + assert_eq!(RequiredRouting::None.combine(RequiredRouting::None), RequiredRouting::None); + assert_eq!( + RequiredRouting::PendingTopology.combine(RequiredRouting::GridX), + RequiredRouting::GridX + ); + + assert_eq!( + RequiredRouting::GridX.combine(RequiredRouting::PendingTopology), + RequiredRouting::GridX + ); + assert_eq!(RequiredRouting::GridX.combine(RequiredRouting::GridY), RequiredRouting::GridXY); + assert_eq!(RequiredRouting::GridY.combine(RequiredRouting::GridX), RequiredRouting::GridXY); + assert_eq!( + RequiredRouting::GridXY.combine(RequiredRouting::GridXY), + RequiredRouting::GridXY + ); + assert_eq!(RequiredRouting::GridX.combine(RequiredRouting::GridX), RequiredRouting::GridX); + assert_eq!(RequiredRouting::GridY.combine(RequiredRouting::GridY), RequiredRouting::GridY); + + assert_eq!(RequiredRouting::None.combine(RequiredRouting::GridY), RequiredRouting::GridY); + assert_eq!(RequiredRouting::None.combine(RequiredRouting::GridX), RequiredRouting::GridX); + assert_eq!(RequiredRouting::None.combine(RequiredRouting::GridXY), RequiredRouting::GridXY); + + assert_eq!(RequiredRouting::GridY.combine(RequiredRouting::None), RequiredRouting::GridY); + assert_eq!(RequiredRouting::GridX.combine(RequiredRouting::None), RequiredRouting::GridX); + assert_eq!(RequiredRouting::GridXY.combine(RequiredRouting::None), RequiredRouting::GridXY); + + assert_eq!( + RequiredRouting::PendingTopology.combine(RequiredRouting::None), + RequiredRouting::PendingTopology + ); + + assert_eq!( + RequiredRouting::None.combine(RequiredRouting::PendingTopology), + RequiredRouting::PendingTopology + ); + } + #[test] fn test_random_routing_sample() { // This test is fragile as it relies on a specific ChaCha12Rng diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index 08059353033d..8bd058b8c849 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -5,45 +5,48 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +arrayvec = { workspace = true } +bitvec = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +fatality = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -sp-staking = { workspace = true } -sp-keystore = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } +indexmap = { workspace = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } 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-node-network-protocol = { workspace = true, default-features = true } -arrayvec = { workspace = true } -indexmap = { workspace = true } -codec = { features = ["derive"], workspace = true } +polkadot-primitives = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-staking = { workspace = true } thiserror = { workspace = true } -fatality = { workspace = true } -bitvec = { workspace = true, default-features = true } [dev-dependencies] -async-channel = { workspace = true } assert_matches = { workspace = true } +async-channel = { workspace = true } +futures-timer = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives = { workspace = true, features = ["test"] } +polkadot-primitives-test-helpers = { workspace = true } +polkadot-subsystem-bench = { workspace = true } +rand_chacha = { workspace = true, default-features = true } +rstest = { workspace = true } +sc-keystore = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } sp-authority-discovery = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -futures-timer = { workspace = true } -polkadot-primitives = { workspace = true, features = ["test"] } -polkadot-primitives-test-helpers = { workspace = true } -rand_chacha = { workspace = true, default-features = true } -polkadot-subsystem-bench = { workspace = true } [[bench]] name = "statement-distribution-regression-bench" diff --git a/polkadot/node/network/statement-distribution/src/error.rs b/polkadot/node/network/statement-distribution/src/error.rs index d7f52162fe23..cff9afbf8667 100644 --- a/polkadot/node/network/statement-distribution/src/error.rs +++ b/polkadot/node/network/statement-distribution/src/error.rs @@ -72,9 +72,6 @@ pub enum Error { #[error("Fetching session info failed {0:?}")] FetchSessionInfo(RuntimeApiError), - #[error("Fetching availability cores failed {0:?}")] - FetchAvailabilityCores(RuntimeApiError), - #[error("Fetching disabled validators failed {0:?}")] FetchDisabledValidators(runtime::Error), @@ -82,7 +79,7 @@ pub enum Error { FetchValidatorGroups(RuntimeApiError), #[error("Fetching claim queue failed {0:?}")] - FetchClaimQueue(runtime::Error), + FetchClaimQueue(RuntimeApiError), #[error("Attempted to share statement when not a validator or not assigned")] InvalidShare, diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index c79ae3953ad9..6bb49e5de13d 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -46,12 +46,15 @@ use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator, runtime::{ - fetch_claim_queue, request_min_backing_votes, ClaimQueueSnapshot, ProspectiveParachainsMode, + request_min_backing_votes, request_node_features, ClaimQueueSnapshot, + ProspectiveParachainsMode, }, }; use polkadot_primitives::{ - vstaging::CoreState, AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, - GroupIndex, GroupRotationInfo, Hash, Id as ParaId, IndexedVec, SessionIndex, SessionInfo, + node_features::FeatureIndex, + vstaging::{transpose_claim_queue, CandidateDescriptorVersion, TransposedClaimQueue}, + AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, SessionIndex, SessionInfo, SignedStatement, SigningContext, UncheckedSignedStatement, ValidatorId, ValidatorIndex, }; @@ -137,6 +140,12 @@ const COST_UNREQUESTED_RESPONSE_STATEMENT: Rep = Rep::CostMajor("Un-requested Statement In Response"); const COST_INACCURATE_ADVERTISEMENT: Rep = Rep::CostMajor("Peer advertised a candidate inaccurately"); +const COST_UNSUPPORTED_DESCRIPTOR_VERSION: Rep = + Rep::CostMajor("Candidate Descriptor version is not supported"); +const COST_INVALID_CORE_INDEX: Rep = + Rep::CostMajor("Candidate Descriptor contains an invalid core index"); +const COST_INVALID_SESSION_INDEX: Rep = + Rep::CostMajor("Candidate Descriptor contains an invalid session index"); const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Peer sent unparsable request"); const COST_INVALID_REQUEST_BITFIELD_SIZE: Rep = @@ -156,6 +165,7 @@ struct PerRelayParentState { statement_store: StatementStore, seconding_limit: usize, session: SessionIndex, + transposed_cq: TransposedClaimQueue, groups_per_para: HashMap>, disabled_validators: HashSet, } @@ -219,10 +229,17 @@ struct PerSessionState { // getting the topology from the gossip-support subsystem grid_view: Option, local_validator: Option, + // `true` if v2 candidate receipts are allowed by the runtime + allow_v2_descriptors: bool, } impl PerSessionState { - fn new(session_info: SessionInfo, keystore: &KeystorePtr, backing_threshold: u32) -> Self { + fn new( + session_info: SessionInfo, + keystore: &KeystorePtr, + backing_threshold: u32, + allow_v2_descriptors: bool, + ) -> Self { let groups = Groups::new(session_info.validator_groups.clone(), backing_threshold); let mut authority_lookup = HashMap::new(); for (i, ad) in session_info.discovery_keys.iter().cloned().enumerate() { @@ -235,7 +252,14 @@ impl PerSessionState { ) .map(|(_, index)| LocalValidatorIndex::Active(index)); - PerSessionState { session_info, groups, authority_lookup, grid_view: None, local_validator } + PerSessionState { + session_info, + groups, + authority_lookup, + grid_view: None, + local_validator, + allow_v2_descriptors, + } } fn supply_topology( @@ -271,6 +295,11 @@ impl PerSessionState { fn is_not_validator(&self) -> bool { self.grid_view.is_some() && self.local_validator.is_none() } + + /// Returns `true` if v2 candidate receipts are enabled + fn candidate_receipt_v2_enabled(&self) -> bool { + self.allow_v2_descriptors + } } pub(crate) struct State { @@ -615,8 +644,18 @@ pub(crate) async fn handle_active_leaves_update( let minimum_backing_votes = request_min_backing_votes(new_relay_parent, session_index, ctx.sender()).await?; - let mut per_session_state = - PerSessionState::new(session_info, &state.keystore, minimum_backing_votes); + let node_features = + request_node_features(new_relay_parent, session_index, ctx.sender()).await?; + let mut per_session_state = PerSessionState::new( + session_info, + &state.keystore, + minimum_backing_votes, + node_features + .unwrap_or(NodeFeatures::EMPTY) + .get(FeatureIndex::CandidateReceiptV2 as usize) + .map(|b| *b) + .unwrap_or(false), + ); if let Some(topology) = state.unused_topologies.remove(&session_index) { per_session_state.supply_topology(&topology.topology, topology.local_index); } @@ -642,18 +681,6 @@ pub(crate) async fn handle_active_leaves_update( continue } - // New leaf: fetch info from runtime API and initialize - // `per_relay_parent`. - - let availability_cores = polkadot_node_subsystem_util::request_availability_cores( - new_relay_parent, - ctx.sender(), - ) - .await - .await - .map_err(JfyiError::RuntimeApiUnavailable)? - .map_err(JfyiError::FetchAvailabilityCores)?; - let group_rotation_info = polkadot_node_subsystem_util::request_validator_groups(new_relay_parent, ctx.sender()) .await @@ -662,23 +689,22 @@ pub(crate) async fn handle_active_leaves_update( .map_err(JfyiError::FetchValidatorGroups)? .1; - let maybe_claim_queue = fetch_claim_queue(ctx.sender(), new_relay_parent) - .await - .unwrap_or_else(|err| { - gum::debug!(target: LOG_TARGET, ?new_relay_parent, ?err, "handle_active_leaves_update: `claim_queue` API not available"); - None - }); + let claim_queue = ClaimQueueSnapshot( + polkadot_node_subsystem_util::request_claim_queue(new_relay_parent, ctx.sender()) + .await + .await + .map_err(JfyiError::RuntimeApiUnavailable)? + .map_err(JfyiError::FetchClaimQueue)?, + ); let local_validator = per_session.local_validator.and_then(|v| { if let LocalValidatorIndex::Active(idx) = v { find_active_validator_state( idx, &per_session.groups, - &availability_cores, &group_rotation_info, - &maybe_claim_queue, + &claim_queue, seconding_limit, - max_candidate_depth, ) } else { Some(LocalValidatorState { grid_tracker: GridTracker::default(), active: None }) @@ -686,13 +712,14 @@ pub(crate) async fn handle_active_leaves_update( }); let groups_per_para = determine_groups_per_para( - availability_cores, + per_session.groups.all().len(), group_rotation_info, - &maybe_claim_queue, - max_candidate_depth, + &claim_queue, ) .await; + let transposed_cq = transpose_claim_queue(claim_queue.0); + state.per_relay_parent.insert( new_relay_parent, PerRelayParentState { @@ -702,6 +729,7 @@ pub(crate) async fn handle_active_leaves_update( session: session_index, groups_per_para, disabled_validators, + transposed_cq, }, ); } @@ -741,11 +769,9 @@ pub(crate) async fn handle_active_leaves_update( fn find_active_validator_state( validator_index: ValidatorIndex, groups: &Groups, - availability_cores: &[CoreState], group_rotation_info: &GroupRotationInfo, - maybe_claim_queue: &Option, + claim_queue: &ClaimQueueSnapshot, seconding_limit: usize, - max_candidate_depth: usize, ) -> Option { if groups.all().is_empty() { return None @@ -753,23 +779,8 @@ fn find_active_validator_state( let our_group = groups.by_validator_index(validator_index)?; - let core_index = group_rotation_info.core_for_group(our_group, availability_cores.len()); - let paras_assigned_to_core = if let Some(claim_queue) = maybe_claim_queue { - claim_queue.iter_claims_for_core(&core_index).copied().collect() - } else { - availability_cores - .get(core_index.0 as usize) - .and_then(|core_state| match core_state { - CoreState::Scheduled(scheduled_core) => Some(scheduled_core.para_id), - CoreState::Occupied(occupied_core) if max_candidate_depth >= 1 => occupied_core - .next_up_on_available - .as_ref() - .map(|scheduled_core| scheduled_core.para_id), - CoreState::Free | CoreState::Occupied(_) => None, - }) - .into_iter() - .collect() - }; + let core_index = group_rotation_info.core_for_group(our_group, groups.all().len()); + let paras_assigned_to_core = claim_queue.iter_claims_for_core(&core_index).copied().collect(); let group_validators = groups.get(our_group)?.to_owned(); Some(LocalValidatorState { @@ -2174,39 +2185,16 @@ async fn provide_candidate_to_grid( // Utility function to populate per relay parent `ParaId` to `GroupIndex` mappings. async fn determine_groups_per_para( - availability_cores: Vec, + n_cores: usize, group_rotation_info: GroupRotationInfo, - maybe_claim_queue: &Option, - max_candidate_depth: usize, + claim_queue: &ClaimQueueSnapshot, ) -> HashMap> { - let n_cores = availability_cores.len(); - // Determine the core indices occupied by each para at the current relay parent. To support // on-demand parachains we also consider the core indices at next blocks. - let schedule: HashMap> = if let Some(claim_queue) = maybe_claim_queue { - claim_queue - .iter_all_claims() - .map(|(core_index, paras)| (*core_index, paras.iter().copied().collect())) - .collect() - } else { - availability_cores - .into_iter() - .enumerate() - .filter_map(|(index, core)| match core { - CoreState::Scheduled(scheduled_core) => - Some((CoreIndex(index as u32), vec![scheduled_core.para_id])), - CoreState::Occupied(occupied_core) => - if max_candidate_depth >= 1 { - occupied_core.next_up_on_available.map(|scheduled_core| { - (CoreIndex(index as u32), vec![scheduled_core.para_id]) - }) - } else { - None - }, - CoreState::Free => None, - }) - .collect() - }; + let schedule: HashMap> = claim_queue + .iter_all_claims() + .map(|(core_index, paras)| (*core_index, paras.iter().copied().collect())) + .collect(); let mut groups_per_para = HashMap::new(); // Map from `CoreIndex` to `GroupIndex` and collect as `HashMap`. @@ -3106,11 +3094,12 @@ pub(crate) async fn handle_response( ) { let &requests::CandidateIdentifier { relay_parent, candidate_hash, group_index } = response.candidate_identifier(); + let peer = *response.requested_peer(); gum::trace!( target: LOG_TARGET, ?candidate_hash, - peer = ?response.requested_peer(), + ?peer, "Received response", ); @@ -3145,6 +3134,8 @@ pub(crate) async fn handle_response( expected_groups.iter().any(|g| g == &g_index) }, disabled_mask, + &relay_parent_state.transposed_cq, + per_session.candidate_receipt_v2_enabled(), ); for (peer, rep) in res.reputation_changes { diff --git a/polkadot/node/network/statement-distribution/src/v2/requests.rs b/polkadot/node/network/statement-distribution/src/v2/requests.rs index 74f29710956f..3b46922c2297 100644 --- a/polkadot/node/network/statement-distribution/src/v2/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/requests.rs @@ -30,9 +30,11 @@ //! (which requires state not owned by the request manager). use super::{ - seconded_and_sufficient, BENEFIT_VALID_RESPONSE, BENEFIT_VALID_STATEMENT, - COST_IMPROPERLY_DECODED_RESPONSE, COST_INVALID_RESPONSE, COST_INVALID_SIGNATURE, - COST_UNREQUESTED_RESPONSE_STATEMENT, REQUEST_RETRY_DELAY, + seconded_and_sufficient, CandidateDescriptorVersion, TransposedClaimQueue, + BENEFIT_VALID_RESPONSE, BENEFIT_VALID_STATEMENT, COST_IMPROPERLY_DECODED_RESPONSE, + COST_INVALID_CORE_INDEX, COST_INVALID_RESPONSE, COST_INVALID_SESSION_INDEX, + COST_INVALID_SIGNATURE, COST_UNREQUESTED_RESPONSE_STATEMENT, + COST_UNSUPPORTED_DESCRIPTOR_VERSION, REQUEST_RETRY_DELAY, }; use crate::LOG_TARGET; @@ -566,6 +568,8 @@ impl UnhandledResponse { validator_key_lookup: impl Fn(ValidatorIndex) -> Option, allowed_para_lookup: impl Fn(ParaId, GroupIndex) -> bool, disabled_mask: BitVec, + transposed_cq: &TransposedClaimQueue, + allow_v2_descriptors: bool, ) -> ResponseValidationOutput { let UnhandledResponse { response: TaggedResponse { identifier, requested_peer, props, response }, @@ -650,6 +654,8 @@ impl UnhandledResponse { validator_key_lookup, allowed_para_lookup, disabled_mask, + transposed_cq, + allow_v2_descriptors, ); if let CandidateRequestStatus::Complete { .. } = output.request_status { @@ -670,6 +676,8 @@ fn validate_complete_response( validator_key_lookup: impl Fn(ValidatorIndex) -> Option, allowed_para_lookup: impl Fn(ParaId, GroupIndex) -> bool, disabled_mask: BitVec, + transposed_cq: &TransposedClaimQueue, + allow_v2_descriptors: bool, ) -> ResponseValidationOutput { let RequestProperties { backing_threshold, mut unwanted_mask } = props; @@ -687,39 +695,83 @@ fn validate_complete_response( unwanted_mask.validated_in_group.resize(group.len(), true); } - let invalid_candidate_output = || ResponseValidationOutput { + let invalid_candidate_output = |cost: Rep| ResponseValidationOutput { request_status: CandidateRequestStatus::Incomplete, - reputation_changes: vec![(requested_peer, COST_INVALID_RESPONSE)], + reputation_changes: vec![(requested_peer, cost)], requested_peer, }; + let mut rep_changes = Vec::new(); + // sanity-check candidate response. // note: roughly ascending cost of operations { if response.candidate_receipt.descriptor.relay_parent() != identifier.relay_parent { - return invalid_candidate_output() + return invalid_candidate_output(COST_INVALID_RESPONSE) } if response.candidate_receipt.descriptor.persisted_validation_data_hash() != response.persisted_validation_data.hash() { - return invalid_candidate_output() + return invalid_candidate_output(COST_INVALID_RESPONSE) } if !allowed_para_lookup( response.candidate_receipt.descriptor.para_id(), identifier.group_index, ) { - return invalid_candidate_output() + return invalid_candidate_output(COST_INVALID_RESPONSE) } if response.candidate_receipt.hash() != identifier.candidate_hash { - return invalid_candidate_output() + return invalid_candidate_output(COST_INVALID_RESPONSE) + } + + let candidate_hash = response.candidate_receipt.hash(); + + // V2 descriptors are invalid if not enabled by runtime. + if !allow_v2_descriptors && + response.candidate_receipt.descriptor.version() == CandidateDescriptorVersion::V2 + { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + peer = ?requested_peer, + "Version 2 candidate receipts are not enabled by the runtime" + ); + return invalid_candidate_output(COST_UNSUPPORTED_DESCRIPTOR_VERSION) + } + // Validate the core index. + if let Err(err) = response.candidate_receipt.check_core_index(transposed_cq) { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + ?err, + peer = ?requested_peer, + "Received candidate has invalid core index" + ); + return invalid_candidate_output(COST_INVALID_CORE_INDEX) + } + + // Check if `session_index` of relay parent matches candidate descriptor + // `session_index`. + if let Some(candidate_session_index) = response.candidate_receipt.descriptor.session_index() + { + if candidate_session_index != session { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + peer = ?requested_peer, + session_index = session, + candidate_session_index, + "Received candidate has invalid session index" + ); + return invalid_candidate_output(COST_INVALID_SESSION_INDEX) + } } } // statement checks. - let mut rep_changes = Vec::new(); let statements = { let mut statements = Vec::with_capacity(std::cmp::min(response.statements.len(), group.len() * 2)); @@ -815,7 +867,7 @@ fn validate_complete_response( // Only accept responses which are sufficient, according to our // required backing threshold. if !seconded_and_sufficient(&received_filter, backing_threshold) { - return invalid_candidate_output() + return invalid_candidate_output(COST_INVALID_RESPONSE) } statements @@ -1091,6 +1143,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask.clone(), + &Default::default(), + false, ); assert_eq!( output, @@ -1130,6 +1184,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask, + &Default::default(), + false, ); assert_eq!( output, @@ -1214,6 +1270,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask, + &Default::default(), + false, ); assert_eq!( output, @@ -1296,6 +1354,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask, + &Default::default(), + false, ); assert_eq!( output, @@ -1434,6 +1494,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask.clone(), + &Default::default(), + false, ); // First request served successfully diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs index fe51f953e244..040123f1774c 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -25,6 +25,7 @@ fn share_seconded_circulated_to_cluster() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -125,6 +126,7 @@ fn cluster_valid_statement_before_seconded_ignored() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -185,6 +187,7 @@ fn cluster_statement_bad_signature() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -258,6 +261,7 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -320,6 +324,7 @@ fn elastic_scaling_useful_cluster_statement_from_non_cluster_peer_rejected() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -379,6 +384,7 @@ fn statement_from_non_cluster_originator_unexpected() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -434,6 +440,7 @@ fn seconded_statement_leads_to_request() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -522,6 +529,7 @@ fn cluster_statements_shared_seconded_first() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -636,6 +644,7 @@ fn cluster_accounts_for_implicit_view() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -772,6 +781,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -895,6 +905,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1031,6 +1042,7 @@ fn ensure_seconding_limit_is_respected() { max_candidate_depth: 1, allowed_ancestry_len: 3, }), + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index d2bf031368c1..0133d9e219f6 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -31,6 +31,7 @@ fn backed_candidate_leads_to_advertisement() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -240,6 +241,7 @@ fn received_advertisement_before_confirmation_leads_to_request() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -412,6 +414,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; test_harness(config, |state, mut overseer| async move { @@ -593,6 +596,7 @@ fn receive_ack_for_unconfirmed_candidate() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; test_harness(config, |state, mut overseer| async move { @@ -654,6 +658,7 @@ fn received_acknowledgements_for_locally_confirmed() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; test_harness(config, |state, mut overseer| async move { @@ -816,6 +821,7 @@ fn received_acknowledgements_for_externally_confirmed() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; test_harness(config, |state, mut overseer| async move { @@ -951,6 +957,7 @@ fn received_advertisement_after_confirmation_before_backing() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1129,6 +1136,7 @@ fn additional_statements_are_shared_after_manifest_exchange() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1416,6 +1424,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1629,6 +1638,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1840,6 +1850,7 @@ fn inner_grid_statements_imported_to_backing(groups_for_first_para: usize) { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2048,6 +2059,7 @@ fn advertisements_rejected_from_incorrect_peers() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2184,6 +2196,7 @@ fn manifest_rejected_with_unknown_relay_parent() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2281,6 +2294,7 @@ fn manifest_rejected_when_not_a_validator() { group_size, local_validator: LocalRole::None, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2374,6 +2388,7 @@ fn manifest_rejected_when_group_does_not_match_para() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2472,6 +2487,7 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2662,6 +2678,7 @@ fn inactive_local_participates_in_grid() { group_size, local_validator: LocalRole::InactiveValidator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs index 9f2c36ad1018..46b72f5adac9 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs @@ -33,9 +33,9 @@ use polkadot_node_subsystem::messages::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ - vstaging::{CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState}, - AssignmentPair, AsyncBackingParams, Block, BlockNumber, GroupRotationInfo, HeadData, Header, - IndexedVec, PersistedValidationData, ScheduledCore, SessionIndex, SessionInfo, ValidatorPair, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, AssignmentPair, + AsyncBackingParams, Block, BlockNumber, GroupRotationInfo, HeadData, Header, IndexedVec, + PersistedValidationData, SessionIndex, SessionInfo, ValidatorPair, }; use sc_keystore::LocalKeystore; use sc_network::ProtocolName; @@ -82,6 +82,8 @@ struct TestConfig { // whether the local node should be a validator local_validator: LocalRole, async_backing_params: Option, + // allow v2 descriptors (feature bit) + allow_v2_descriptors: bool, } #[derive(Debug, Clone)] @@ -96,6 +98,7 @@ struct TestState { validators: Vec, session_info: SessionInfo, req_sender: async_channel::Sender, + node_features: NodeFeatures, } impl TestState { @@ -174,7 +177,13 @@ impl TestState { random_seed: [0u8; 32], }; - TestState { config, local, validators, session_info, req_sender } + let mut node_features = NodeFeatures::new(); + if config.allow_v2_descriptors { + node_features.resize(FeatureIndex::FirstUnassigned as usize, false); + node_features.set(FeatureIndex::CandidateReceiptV2 as usize, true); + } + + TestState { config, local, validators, session_info, req_sender, node_features } } fn make_dummy_leaf(&self, relay_parent: Hash) -> TestLeaf { @@ -186,20 +195,23 @@ impl TestState { relay_parent: Hash, groups_for_first_para: usize, ) -> TestLeaf { + let mut cq = std::collections::BTreeMap::new(); + + for i in 0..self.session_info.validator_groups.len() { + if i < groups_for_first_para { + cq.entry(CoreIndex(i as u32)) + .or_insert_with(|| vec![ParaId::from(0u32), ParaId::from(0u32)].into()); + } else { + cq.entry(CoreIndex(i as u32)) + .or_insert_with(|| vec![ParaId::from(i), ParaId::from(i)].into()); + }; + } + TestLeaf { number: 1, hash: relay_parent, parent_hash: Hash::repeat_byte(0), session: 1, - availability_cores: self.make_availability_cores(|i| { - let para_id = if i < groups_for_first_para { - ParaId::from(0u32) - } else { - ParaId::from(i as u32) - }; - - CoreState::Scheduled(ScheduledCore { para_id, collator: None }) - }), disabled_validators: Default::default(), para_data: (0..self.session_info.validator_groups.len()) .map(|i| { @@ -213,6 +225,7 @@ impl TestState { }) .collect(), minimum_backing_votes: 2, + claim_queue: ClaimQueueSnapshot(cq), } } @@ -232,10 +245,6 @@ impl TestState { TestLeaf { minimum_backing_votes, ..self.make_dummy_leaf(relay_parent) } } - fn make_availability_cores(&self, f: impl Fn(usize) -> CoreState) -> Vec { - (0..self.session_info.validator_groups.len()).map(f).collect() - } - fn make_dummy_topology(&self) -> NewGossipTopology { let validator_count = self.config.validator_count; let is_local_inactive = matches!(self.config.local_validator, LocalRole::InactiveValidator); @@ -423,10 +432,10 @@ struct TestLeaf { hash: Hash, parent_hash: Hash, session: SessionIndex, - availability_cores: Vec, pub disabled_validators: Vec, para_data: Vec<(ParaId, PerParaData)>, minimum_backing_votes: u32, + claim_queue: ClaimQueueSnapshot, } impl TestLeaf { @@ -574,9 +583,9 @@ async fn handle_leaf_activation( parent_hash, para_data, session, - availability_cores, disabled_validators, minimum_backing_votes, + claim_queue, } = leaf; assert_matches!( @@ -623,7 +632,7 @@ async fn handle_leaf_activation( _parent, RuntimeApiRequest::Version(tx), )) => { - tx.send(Ok(RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT)).unwrap(); + tx.send(Ok(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)).unwrap(); }, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, @@ -657,12 +666,6 @@ async fn handle_leaf_activation( assert!(is_new_session, "only expecting this call in a new session"); tx.send(Ok(*minimum_backing_votes)).unwrap(); }, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - parent, - RuntimeApiRequest::AvailabilityCores(tx), - )) if parent == *hash => { - tx.send(Ok(availability_cores.clone())).unwrap(); - }, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, RuntimeApiRequest::ValidatorGroups(tx), @@ -675,6 +678,18 @@ async fn handle_leaf_activation( }; tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::NodeFeatures(_session_index, tx), + )) if parent == *hash => { + tx.send(Ok(test_state.node_features.clone())).unwrap(); + }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + parent, + RuntimeApiRequest::ClaimQueue(tx), + )) if parent == *hash => { + tx.send(Ok(claim_queue.0.clone())).unwrap(); + }, AllMessages::ProspectiveParachains( ProspectiveParachainsMessage::GetHypotheticalMembership(req, tx), ) => { diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs index dcb90bacdcde..fc880c1d9a83 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs @@ -21,19 +21,25 @@ use codec::{Decode, Encode}; use polkadot_node_network_protocol::{ request_response::v2 as request_v2, v2::BackedCandidateManifest, }; -use polkadot_primitives_test_helpers::make_candidate; +use polkadot_primitives_test_helpers::{make_candidate, make_candidate_v2}; use sc_network::config::{ IncomingRequest as RawIncomingRequest, OutgoingResponse as RawOutgoingResponse, }; -#[test] -fn cluster_peer_allowed_to_send_incomplete_statements() { +use polkadot_primitives::vstaging::MutateDescriptorV2; +use rstest::rstest; + +#[rstest] +#[case(false)] +#[case(true)] +fn cluster_peer_allowed_to_send_incomplete_statements(#[case] allow_v2_descriptors: bool) { let group_size = 3; let config = TestConfig { validator_count: 20, group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors, }; let relay_parent = Hash::repeat_byte(1); @@ -48,14 +54,28 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { let test_leaf = state.make_dummy_leaf(relay_parent); - let (candidate, pvd) = make_candidate( - relay_parent, - 1, - local_para, - test_leaf.para_data(local_para).head_data.clone(), - vec![4, 5, 6].into(), - Hash::repeat_byte(42).into(), - ); + let (candidate, pvd) = if allow_v2_descriptors { + let (mut candidate, pvd) = make_candidate_v2( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + candidate.descriptor.set_core_index(CoreIndex(local_group_index.0)); + (candidate, pvd) + } else { + make_candidate( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ) + }; + let candidate_hash = candidate.hash(); let other_group_validators = state.group_validators(local_group_index, true); @@ -187,6 +207,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { max_candidate_depth: 1, allowed_ancestry_len: 3, }), + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -462,6 +483,7 @@ fn peer_reported_for_not_enough_statements() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -649,6 +671,7 @@ fn peer_reported_for_duplicate_statements() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -802,6 +825,7 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -925,6 +949,415 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { }); } +#[test] +fn peer_reported_for_invalid_v2_descriptor() { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: LocalRole::Validator, + async_backing_params: None, + allow_v2_descriptors: true, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (mut candidate, pvd) = make_candidate_v2( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + + candidate.descriptor.set_core_index(CoreIndex(100)); + + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_group_index, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + let v_c = other_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true, vec![]).await; + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include a candidate with invalid core + // index. + { + let b_seconded_invalid = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded_invalid.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_INVALID_CORE_INDEX.into() => { } + ); + } + + // Test invalid session index + candidate.descriptor.set_session_index(100); + // Set good core index + candidate.descriptor.set_core_index(CoreIndex(local_group_index.0)); + + let candidate_hash = candidate.hash(); + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include a candidate with invalid session + // index. + { + let b_seconded_invalid = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded_invalid.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_INVALID_SESSION_INDEX.into() => { } + ); + } + + // Test valid candidate does not lead to punishment + candidate.descriptor.set_session_index(1); + + let candidate_hash = candidate.hash(); + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include a valid candidate. + { + let b_seconded_invalid = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded_invalid.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT.into() => { } + ); + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } + ); + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V2(protocol_v2::ValidationProtocol::StatementDistribution( + protocol_v2::StatementDistributionMessage::Statement( + r, + s, + ) + )) + )) => { + assert_eq!(peers, vec![peer_a.clone()]); + assert_eq!(r, relay_parent); + assert_eq!(s.unchecked_payload(), &CompactStatement::Seconded(candidate_hash)); + assert_eq!(s.unchecked_validator_index(), v_c); + } + ); + + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; + } + overseer + }); +} + +#[rstest] +#[case(false)] +#[case(true)] +// Test if v2 descriptors are filtered and peers punished if the node feature is disabled. +// Also test if the peer is rewarded for providing v2 descriptor if the node feature is enabled. +fn v2_descriptors_filtered(#[case] allow_v2_descriptors: bool) { + let group_size = 3; + let config = TestConfig { + validator_count: 20, + group_size, + local_validator: LocalRole::Validator, + async_backing_params: None, + allow_v2_descriptors, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + let peer_b = PeerId::random(); + let peer_c = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let local_validator = state.local.clone().unwrap(); + let local_group_index = local_validator.group_index.unwrap(); + let local_para = ParaId::from(local_group_index.0); + + let test_leaf = state.make_dummy_leaf(relay_parent); + + let (mut candidate, pvd) = make_candidate_v2( + relay_parent, + 1, + local_para, + test_leaf.para_data(local_para).head_data.clone(), + vec![4, 5, 6].into(), + Hash::repeat_byte(42).into(), + ); + + // Makes the candidate invalid. + candidate.descriptor.set_core_index(CoreIndex(100)); + + let candidate_hash = candidate.hash(); + + let other_group_validators = state.group_validators(local_group_index, true); + let v_a = other_group_validators[0]; + let v_b = other_group_validators[1]; + + // peer A is in group, has relay parent in view. + // peer B is in group, has no relay parent in view. + // peer C is not in group, has relay parent in view. + { + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(other_group_validators[0])].into_iter().collect()), + ) + .await; + + connect_peer( + &mut overseer, + peer_b.clone(), + Some(vec![state.discovery_id(other_group_validators[1])].into_iter().collect()), + ) + .await; + + connect_peer(&mut overseer, peer_c.clone(), None).await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await; + } + + activate_leaf(&mut overseer, &test_leaf, &state, true, vec![]).await; + + // Peer in cluster sends a statement, triggering a request. + { + let a_seconded = state + .sign_statement( + v_a, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, a_seconded), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == BENEFIT_VALID_STATEMENT_FIRST.into() => { } + ); + } + + // Send a request to peer and mock its response to include a candidate with invalid core + // index. + { + let b_seconded_invalid = state + .sign_statement( + v_b, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + let statements = vec![b_seconded_invalid.clone()]; + + handle_sent_request( + &mut overseer, + peer_a, + candidate_hash, + StatementFilter::blank(group_size), + candidate.clone(), + pvd.clone(), + statements, + ) + .await; + + let expected_rep_change = if allow_v2_descriptors { + COST_INVALID_CORE_INDEX.into() + } else { + COST_UNSUPPORTED_DESCRIPTOR_VERSION.into() + }; + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == expected_rep_change => { } + ); + } + + overseer + }); +} #[test] fn peer_reported_for_providing_statements_with_wrong_validator_id() { let group_size = 3; @@ -933,6 +1366,7 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1063,6 +1497,7 @@ fn disabled_validators_added_to_unwanted_mask() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1229,6 +1664,7 @@ fn disabling_works_from_relay_parent_not_the_latest_state() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_1 = Hash::repeat_byte(1); @@ -1428,6 +1864,7 @@ fn local_node_sanity_checks_incoming_requests() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1629,6 +2066,7 @@ fn local_node_checks_that_peer_can_request_before_responding() { group_size: 3, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -1828,6 +2266,7 @@ fn local_node_respects_statement_mask() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); @@ -2070,6 +2509,7 @@ fn should_delay_before_retrying_dropped_requests() { group_size, local_validator: LocalRole::Validator, async_backing_params: None, + allow_v2_descriptors: false, }; let relay_parent = Hash::repeat_byte(1); diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 2253a5ae0c66..fd7f1e039247 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -5,35 +5,37 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "System overseer of the Polkadot node" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -sc-client-api = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } +async-trait = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } +gum = { workspace = true, default-features = true } +orchestra = { features = ["futures_channel"], workspace = true } parking_lot = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem-types = { workspace = true, default-features = true } -polkadot-node-metrics = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -orchestra = { features = ["futures_channel"], workspace = true } -gum = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -async-trait = { workspace = true } tikv-jemalloc-ctl = { optional = true, workspace = true } [dev-dependencies] -metered = { features = ["futures_channel"], workspace = true } -sp-core = { workspace = true, default-features = true } -futures = { features = ["thread-pool"], workspace = true } -femme = { workspace = true } assert_matches = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } +femme = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } +metered = { features = ["futures_channel"], workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true } +sp-core = { workspace = true, default-features = true } [target.'cfg(target_os = "linux")'.dependencies] tikv-jemalloc-ctl = "0.5.0" diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index e1b2af733b47..f2cf60280b72 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -83,7 +83,7 @@ impl Subsystem1 { candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), - exec_kind: PvfExecKind::Backing, + exec_kind: PvfExecKind::Backing(dummy_hash()), response_sender: tx, }; ctx.send_message(msg).await; diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 87ef63d8a5d7..3881ddbcc904 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -468,6 +468,7 @@ pub async fn forward_events>(client: Arc

, mut hand )] pub struct Overseer { #[subsystem(CandidateValidationMessage, sends: [ + ChainApiMessage, RuntimeApiMessage, ])] candidate_validation: CandidateValidation, diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index c3c47335cd3e..0b9b783ef9b1 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -111,7 +111,7 @@ where candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), - exec_kind: PvfExecKind::Backing, + exec_kind: PvfExecKind::Backing(dummy_hash()), response_sender: tx, }) .await; @@ -811,7 +811,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { candidate_receipt, pov, executor_params: Default::default(), - exec_kind: PvfExecKind::Backing, + exec_kind: PvfExecKind::Backing(dummy_hash()), response_sender, } } diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index 7185205f905b..d138b77dea8f 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -5,29 +5,31 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +bitvec = { features = ["alloc"], workspace = true } bounded-vec = { workspace = true } +codec = { features = ["derive"], workspace = true } futures = { workspace = true } futures-timer = { workspace = true } +polkadot-parachain-primitives = { workspace = true } polkadot-primitives = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true } -sp-core = { workspace = true, default-features = true } +sc-keystore = { workspace = true } +schnorrkel = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } sp-consensus-slots = { workspace = true } +sp-core = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-maybe-compressed-blob = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true } -schnorrkel = { workspace = true, default-features = true } thiserror = { workspace = true } -bitvec = { features = ["alloc"], workspace = true } -serde = { features = ["derive"], workspace = true, default-features = true } -sc-keystore = { workspace = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] zstd = { version = "0.12.4", default-features = false } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 6985e86098b0..1e5ce6489bc8 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.16.1"; +pub const NODE_VERSION: &'static str = "1.17.0"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 3edb3f4dadbe..122040a9b207 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -6,104 +6,106 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Utils to tie different Polkadot components together and allow instantiation of a node." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] # Substrate Client -sc-authority-discovery = { workspace = true, default-features = true } -sc-consensus-babe = { workspace = true, default-features = true } -sc-consensus-beefy = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true, default-features = true } mmr-gadget = { workspace = true, default-features = true } -sp-mmr-primitives = { workspace = true, default-features = true } -sp-genesis-builder = { workspace = true, default-features = true } +sc-authority-discovery = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-beefy = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-slots = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } -sc-transaction-pool = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } -sc-sync-state-rpc = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -sc-basic-authorship = { workspace = true, default-features = true } sc-offchain = { workspace = true, default-features = true } -sc-sysinfo = { workspace = true, default-features = true } sc-service = { workspace = true } +sc-sync-state-rpc = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } +sp-mmr-primitives = { workspace = true, default-features = true } # Substrate Primitives +pallet-transaction-payment = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } sp-authority-discovery = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } sp-consensus-beefy = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } -sp-inherents = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } -sp-block-builder = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-offchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-session = { workspace = true, default-features = true } -sp-transaction-pool = { workspace = true, default-features = true } -pallet-transaction-payment = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } -sp-consensus-babe = { workspace = true, default-features = true } -sp-weights = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } +sp-weights = { workspace = true, default-features = true } # Substrate Pallets -pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } frame-metadata-hash-extension = { optional = true, workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } # Substrate Other +frame-benchmarking = { workspace = true, default-features = true } +frame-benchmarking-cli = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } -frame-benchmarking-cli = { workspace = true, default-features = true } -frame-benchmarking = { workspace = true, default-features = true } # External Crates async-trait = { workspace = true } +codec = { workspace = true, default-features = true } futures = { workspace = true } -is_executable = { workspace = true } gum = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -thiserror = { workspace = true } +is_executable = { workspace = true } kvdb = { workspace = true } kvdb-rocksdb = { optional = true, workspace = true } +log = { workspace = true, default-features = true } parity-db = { optional = true, workspace = true } -codec = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } # Polkadot polkadot-core-primitives = { workspace = true, default-features = true } polkadot-node-core-parachains-inherent = { workspace = true, default-features = true } -polkadot-overseer = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-rpc = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-node-subsystem-types = { 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-rpc = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } -polkadot-node-network-protocol = { workspace = true, default-features = true } # Polkadot Runtime Constants rococo-runtime-constants = { optional = true, workspace = true, default-features = true } westend-runtime-constants = { optional = true, workspace = true, default-features = true } # Polkadot Runtimes -westend-runtime = { optional = true, workspace = true } rococo-runtime = { optional = true, workspace = true } +westend-runtime = { optional = true, workspace = true } # Polkadot Subsystems polkadot-approval-distribution = { optional = true, workspace = true, default-features = true } @@ -135,12 +137,11 @@ xcm = { workspace = true, default-features = true } xcm-runtime-apis = { workspace = true, default-features = true } [dev-dependencies] -polkadot-test-client = { workspace = true } +assert_matches = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } +polkadot-test-client = { workspace = true } sp-tracing = { workspace = true } -assert_matches = { workspace = true } -serial_test = { workspace = true } tempfile = { workspace = true } [features] @@ -209,6 +210,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "westend-runtime?/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-system/try-runtime", diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index abba91a38a97..227bc5253994 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -80,7 +80,7 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; use prometheus_endpoint::Registry; #[cfg(feature = "full-node")] use sc_service::KeystoreContainer; -use sc_service::{build_polkadot_syncing_strategy, RpcHandlers, SpawnTaskHandle}; +use sc_service::{RpcHandlers, SpawnTaskHandle}; use sc_telemetry::TelemetryWorker; #[cfg(feature = "full-node")] use sc_telemetry::{Telemetry, TelemetryWorkerHandle}; @@ -1003,17 +1003,7 @@ pub fn new_full< }) }; - let syncing_strategy = build_polkadot_syncing_strategy( - config.protocol_id(), - config.chain_spec.fork_id(), - &mut net_config, - Some(WarpSyncConfig::WithProvider(warp_sync)), - client.clone(), - &task_manager.spawn_handle(), - config.prometheus_config.as_ref().map(|config| &config.registry), - )?; - - let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, net_config, @@ -1022,7 +1012,7 @@ pub fn new_full< spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - syncing_strategy, + warp_sync_config: Some(WarpSyncConfig::WithProvider(warp_sync)), block_relay: None, metrics, })?; @@ -1393,8 +1383,6 @@ pub fn new_full< ); } - network_starter.start_network(); - Ok(NewFull { task_manager, client, diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 279b6ff80704..e4ea6efeaac2 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -210,7 +210,7 @@ pub fn validator_overseer_builder( AuthorityDiscoveryService, >, ChainApiSubsystem, - CollationGenerationSubsystem, + DummySubsystem, CollatorProtocolSubsystem, ApprovalDistributionSubsystem, ApprovalVotingSubsystem, @@ -237,6 +237,7 @@ where 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(), @@ -295,7 +296,7 @@ where )) .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)?)) + .collation_generation(DummySubsystem) .collator_protocol({ let side = match is_parachain_node { IsParachainNode::Collator(_) | IsParachainNode::FullNode => @@ -434,7 +435,7 @@ pub fn validator_with_parallel_overseer_builder( AuthorityDiscoveryService, >, ChainApiSubsystem, - CollationGenerationSubsystem, + DummySubsystem, CollatorProtocolSubsystem, DummySubsystem, DummySubsystem, @@ -519,7 +520,7 @@ where )) .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)?)) + .collation_generation(DummySubsystem) .collator_protocol({ let side = match is_parachain_node { IsParachainNode::Collator(_) | IsParachainNode::FullNode => diff --git a/polkadot/node/service/src/workers.rs b/polkadot/node/service/src/workers.rs index b35bb8302fdc..73c3aa466608 100644 --- a/polkadot/node/service/src/workers.rs +++ b/polkadot/node/service/src/workers.rs @@ -21,19 +21,20 @@ use is_executable::IsExecutable; use std::path::PathBuf; #[cfg(test)] -use std::sync::{Mutex, OnceLock}; +thread_local! { + static TMP_DIR: std::cell::RefCell> = std::cell::RefCell::new(None); +} /// Override the workers polkadot binary directory path, used for testing. #[cfg(test)] -fn workers_exe_path_override() -> &'static Mutex> { - static OVERRIDE: OnceLock>> = OnceLock::new(); - OVERRIDE.get_or_init(|| Mutex::new(None)) +fn workers_exe_path_override() -> Option { + TMP_DIR.with_borrow(|t| t.as_ref().map(|t| t.path().join("usr/bin"))) } + /// Override the workers lib directory path, used for testing. #[cfg(test)] -fn workers_lib_path_override() -> &'static Mutex> { - static OVERRIDE: OnceLock>> = OnceLock::new(); - OVERRIDE.get_or_init(|| Mutex::new(None)) +fn workers_lib_path_override() -> Option { + TMP_DIR.with_borrow(|t| t.as_ref().map(|t| t.path().join("usr/lib/polkadot"))) } /// Determines the final set of paths to use for the PVF workers. @@ -147,12 +148,9 @@ fn list_workers_paths( // Consider the /usr/lib/polkadot/ directory. { - #[allow(unused_mut)] - let mut lib_path = PathBuf::from("/usr/lib/polkadot"); + let lib_path = PathBuf::from("/usr/lib/polkadot"); #[cfg(test)] - if let Some(ref path_override) = *workers_lib_path_override().lock().unwrap() { - lib_path = path_override.clone(); - } + let lib_path = if let Some(o) = workers_lib_path_override() { o } else { lib_path }; let (prep_worker, exec_worker) = build_worker_paths(lib_path, workers_names); @@ -175,9 +173,10 @@ fn get_exe_path() -> Result { let mut exe_path = std::env::current_exe()?; let _ = exe_path.pop(); // executable file will always have a parent directory. #[cfg(test)] - if let Some(ref path_override) = *workers_exe_path_override().lock().unwrap() { - exe_path = path_override.clone(); + if let Some(o) = workers_exe_path_override() { + exe_path = o; } + Ok(exe_path) } @@ -205,8 +204,7 @@ mod tests { use super::*; use assert_matches::assert_matches; - use serial_test::serial; - use std::{env::temp_dir, fs, os::unix::fs::PermissionsExt, path::Path}; + use std::{fs, os::unix::fs::PermissionsExt, path::Path}; const TEST_NODE_VERSION: &'static str = "v0.1.2"; @@ -228,7 +226,7 @@ mod tests { fn get_program(version: &str) -> String { format!( - "#!/bin/bash + "#!/usr/bin/env bash if [[ $# -ne 1 ]] ; then echo \"unexpected number of arguments: $#\" @@ -253,27 +251,21 @@ echo {} ) -> Result<(), Box> { // Set up /usr/lib/polkadot and /usr/bin, both empty. - let tempdir = temp_dir(); - let lib_path = tempdir.join("usr/lib/polkadot"); - let _ = fs::remove_dir_all(&lib_path); - fs::create_dir_all(&lib_path)?; - *workers_lib_path_override().lock()? = Some(lib_path); + let tempdir = tempfile::tempdir().unwrap(); + let tmp_dir = tempdir.path().to_path_buf(); + TMP_DIR.with_borrow_mut(|t| *t = Some(tempdir)); - let exe_path = tempdir.join("usr/bin"); - let _ = fs::remove_dir_all(&exe_path); - fs::create_dir_all(&exe_path)?; - *workers_exe_path_override().lock()? = Some(exe_path.clone()); + fs::create_dir_all(workers_lib_path_override().unwrap()).unwrap(); + fs::create_dir_all(workers_exe_path_override().unwrap()).unwrap(); + let custom_path = tmp_dir.join("usr/local/bin"); // Set up custom path at /usr/local/bin. - let custom_path = tempdir.join("usr/local/bin"); - let _ = fs::remove_dir_all(&custom_path); - fs::create_dir_all(&custom_path)?; + fs::create_dir_all(&custom_path).unwrap(); - f(tempdir, exe_path) + f(tmp_dir, workers_exe_path_override().unwrap()) } #[test] - #[serial] fn test_given_worker_path() { with_temp_dir_structure(|tempdir, exe_path| { let given_workers_path = tempdir.join("usr/local/bin"); @@ -318,7 +310,6 @@ echo {} } #[test] - #[serial] fn missing_workers_paths_throws_error() { with_temp_dir_structure(|tempdir, exe_path| { // Try with both binaries missing. @@ -368,7 +359,6 @@ echo {} } #[test] - #[serial] fn should_find_workers_at_all_locations() { with_temp_dir_structure(|tempdir, _| { let prepare_worker_bin_path = tempdir.join("usr/bin/polkadot-prepare-worker"); @@ -394,7 +384,6 @@ echo {} } #[test] - #[serial] fn should_find_workers_with_custom_names_at_all_locations() { with_temp_dir_structure(|tempdir, _| { let (prep_worker_name, exec_worker_name) = ("test-prepare", "test-execute"); @@ -422,7 +411,6 @@ echo {} } #[test] - #[serial] fn workers_version_mismatch_throws_error() { let bad_version = "v9.9.9.9"; @@ -474,7 +462,6 @@ echo {} } #[test] - #[serial] fn should_find_valid_workers() { // Test bin location. with_temp_dir_structure(|tempdir, _| { diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 8633818e775d..e288ee2b78d3 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -21,79 +21,79 @@ doc = false [dependencies] -tikv-jemallocator = { features = ["profiling", "unprefixed_malloc_on_supported_platforms"], workspace = true, optional = true } -jemalloc_pprof = { workspace = true, optional = true } -polkadot-service = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } -polkadot-node-subsystem-util = { workspace = true, default-features = true } -polkadot-node-subsystem-types = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, features = ["test"] } -polkadot-node-network-protocol = { workspace = true, default-features = true } -polkadot-availability-recovery = { features = ["subsystem-benchmarks"], workspace = true, default-features = true } -polkadot-availability-distribution = { workspace = true, default-features = true } -polkadot-statement-distribution = { workspace = true, default-features = true } -polkadot-node-core-av-store = { workspace = true, default-features = true } -polkadot-node-core-chain-api = { workspace = true, default-features = true } -polkadot-availability-bitfield-distribution = { workspace = true, default-features = true } -color-eyre = { workspace = true } -polkadot-overseer = { workspace = true, default-features = true } -colored = { workspace = true } assert_matches = { workspace = true } async-trait = { workspace = true } -sp-keystore = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +bincode = { workspace = true } clap = { features = ["derive"], workspace = true } +color-eyre = { workspace = true } +colored = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } -bincode = { workspace = true } -sha1 = { workspace = true } -hex = { workspace = true, default-features = true } gum = { workspace = true, default-features = true } -polkadot-erasure-coding = { workspace = true, default-features = true } +hex = { workspace = true, default-features = true } +jemalloc_pprof = { workspace = true, optional = true } log = { workspace = true, default-features = true } -sp-tracing = { workspace = true } +polkadot-availability-bitfield-distribution = { workspace = true, default-features = true } +polkadot-availability-distribution = { workspace = true, default-features = true } +polkadot-availability-recovery = { features = ["subsystem-benchmarks"], workspace = true, default-features = true } +polkadot-erasure-coding = { workspace = true, default-features = true } +polkadot-node-core-av-store = { workspace = true, default-features = true } +polkadot-node-core-chain-api = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { 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, features = ["test"] } +polkadot-service = { workspace = true, default-features = true } +polkadot-statement-distribution = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } +sha1 = { workspace = true } +sp-core = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-tracing = { workspace = true } +tikv-jemallocator = { features = ["profiling", "unprefixed_malloc_on_supported_platforms"], workspace = true, optional = true } # `rand` only supports uniform distribution, we need normal distribution for latency. -rand_distr = { workspace = true } bitvec = { workspace = true, default-features = true } kvdb-memorydb = { workspace = true } +rand_distr = { workspace = true } -codec = { features = ["derive", "std"], workspace = true, default-features = true } -tokio = { features = ["parking_lot", "rt-multi-thread"], workspace = true, default-features = true } clap-num = { workspace = true } +codec = { features = ["derive", "std"], workspace = true, default-features = true } +itertools = { workspace = true } +polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } -sp-keyring = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } +polkadot-primitives-test-helpers = { workspace = true } +prometheus = { workspace = true } +prometheus-endpoint = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } -polkadot-node-metrics = { workspace = true, default-features = true } -itertools = { workspace = true } -polkadot-primitives-test-helpers = { workspace = true } -prometheus-endpoint = { workspace = true, default-features = true } -prometheus = { workspace = true } serde = { workspace = true, default-features = true } -serde_yaml = { workspace = true } serde_json = { workspace = true } +serde_yaml = { workspace = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +tokio = { features = ["parking_lot", "rt-multi-thread"], workspace = true, default-features = true } +polkadot-approval-distribution = { workspace = true, default-features = 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 } sp-timestamp = { workspace = true, default-features = true } schnorrkel = { workspace = true } # rand_core should match schnorrkel -rand_core = { workspace = true } -rand_chacha = { workspace = true, default-features = true } -paste = { workspace = true, default-features = true } orchestra = { features = ["futures_channel"], workspace = true } +paste = { workspace = true, default-features = true } pyroscope = { workspace = true } pyroscope_pprofrs = { workspace = true } +rand_chacha = { workspace = true, default-features = true } +rand_core = { workspace = true } strum = { features = ["derive"], workspace = true, default-features = true } [features] diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index 8ac9796acb62..23dc6bd1caf9 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -22,9 +22,7 @@ use crate::{ av_store::{MockAvailabilityStore, NetworkAvailabilityState}, chain_api::{ChainApiState, MockChainApi}, network_bridge::{self, MockNetworkBridgeRx, MockNetworkBridgeTx}, - runtime_api::{ - node_features_with_chunk_mapping_enabled, MockRuntimeApi, MockRuntimeApiCoreState, - }, + runtime_api::{default_node_features, MockRuntimeApi, MockRuntimeApiCoreState}, AlwaysSupportsParachains, }, network::new_network, @@ -394,7 +392,7 @@ pub async fn benchmark_availability_write( expected_erasure_root: backed_candidate.descriptor().erasure_root(), tx, core_index: CoreIndex(core_index as u32), - node_features: node_features_with_chunk_mapping_enabled(), + node_features: default_node_features(), }, )) .await; diff --git a/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs b/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs index 511795970e6c..764572ffe192 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs @@ -17,7 +17,7 @@ use crate::{ configuration::{TestAuthorities, TestConfiguration}, environment::GENESIS_HASH, - mock::runtime_api::node_features_with_chunk_mapping_enabled, + mock::runtime_api::default_node_features, }; use bitvec::bitvec; use codec::Encode; @@ -118,7 +118,7 @@ impl TestState { test_state.chunk_indices = (0..config.n_cores) .map(|core_index| { availability_chunk_indices( - Some(&node_features_with_chunk_mapping_enabled()), + Some(&default_node_features()), config.n_validators, CoreIndex(core_index as u32), ) diff --git a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs index 6c54d14448a1..69e838eb864e 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -28,12 +28,13 @@ use polkadot_node_subsystem_types::OverseerSignal; use polkadot_primitives::{ node_features, vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt, CoreState, OccupiedCore}, - ApprovalVotingParams, AsyncBackingParams, GroupIndex, GroupRotationInfo, IndexedVec, - NodeFeatures, ScheduledCore, SessionIndex, SessionInfo, ValidationCode, ValidatorIndex, + ApprovalVotingParams, AsyncBackingParams, CoreIndex, GroupIndex, GroupRotationInfo, + Id as ParaId, IndexedVec, NodeFeatures, ScheduledCore, SessionIndex, SessionInfo, + ValidationCode, ValidatorIndex, }; use sp_consensus_babe::Epoch as BabeEpoch; use sp_core::H256; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap, VecDeque}; const LOG_TARGET: &str = "subsystem-bench::runtime-api-mock"; @@ -51,6 +52,8 @@ pub struct RuntimeApiState { babe_epoch: Option, // The session child index, session_index: SessionIndex, + // The claim queue + claim_queue: BTreeMap>, } #[derive(Clone)] @@ -80,7 +83,25 @@ impl MockRuntimeApi { core_state: MockRuntimeApiCoreState, ) -> MockRuntimeApi { // Enable chunk mapping feature to make systematic av-recovery possible. - let node_features = node_features_with_chunk_mapping_enabled(); + let node_features = default_node_features(); + let validator_group_count = + session_info_for_peers(&config, &authorities).validator_groups.len(); + + // Each para gets one core assigned and there is only one candidate per + // parachain per relay chain block (no elastic scaling). + let claim_queue = candidate_hashes + .iter() + .next() + .expect("Candidates are generated at test start") + .1 + .iter() + .enumerate() + .map(|(index, candidate_receipt)| { + // Ensure test breaks if badly configured. + assert!(index < validator_group_count); + (CoreIndex(index as u32), vec![candidate_receipt.descriptor.para_id()].into()) + }) + .collect(); Self { state: RuntimeApiState { @@ -90,6 +111,7 @@ impl MockRuntimeApi { babe_epoch, session_index, node_features, + claim_queue, }, config, core_state, @@ -305,6 +327,9 @@ impl MockRuntimeApi { if let Err(err) = tx.send(Ok(ApprovalVotingParams::default())) { gum::error!(target: LOG_TARGET, ?err, "Voting params weren't received"); }, + RuntimeApiMessage::Request(_parent, RuntimeApiRequest::ClaimQueue(tx)) => { + tx.send(Ok(self.state.claim_queue.clone())).unwrap(); + }, // Long term TODO: implement more as needed. message => { unimplemented!("Unexpected runtime-api message: {:?}", message) @@ -316,9 +341,12 @@ impl MockRuntimeApi { } } -pub fn node_features_with_chunk_mapping_enabled() -> NodeFeatures { +pub fn default_node_features() -> NodeFeatures { let mut node_features = NodeFeatures::new(); - node_features.resize(node_features::FeatureIndex::AvailabilityChunkMapping as usize + 1, false); + node_features.resize(node_features::FeatureIndex::FirstUnassigned as usize, false); node_features.set(node_features::FeatureIndex::AvailabilityChunkMapping as u8 as usize, true); + node_features.set(node_features::FeatureIndex::ElasticScalingMVP as u8 as usize, true); + node_features.set(node_features::FeatureIndex::CandidateReceiptV2 as u8 as usize, true); + node_features } diff --git a/polkadot/node/subsystem-bench/src/lib/statement/test_state.rs b/polkadot/node/subsystem-bench/src/lib/statement/test_state.rs index 2d2e9434b767..e9b586522d2b 100644 --- a/polkadot/node/subsystem-bench/src/lib/statement/test_state.rs +++ b/polkadot/node/subsystem-bench/src/lib/statement/test_state.rs @@ -45,8 +45,9 @@ use polkadot_primitives::{ CandidateReceiptV2 as CandidateReceipt, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, MutateDescriptorV2, }, - BlockNumber, CandidateHash, CompactStatement, Hash, Header, Id, PersistedValidationData, - SessionInfo, SignedStatement, SigningContext, UncheckedSigned, ValidatorIndex, ValidatorPair, + BlockNumber, CandidateHash, CompactStatement, CoreIndex, Hash, Header, Id, + PersistedValidationData, SessionInfo, SignedStatement, SigningContext, UncheckedSigned, + ValidatorIndex, ValidatorPair, }; use polkadot_primitives_test_helpers::{ dummy_committed_candidate_receipt_v2, dummy_hash, dummy_head_data, dummy_pvd, @@ -61,6 +62,8 @@ use std::{ }, }; +const SESSION_INDEX: u32 = 0; + #[derive(Clone)] pub struct TestState { // Full test config @@ -130,6 +133,8 @@ impl TestState { let mut receipt = receipt_templates[candidate_index].clone(); receipt.descriptor.set_para_id(Id::new(core_idx as u32 + 1)); receipt.descriptor.set_relay_parent(block_info.hash); + receipt.descriptor.set_core_index(CoreIndex(core_idx as u32)); + receipt.descriptor.set_session_index(SESSION_INDEX); state.candidate_receipts.entry(block_info.hash).or_default().push( CandidateReceipt { @@ -193,7 +198,7 @@ fn sign_statement( validator_index: ValidatorIndex, pair: &ValidatorPair, ) -> UncheckedSigned { - let context = SigningContext { parent_hash: relay_parent, session_index: 0 }; + let context = SigningContext { parent_hash: relay_parent, session_index: SESSION_INDEX }; let payload = statement.signing_payload(&context); SignedStatement::new( @@ -320,7 +325,8 @@ impl HandleNetworkMessage for TestState { } let statement = CompactStatement::Valid(candidate_hash); - let context = SigningContext { parent_hash: relay_parent, session_index: 0 }; + let context = + SigningContext { parent_hash: relay_parent, session_index: SESSION_INDEX }; let payload = statement.signing_payload(&context); let pair = self.test_authorities.validator_pairs.get(index).unwrap(); let signature = pair.sign(&payload[..]); diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index d3229291673c..4e660b15c1e2 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -14,16 +14,16 @@ workspace = true async-trait = { workspace = true } futures = { workspace = true } parking_lot = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-erasure-coding = { workspace = true, default-features = true } +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-primitives = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index b8bad8f8a295..6c88a4474137 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -5,31 +5,32 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +async-trait = { workspace = true } +bitvec = { features = ["alloc"], workspace = true } derive_more = { workspace = true, default-features = true } fatality = { workspace = true } futures = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } +orchestra = { features = ["futures_channel"], workspace = true } polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-statement-table = { workspace = true, default-features = true } -orchestra = { features = ["futures_channel"], workspace = true } +prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +smallvec = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-authority-discovery = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } -smallvec = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } thiserror = { workspace = true } -async-trait = { workspace = true } -bitvec = { features = ["alloc"], workspace = true } -strum = { features = ["derive"], workspace = true, default-features = true } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index ba1ba5755be0..b541f9519219 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -24,7 +24,6 @@ use futures::channel::oneshot; use sc_network::{Multiaddr, ReputationChange}; -use strum::EnumIter; use thiserror::Error; pub use sc_network::IfDisconnected; @@ -49,12 +48,12 @@ use polkadot_primitives::{ CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, }, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateHash, - CandidateIndex, CollatorId, CoreIndex, DisputeState, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, HeadData, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, MultiDisputeStatementSet, NodeFeatures, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, PvfExecKind as RuntimePvfExecKind, SessionIndex, - SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + CandidateIndex, CoreIndex, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, + HeadData, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + MultiDisputeStatementSet, NodeFeatures, OccupiedCoreAssumption, PersistedValidationData, + PvfCheckStatement, PvfExecKind as RuntimePvfExecKind, SessionIndex, SessionInfo, + SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -189,18 +188,16 @@ pub enum CandidateValidationMessage { /// Extends primitives::PvfExecKind, which is a runtime parameter we don't want to change, /// to separate and prioritize execution jobs by request type. -/// The order is important, because we iterate through the values and assume it is going from higher -/// to lowest priority. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumIter)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PvfExecKind { /// For dispute requests Dispute, /// For approval requests Approval, - /// For backing requests from system parachains. - BackingSystemParas, - /// For backing requests. - Backing, + /// For backing requests from system parachains. With relay parent hash + BackingSystemParas(Hash), + /// For backing requests. With relay parent hash + Backing(Hash), } impl PvfExecKind { @@ -209,8 +206,8 @@ impl PvfExecKind { match *self { Self::Dispute => "dispute", Self::Approval => "approval", - Self::BackingSystemParas => "backing_system_paras", - Self::Backing => "backing", + Self::BackingSystemParas(_) => "backing_system_paras", + Self::Backing(_) => "backing", } } } @@ -220,8 +217,8 @@ impl From for RuntimePvfExecKind { match exec { PvfExecKind::Dispute => RuntimePvfExecKind::Approval, PvfExecKind::Approval => RuntimePvfExecKind::Approval, - PvfExecKind::BackingSystemParas => RuntimePvfExecKind::Backing, - PvfExecKind::Backing => RuntimePvfExecKind::Backing, + PvfExecKind::BackingSystemParas(_) => RuntimePvfExecKind::Backing, + PvfExecKind::Backing(_) => RuntimePvfExecKind::Backing, } } } @@ -253,9 +250,6 @@ pub enum CollatorProtocolMessage { /// The core index where the candidate should be backed. core_index: CoreIndex, }, - /// Report a collator as having provided an invalid collation. This should lead to disconnect - /// and blacklist of the collator. - ReportCollator(CollatorId), /// Get a network bridge update. #[from] NetworkBridgeUpdate(NetworkBridgeEvent), diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index d12daa572055..0e6ebf611997 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -5,39 +5,41 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true } +derive_more = { workspace = true, default-features = true } +fatality = { workspace = true } futures = { workspace = true } futures-channel = { workspace = true } +gum = { workspace = true, default-features = true } itertools = { workspace = true } -codec = { features = ["derive"], workspace = true } parking_lot = { workspace = true, default-features = true } pin-project = { workspace = true } rand = { workspace = true, default-features = true } -thiserror = { workspace = true } -fatality = { workspace = true } -gum = { workspace = true, default-features = true } -derive_more = { workspace = true, default-features = true } schnellru = { workspace = true } +thiserror = { workspace = true } +metered = { features = ["futures_channel"], workspace = true } polkadot-erasure-coding = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } -polkadot-node-subsystem-types = { workspace = true, default-features = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-types = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } -metered = { features = ["futures_channel"], workspace = true } +polkadot-primitives = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } kvdb = { workspace = true } parity-db = { workspace = true } @@ -45,9 +47,9 @@ parity-db = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } futures = { features = ["thread-pool"], workspace = true } +kvdb-memorydb = { workspace = true } +kvdb-shared-tests = { workspace = true } log = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } -kvdb-shared-tests = { workspace = true } tempfile = { workspace = true } -kvdb-memorydb = { workspace = true } diff --git a/polkadot/node/subsystem-util/src/backing_implicit_view.rs b/polkadot/node/subsystem-util/src/backing_implicit_view.rs index a805ef8165e5..67f5dad518e1 100644 --- a/polkadot/node/subsystem-util/src/backing_implicit_view.rs +++ b/polkadot/node/subsystem-util/src/backing_implicit_view.rs @@ -20,14 +20,15 @@ use polkadot_node_subsystem::{ messages::{ChainApiMessage, ProspectiveParachainsMessage, RuntimeApiMessage}, SubsystemSender, }; -use polkadot_primitives::{BlockNumber, Hash, Id as ParaId}; +use polkadot_primitives::{AsyncBackingParams, BlockNumber, Hash, Id as ParaId}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use crate::{ inclusion_emulator::RelayChainBlockInfo, - request_session_index_for_child, - runtime::{self, prospective_parachains_mode, recv_runtime, ProspectiveParachainsMode}, + request_async_backing_params, request_session_index_for_child, + runtime::{self, recv_runtime}, + LOG_TARGET, }; // Always aim to retain 1 block before the active leaves. @@ -173,13 +174,7 @@ impl View { return Err(FetchError::AlreadyKnown) } - let res = fetch_fresh_leaf_and_insert_ancestry( - leaf_hash, - &mut self.block_info_storage, - &mut *sender, - self.collating_for, - ) - .await; + let res = self.fetch_fresh_leaf_and_insert_ancestry(leaf_hash, &mut *sender).await; match res { Ok(fetched) => { @@ -323,6 +318,205 @@ impl View { .as_ref() .map(|mins| mins.allowed_relay_parents_for(para_id, block_info.block_number)) } + + /// Returns all paths from each leaf to the last block in state containing `relay_parent`. If no + /// paths exist the function will return an empty `Vec`. + pub fn paths_via_relay_parent(&self, relay_parent: &Hash) -> Vec> { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + leaves=?self.leaves, + block_info_storage=?self.block_info_storage, + "Finding paths via relay parent" + ); + + if self.leaves.is_empty() { + // No leaves so the view should be empty. Don't return any paths. + return vec![] + }; + + if !self.block_info_storage.contains_key(relay_parent) { + // `relay_parent` is not in the view - don't return any paths + return vec![] + } + + // Find all paths from each leaf to `relay_parent`. + let mut paths = Vec::new(); + for (leaf, _) in &self.leaves { + let mut path = Vec::new(); + let mut current_leaf = *leaf; + let mut visited = HashSet::new(); + let mut path_contains_target = false; + + // Start from the leaf and traverse all known blocks + loop { + if visited.contains(¤t_leaf) { + // There is a cycle - abandon this path + break + } + + current_leaf = match self.block_info_storage.get(¤t_leaf) { + Some(info) => { + // `current_leaf` is a known block - add it to the path and mark it as + // visited + path.push(current_leaf); + visited.insert(current_leaf); + + // `current_leaf` is the target `relay_parent`. Mark the path so that it's + // included in the result + if current_leaf == *relay_parent { + path_contains_target = true; + } + + // update `current_leaf` with the parent + info.parent_hash + }, + None => { + // path is complete + if path_contains_target { + // we want the path ordered from oldest to newest so reverse it + paths.push(path.into_iter().rev().collect()); + } + break + }, + }; + } + } + + paths + } + + async fn fetch_fresh_leaf_and_insert_ancestry( + &mut self, + leaf_hash: Hash, + sender: &mut Sender, + ) -> Result + where + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender, + { + let leaf_header = { + let (tx, rx) = oneshot::channel(); + sender.send_message(ChainApiMessage::BlockHeader(leaf_hash, tx)).await; + + match rx.await { + Ok(Ok(Some(header))) => header, + Ok(Ok(None)) => + return Err(FetchError::BlockHeaderUnavailable( + leaf_hash, + BlockHeaderUnavailableReason::Unknown, + )), + Ok(Err(e)) => + return Err(FetchError::BlockHeaderUnavailable( + leaf_hash, + BlockHeaderUnavailableReason::Internal(e), + )), + Err(_) => + return Err(FetchError::BlockHeaderUnavailable( + leaf_hash, + BlockHeaderUnavailableReason::SubsystemUnavailable, + )), + } + }; + + // If the node is a collator, bypass prospective-parachains. We're only interested in the + // one paraid and the subsystem is not present. + let min_relay_parents = if let Some(para_id) = self.collating_for { + fetch_min_relay_parents_for_collator(leaf_hash, leaf_header.number, sender) + .await? + .map(|x| vec![(para_id, x)]) + .unwrap_or_default() + } else { + fetch_min_relay_parents_from_prospective_parachains(leaf_hash, sender).await? + }; + + let min_min = min_relay_parents.iter().map(|x| x.1).min().unwrap_or(leaf_header.number); + let expected_ancestry_len = (leaf_header.number.saturating_sub(min_min) as usize) + 1; + + let ancestry = if leaf_header.number > 0 { + let mut next_ancestor_number = leaf_header.number - 1; + let mut next_ancestor_hash = leaf_header.parent_hash; + + let mut ancestry = Vec::with_capacity(expected_ancestry_len); + ancestry.push(leaf_hash); + + // Ensure all ancestors up to and including `min_min` are in the + // block storage. When views advance incrementally, everything + // should already be present. + while next_ancestor_number >= min_min { + let parent_hash = if let Some(info) = + self.block_info_storage.get(&next_ancestor_hash) + { + info.parent_hash + } else { + // load the header and insert into block storage. + let (tx, rx) = oneshot::channel(); + sender.send_message(ChainApiMessage::BlockHeader(next_ancestor_hash, tx)).await; + + let header = match rx.await { + Ok(Ok(Some(header))) => header, + Ok(Ok(None)) => + return Err(FetchError::BlockHeaderUnavailable( + next_ancestor_hash, + BlockHeaderUnavailableReason::Unknown, + )), + Ok(Err(e)) => + return Err(FetchError::BlockHeaderUnavailable( + next_ancestor_hash, + BlockHeaderUnavailableReason::Internal(e), + )), + Err(_) => + return Err(FetchError::BlockHeaderUnavailable( + next_ancestor_hash, + BlockHeaderUnavailableReason::SubsystemUnavailable, + )), + }; + + self.block_info_storage.insert( + next_ancestor_hash, + BlockInfo { + block_number: next_ancestor_number, + parent_hash: header.parent_hash, + maybe_allowed_relay_parents: None, + }, + ); + + header.parent_hash + }; + + ancestry.push(next_ancestor_hash); + if next_ancestor_number == 0 { + break + } + + next_ancestor_number -= 1; + next_ancestor_hash = parent_hash; + } + + ancestry + } else { + vec![leaf_hash] + }; + + let fetched_ancestry = + FetchSummary { minimum_ancestor_number: min_min, leaf_number: leaf_header.number }; + + let allowed_relay_parents = AllowedRelayParents { + minimum_relay_parents: min_relay_parents.into_iter().collect(), + allowed_relay_parents_contiguous: ancestry, + }; + + let leaf_block_info = BlockInfo { + parent_hash: leaf_header.parent_hash, + block_number: leaf_header.number, + maybe_allowed_relay_parents: Some(allowed_relay_parents), + }; + + self.block_info_storage.insert(leaf_hash, leaf_block_info); + + Ok(fetched_ancestry) + } } /// Errors when fetching a leaf and associated ancestry. @@ -396,13 +590,8 @@ where + SubsystemSender + SubsystemSender, { - let Ok(ProspectiveParachainsMode::Enabled { allowed_ancestry_len, .. }) = - prospective_parachains_mode(sender, leaf_hash).await - else { - // This should never happen, leaves that don't have prospective parachains mode enabled - // should not use implicit view. - return Ok(None) - }; + let AsyncBackingParams { allowed_ancestry_len, .. } = + recv_runtime(request_async_backing_params(leaf_hash, sender).await).await?; // Fetch the session of the leaf. We must make sure that we stop at the ancestor which has a // different session index. @@ -416,7 +605,7 @@ where sender .send_message(ChainApiMessage::Ancestors { hash: leaf_hash, - k: allowed_ancestry_len, + k: allowed_ancestry_len as usize, response_channel: tx, }) .await; @@ -442,137 +631,6 @@ where Ok(Some(min)) } -async fn fetch_fresh_leaf_and_insert_ancestry( - leaf_hash: Hash, - block_info_storage: &mut HashMap, - sender: &mut Sender, - collating_for: Option, -) -> Result -where - Sender: SubsystemSender - + SubsystemSender - + SubsystemSender, -{ - let leaf_header = { - let (tx, rx) = oneshot::channel(); - sender.send_message(ChainApiMessage::BlockHeader(leaf_hash, tx)).await; - - match rx.await { - Ok(Ok(Some(header))) => header, - Ok(Ok(None)) => - return Err(FetchError::BlockHeaderUnavailable( - leaf_hash, - BlockHeaderUnavailableReason::Unknown, - )), - Ok(Err(e)) => - return Err(FetchError::BlockHeaderUnavailable( - leaf_hash, - BlockHeaderUnavailableReason::Internal(e), - )), - Err(_) => - return Err(FetchError::BlockHeaderUnavailable( - leaf_hash, - BlockHeaderUnavailableReason::SubsystemUnavailable, - )), - } - }; - - // If the node is a collator, bypass prospective-parachains. We're only interested in the one - // paraid and the subsystem is not present. - let min_relay_parents = if let Some(para_id) = collating_for { - fetch_min_relay_parents_for_collator(leaf_hash, leaf_header.number, sender) - .await? - .map(|x| vec![(para_id, x)]) - .unwrap_or_default() - } else { - fetch_min_relay_parents_from_prospective_parachains(leaf_hash, sender).await? - }; - - let min_min = min_relay_parents.iter().map(|x| x.1).min().unwrap_or(leaf_header.number); - let expected_ancestry_len = (leaf_header.number.saturating_sub(min_min) as usize) + 1; - - let ancestry = if leaf_header.number > 0 { - let mut next_ancestor_number = leaf_header.number - 1; - let mut next_ancestor_hash = leaf_header.parent_hash; - - let mut ancestry = Vec::with_capacity(expected_ancestry_len); - ancestry.push(leaf_hash); - - // Ensure all ancestors up to and including `min_min` are in the - // block storage. When views advance incrementally, everything - // should already be present. - while next_ancestor_number >= min_min { - let parent_hash = if let Some(info) = block_info_storage.get(&next_ancestor_hash) { - info.parent_hash - } else { - // load the header and insert into block storage. - let (tx, rx) = oneshot::channel(); - sender.send_message(ChainApiMessage::BlockHeader(next_ancestor_hash, tx)).await; - - let header = match rx.await { - Ok(Ok(Some(header))) => header, - Ok(Ok(None)) => - return Err(FetchError::BlockHeaderUnavailable( - next_ancestor_hash, - BlockHeaderUnavailableReason::Unknown, - )), - Ok(Err(e)) => - return Err(FetchError::BlockHeaderUnavailable( - next_ancestor_hash, - BlockHeaderUnavailableReason::Internal(e), - )), - Err(_) => - return Err(FetchError::BlockHeaderUnavailable( - next_ancestor_hash, - BlockHeaderUnavailableReason::SubsystemUnavailable, - )), - }; - - block_info_storage.insert( - next_ancestor_hash, - BlockInfo { - block_number: next_ancestor_number, - parent_hash: header.parent_hash, - maybe_allowed_relay_parents: None, - }, - ); - - header.parent_hash - }; - - ancestry.push(next_ancestor_hash); - if next_ancestor_number == 0 { - break - } - - next_ancestor_number -= 1; - next_ancestor_hash = parent_hash; - } - - ancestry - } else { - vec![leaf_hash] - }; - - let fetched_ancestry = - FetchSummary { minimum_ancestor_number: min_min, leaf_number: leaf_header.number }; - - let allowed_relay_parents = AllowedRelayParents { - minimum_relay_parents: min_relay_parents.into_iter().collect(), - allowed_relay_parents_contiguous: ancestry, - }; - - let leaf_block_info = BlockInfo { - parent_hash: leaf_header.parent_hash, - block_number: leaf_header.number, - maybe_allowed_relay_parents: Some(allowed_relay_parents), - }; - - block_info_storage.insert(leaf_hash, leaf_block_info); - - Ok(fetched_ancestry) -} - #[cfg(test)] mod tests { use super::*; @@ -803,6 +861,23 @@ mod tests { assert_eq!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_A)), Some(&expected_ancestry[..(PARA_A_MIN_PARENT - 1) as usize])); assert_eq!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_B)), Some(&expected_ancestry[..])); assert!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_C)).unwrap().is_empty()); + + assert_eq!(view.leaves.len(), 1); + assert!(view.leaves.contains_key(leaf)); + assert!(view.paths_via_relay_parent(&CHAIN_B[0]).is_empty()); + assert!(view.paths_via_relay_parent(&CHAIN_A[0]).is_empty()); + assert_eq!( + view.paths_via_relay_parent(&CHAIN_B[min_min_idx]), + vec![CHAIN_B[min_min_idx..].to_vec()] + ); + assert_eq!( + view.paths_via_relay_parent(&CHAIN_B[min_min_idx + 1]), + vec![CHAIN_B[min_min_idx..].to_vec()] + ); + assert_eq!( + view.paths_via_relay_parent(&leaf), + vec![CHAIN_B[min_min_idx..].to_vec()] + ); } ); @@ -923,6 +998,12 @@ mod tests { assert!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_B)).unwrap().is_empty()); assert!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_C)).unwrap().is_empty()); + + assert!(view.paths_via_relay_parent(&CHAIN_A[0]).is_empty()); + assert_eq!( + view.paths_via_relay_parent(&CHAIN_B[min_min_idx]), + vec![CHAIN_B[min_min_idx..].to_vec()] + ); } ); @@ -991,6 +1072,12 @@ mod tests { assert!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_B)).unwrap().is_empty()); assert!(view.known_allowed_relay_parents_under(&leaf, Some(PARA_C)).unwrap().is_empty()); + + assert!(view.paths_via_relay_parent(&GENESIS_HASH).is_empty()); + assert_eq!( + view.paths_via_relay_parent(&CHAIN_A[0]), + vec![CHAIN_A.to_vec()] + ); } ); } @@ -1165,4 +1252,69 @@ mod tests { Some(hashes) if hashes == &[GENESIS_HASH] ); } + + #[test] + fn path_with_fork() { + let pool = TaskExecutor::new(); + let (mut ctx, mut ctx_handle) = make_subsystem_context::(pool); + + let mut view = View::default(); + + assert_eq!(view.collating_for, None); + + // Chain A + let prospective_response = vec![(PARA_A, 0)]; // was PARA_A_MIN_PARENT + let leaf = CHAIN_A.last().unwrap(); + let blocks = [&[GENESIS_HASH], CHAIN_A].concat(); + let leaf_idx = blocks.len() - 1; + + let fut = view.activate_leaf(ctx.sender(), *leaf).timeout(TIMEOUT).map(|res| { + res.expect("`activate_leaf` timed out").unwrap(); + }); + let overseer_fut = async { + assert_block_header_requests(&mut ctx_handle, CHAIN_A, &blocks[leaf_idx..]).await; + assert_min_relay_parents_request(&mut ctx_handle, leaf, prospective_response).await; + assert_block_header_requests(&mut ctx_handle, CHAIN_A, &blocks[..leaf_idx]).await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + // Chain B + let prospective_response = vec![(PARA_A, 1)]; + + let leaf = CHAIN_B.last().unwrap(); + let leaf_idx = CHAIN_B.len() - 1; + + let fut = view.activate_leaf(ctx.sender(), *leaf).timeout(TIMEOUT).map(|res| { + res.expect("`activate_leaf` timed out").unwrap(); + }); + let overseer_fut = async { + assert_block_header_requests(&mut ctx_handle, CHAIN_B, &CHAIN_B[leaf_idx..]).await; + assert_min_relay_parents_request(&mut ctx_handle, leaf, prospective_response).await; + assert_block_header_requests(&mut ctx_handle, CHAIN_B, &CHAIN_B[0..leaf_idx]).await; + }; + futures::executor::block_on(join(fut, overseer_fut)); + + assert_eq!(view.leaves.len(), 2); + + let mut paths_to_genesis = view.paths_via_relay_parent(&GENESIS_HASH); + paths_to_genesis.sort(); + let mut expected_paths_to_genesis = vec![ + [GENESIS_HASH].iter().chain(CHAIN_A.iter()).copied().collect::>(), + [GENESIS_HASH].iter().chain(CHAIN_B.iter()).copied().collect::>(), + ]; + expected_paths_to_genesis.sort(); + assert_eq!(paths_to_genesis, expected_paths_to_genesis); + + let path_to_leaf_in_a = view.paths_via_relay_parent(&CHAIN_A[1]); + let expected_path_to_leaf_in_a = + vec![[GENESIS_HASH].iter().chain(CHAIN_A.iter()).copied().collect::>()]; + assert_eq!(path_to_leaf_in_a, expected_path_to_leaf_in_a); + + let path_to_leaf_in_b = view.paths_via_relay_parent(&CHAIN_B[4]); + let expected_path_to_leaf_in_b = + vec![[GENESIS_HASH].iter().chain(CHAIN_B.iter()).copied().collect::>()]; + assert_eq!(path_to_leaf_in_b, expected_path_to_leaf_in_b); + + assert_eq!(view.paths_via_relay_parent(&Hash::repeat_byte(0x0A)), Vec::>::new()); + } } diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index a2a6095b765c..48d3f27b1fa6 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -82,9 +82,9 @@ /// in practice at most once every few weeks. use polkadot_node_subsystem::messages::HypotheticalCandidate; use polkadot_primitives::{ - async_backing::Constraints as PrimitiveConstraints, BlockNumber, CandidateCommitments, - CandidateHash, Hash, HeadData, Id as ParaId, PersistedValidationData, UpgradeRestriction, - ValidationCodeHash, + async_backing::Constraints as PrimitiveConstraints, vstaging::skip_ump_signals, BlockNumber, + CandidateCommitments, CandidateHash, Hash, HeadData, Id as ParaId, PersistedValidationData, + UpgradeRestriction, ValidationCodeHash, }; use std::{collections::HashMap, sync::Arc}; @@ -431,9 +431,9 @@ pub struct ConstraintModifications { pub hrmp_watermark: Option, /// Outbound HRMP channel modifications. pub outbound_hrmp: HashMap, - /// The amount of UMP messages sent. + /// The amount of UMP XCM messages sent. `UMPSignal` and separator are excluded. pub ump_messages_sent: usize, - /// The amount of UMP bytes sent. + /// The amount of UMP XCM bytes sent. `UMPSignal` and separator are excluded. pub ump_bytes_sent: usize, /// The amount of DMP messages processed. pub dmp_messages_processed: usize, @@ -600,6 +600,13 @@ impl Fragment { validation_code_hash: &ValidationCodeHash, persisted_validation_data: &PersistedValidationData, ) -> Result { + // Filter UMP signals and the separator. + let upward_messages = + skip_ump_signals(commitments.upward_messages.iter()).collect::>(); + + let ump_messages_sent = upward_messages.len(); + let ump_bytes_sent = upward_messages.iter().map(|msg| msg.len()).sum(); + let modifications = { ConstraintModifications { required_parent: Some(commitments.head_data.clone()), @@ -632,8 +639,8 @@ impl Fragment { outbound_hrmp }, - ump_messages_sent: commitments.upward_messages.len(), - ump_bytes_sent: commitments.upward_messages.iter().map(|msg| msg.len()).sum(), + ump_messages_sent, + ump_bytes_sent, dmp_messages_processed: commitments.processed_downward_messages as _, code_upgrade_applied: operating_constraints .future_validation_code @@ -750,7 +757,7 @@ fn validate_against_constraints( }) } - if commitments.upward_messages.len() > constraints.max_ump_num_per_candidate { + if modifications.ump_messages_sent > constraints.max_ump_num_per_candidate { return Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { messages_allowed: constraints.max_ump_num_per_candidate, messages_submitted: commitments.upward_messages.len(), @@ -814,7 +821,11 @@ impl HypotheticalOrConcreteCandidate for HypotheticalCandidate { #[cfg(test)] mod tests { use super::*; - use polkadot_primitives::{HorizontalMessages, OutboundHrmpMessage, ValidationCode}; + use codec::Encode; + use polkadot_primitives::{ + vstaging::{ClaimQueueOffset, CoreSelector, UMPSignal, UMP_SEPARATOR}, + HorizontalMessages, OutboundHrmpMessage, ValidationCode, + }; #[test] fn stack_modifications() { @@ -1267,6 +1278,35 @@ mod tests { ); } + #[test] + fn ump_signals_ignored() { + let relay_parent = RelayChainBlockInfo { + number: 6, + hash: Hash::repeat_byte(0xbe), + storage_root: Hash::repeat_byte(0xff), + }; + + let constraints = make_constraints(); + let mut candidate = make_candidate(&constraints, &relay_parent); + let max_ump = constraints.max_ump_num_per_candidate; + + // Fill ump queue to the limit. + candidate + .commitments + .upward_messages + .try_extend((0..max_ump).map(|i| vec![i as u8])) + .unwrap(); + + // Add ump signals. + candidate.commitments.upward_messages.force_push(UMP_SEPARATOR); + candidate + .commitments + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(1)).encode()); + + Fragment::new(relay_parent, constraints, Arc::new(candidate)).unwrap(); + } + #[test] fn fragment_relay_parent_too_old() { let relay_parent = RelayChainBlockInfo { diff --git a/polkadot/node/subsystem/Cargo.toml b/polkadot/node/subsystem/Cargo.toml index ce4bceec7336..8b4a26e33ee6 100644 --- a/polkadot/node/subsystem/Cargo.toml +++ b/polkadot/node/subsystem/Cargo.toml @@ -5,10 +5,12 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -polkadot-overseer = { workspace = true, default-features = true } polkadot-node-subsystem-types = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index 587af659fbd2..13b14c0b9231 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -13,32 +13,32 @@ workspace = true codec = { features = ["derive"], workspace = true } # Polkadot dependencies +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-test-runtime = { workspace = true } polkadot-test-service = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } # Substrate dependencies -substrate-test-client = { workspace = true } -sc-service = { workspace = true, default-features = true } +frame-benchmarking = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-offchain = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-inherents = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } -sp-state-machine = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -frame-benchmarking = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +substrate-test-client = { workspace = true } [dev-dependencies] -sp-keyring = { workspace = true, default-features = true } futures = { workspace = true } +sp-keyring = { workspace = true, default-features = true } [features] runtime-benchmarks = [ diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 4ef9d88621fb..54db2a0ac942 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -11,50 +11,50 @@ workspace = true [dependencies] futures = { workspace = true } -hex = { workspace = true, default-features = true } gum = { workspace = true, default-features = true } +hex = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } tempfile = { workspace = true } tokio = { workspace = true, default-features = true } # Polkadot dependencies +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-rpc = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } polkadot-service = { workspace = true, default-features = true } -polkadot-node-subsystem = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } polkadot-test-runtime = { workspace = true } test-runtime-constants = { workspace = true, default-features = true } -polkadot-runtime-parachains = { workspace = true, default-features = true } # Substrate dependencies -sp-authority-discovery = { workspace = true, default-features = true } -sc-authority-discovery = { workspace = true, default-features = true } -sc-consensus-babe = { workspace = true, default-features = true } -sp-consensus-babe = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true, default-features = true } -sp-consensus-grandpa = { workspace = true, default-features = true } -sp-inherents = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } pallet-transaction-payment = { workspace = true, default-features = true } +sc-authority-discovery = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } +sc-consensus-babe = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } +sc-service = { workspace = true } sc-tracing = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } -sc-service = { workspace = true } sp-arithmetic = { workspace = true, default-features = true } +sp-authority-discovery = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index 6e09bb9e4310..f34bb62a7cf0 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -451,8 +451,8 @@ pub fn construct_extrinsic( /// Construct a transfer extrinsic. pub fn construct_transfer_extrinsic( client: &Client, - origin: sp_keyring::AccountKeyring, - dest: sp_keyring::AccountKeyring, + origin: sp_keyring::Sr25519Keyring, + dest: sp_keyring::Sr25519Keyring, value: Balance, ) -> UncheckedExtrinsic { let function = diff --git a/polkadot/node/tracking-allocator/Cargo.toml b/polkadot/node/tracking-allocator/Cargo.toml index d98377e53759..0fbf526ccb8b 100644 --- a/polkadot/node/tracking-allocator/Cargo.toml +++ b/polkadot/node/tracking-allocator/Cargo.toml @@ -5,6 +5,8 @@ version = "2.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index 56c49a1ec305..0d04012e28a8 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -12,13 +12,13 @@ license.workspace = true workspace = true [dependencies] -tokio = { features = ["macros", "net", "rt-multi-thread", "sync"], workspace = true } -url = { workspace = true } -tokio-tungstenite = { workspace = true } -futures-util = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true, default-features = true } -reqwest = { features = ["rustls-tls"], workspace = true } -thiserror = { workspace = true } +futures-util = { workspace = true, default-features = true } gum = { workspace = true, default-features = true } +reqwest = { features = ["rustls-tls"], workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +thiserror = { workspace = true } +tokio = { features = ["macros", "net", "rt-multi-thread", "sync"], workspace = true } +tokio-tungstenite = { workspace = true } +url = { workspace = true } diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 9d0518fd46ad..0dd103d58b25 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true version = "6.0.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -13,14 +15,14 @@ workspace = true # note: special care is taken to avoid inclusion of `sp-io` externals when compiling # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. +bounded-collections = { features = ["serde"], workspace = true } codec = { features = ["derive"], workspace = true } +derive_more = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true } scale-info = { features = ["derive", "serde"], workspace = true } -sp-runtime = { features = ["serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } +sp-runtime = { features = ["serde"], workspace = true } sp-weights = { workspace = true } -polkadot-core-primitives = { workspace = true } -derive_more = { workspace = true, default-features = true } -bounded-collections = { features = ["serde"], workspace = true } # all optional crates. serde = { features = ["alloc", "derive"], workspace = true } diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index c5757928c3fc..1f2f9e2e9cdc 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -57,6 +57,8 @@ impl HeadData { } } +impl codec::EncodeLike for alloc::vec::Vec {} + /// Parachain validation code. #[derive( PartialEq, @@ -154,6 +156,9 @@ pub struct BlockData(#[cfg_attr(feature = "std", serde(with = "bytes"))] pub Vec #[cfg_attr(feature = "std", derive(derive_more::Display))] pub struct Id(u32); +impl codec::EncodeLike for Id {} +impl codec::EncodeLike for u32 {} + impl TypeId for Id { const TYPE_ID: [u8; 4] = *b"para"; } diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index 9f35653f957f..2a1e1722bff9 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -11,8 +11,8 @@ publish = false workspace = true [dependencies] -tiny-keccak = { features = ["keccak"], workspace = true } codec = { features = ["derive"], workspace = true } +tiny-keccak = { features = ["keccak"], workspace = true } test-parachain-adder = { workspace = true } test-parachain-halt = { workspace = true } diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index 7a150b75d5cd..945b0e156904 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -12,10 +12,10 @@ publish = false workspace = true [dependencies] -polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } codec = { features = ["derive"], workspace = true } -tiny-keccak = { features = ["keccak"], workspace = true } dlmalloc = { features = ["global"], workspace = true } +polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } +tiny-keccak = { features = ["keccak"], workspace = true } # We need to make sure the global allocator is disabled until we have support of full substrate externalities sp-io = { features = ["disable_allocator"], workspace = true } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 061378a76a82..20305dc07c3a 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -15,30 +15,30 @@ name = "adder-collator" path = "src/main.rs" [dependencies] -codec = { features = ["derive"], workspace = true } clap = { features = ["derive"], workspace = true } +codec = { features = ["derive"], workspace = true } futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } -test-parachain-adder = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-cli = { workspace = true, default-features = true } -polkadot-service = { features = ["rococo-native"], workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-service = { features = ["rococo-native"], workspace = true, default-features = true } +test-parachain-adder = { workspace = true } sc-cli = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } [dev-dependencies] +polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-test-service = { workspace = true } -polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } -substrate-test-utils = { workspace = true } sc-service = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } +substrate-test-utils = { workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs b/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs index 85abf8bf36b9..5d728517c4bb 100644 --- a/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs +++ b/polkadot/parachain/test-parachains/adder/collator/tests/integration.rs @@ -23,7 +23,7 @@ #[tokio::test(flavor = "multi_thread")] async fn collating_using_adder_collator() { use polkadot_primitives::Id as ParaId; - use sp_keyring::AccountKeyring::*; + use sp_keyring::Sr25519Keyring::*; let mut builder = sc_cli::LoggerBuilder::new(""); builder.with_colors(false); diff --git a/polkadot/parachain/test-parachains/halt/Cargo.toml b/polkadot/parachain/test-parachains/halt/Cargo.toml index f8272f6ed196..ea8372ccd121 100644 --- a/polkadot/parachain/test-parachains/halt/Cargo.toml +++ b/polkadot/parachain/test-parachains/halt/Cargo.toml @@ -14,8 +14,8 @@ workspace = true [dependencies] [build-dependencies] -substrate-wasm-builder = { workspace = true, default-features = true } rustversion = { workspace = true } +substrate-wasm-builder = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 4b2e12ebf435..43b5a3352434 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -12,11 +12,11 @@ license.workspace = true workspace = true [dependencies] -polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } codec = { features = ["derive"], workspace = true } -tiny-keccak = { features = ["keccak"], workspace = true } dlmalloc = { features = ["global"], workspace = true } log = { workspace = true } +polkadot-parachain-primitives = { features = ["wasm-api"], workspace = true } +tiny-keccak = { features = ["keccak"], workspace = true } # We need to make sure the global allocator is disabled until we have support of full substrate externalities sp-io = { features = ["disable_allocator"], workspace = true } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 5760258c70ea..b964b4dc49ce 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -15,30 +15,30 @@ name = "undying-collator" path = "src/main.rs" [dependencies] -codec = { features = ["derive"], workspace = true } clap = { features = ["derive"], workspace = true } +codec = { features = ["derive"], workspace = true } futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } -test-parachain-undying = { workspace = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-cli = { workspace = true, default-features = true } -polkadot-service = { features = ["rococo-native"], workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-service = { features = ["rococo-native"], workspace = true, default-features = true } +test-parachain-undying = { workspace = true } sc-cli = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } [dev-dependencies] +polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-test-service = { workspace = true } -polkadot-node-core-pvf = { features = ["test-utils"], workspace = true, default-features = true } -substrate-test-utils = { workspace = true } sc-service = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } +substrate-test-utils = { workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs b/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs index 8be535b9bb4c..b8e32b13bc9c 100644 --- a/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs +++ b/polkadot/parachain/test-parachains/undying/collator/tests/integration.rs @@ -22,7 +22,7 @@ #[tokio::test(flavor = "multi_thread")] async fn collating_using_undying_collator() { use polkadot_primitives::Id as ParaId; - use sp_keyring::AccountKeyring::*; + use sp_keyring::Sr25519Keyring::*; let mut builder = sc_cli::LoggerBuilder::new(""); builder.with_colors(false); diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index dd269caa2d60..e693fe8c4a8c 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -5,29 +5,31 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Shared primitives used by Polkadot runtime" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] bitvec = { features = ["alloc", "serde"], workspace = true } -hex-literal = { workspace = true, default-features = true } codec = { features = ["bit-vec", "derive"], workspace = true } -scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } +hex-literal = { workspace = true, default-features = true } log = { workspace = true } +scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } thiserror = { workspace = true, optional = true } -sp-application-crypto = { features = ["serde"], workspace = true } -sp-inherents = { workspace = true } -sp-core = { workspace = true } -sp-runtime = { workspace = true } sp-api = { workspace = true } +sp-application-crypto = { features = ["serde"], workspace = true } sp-arithmetic = { features = ["serde"], workspace = true } sp-authority-discovery = { features = ["serde"], workspace = true } sp-consensus-slots = { features = ["serde"], workspace = true } +sp-core = { workspace = true } +sp-inherents = { workspace = true } sp-io = { workspace = true } sp-keystore = { optional = true, workspace = true } +sp-runtime = { workspace = true } sp-staking = { features = ["serde"], workspace = true } sp-std = { workspace = true, optional = true } diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 94b7b200e68f..271f78efe090 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -39,6 +39,10 @@ use sp_staking::SessionIndex; /// Async backing primitives pub mod async_backing; +/// The default claim queue offset to be used if it's not configured/accessible in the parachain +/// runtime +pub const DEFAULT_CLAIM_QUEUE_OFFSET: u8 = 0; + /// A type representing the version of the candidate descriptor and internal version number. #[derive(PartialEq, Eq, Encode, Decode, Clone, TypeInfo, RuntimeDebug, Copy)] #[cfg_attr(feature = "std", derive(Hash))] @@ -204,6 +208,8 @@ pub trait MutateDescriptorV2 { fn set_version(&mut self, version: InternalVersion); /// Set the PVD of the descriptor. fn set_persisted_validation_data_hash(&mut self, persisted_validation_data_hash: Hash); + /// Set the validation code hash of the descriptor. + fn set_validation_code_hash(&mut self, validation_code_hash: ValidationCodeHash); /// Set the erasure root of the descriptor. fn set_erasure_root(&mut self, erasure_root: Hash); /// Set the para head of the descriptor. @@ -244,6 +250,10 @@ impl MutateDescriptorV2 for CandidateDescriptorV2 { self.persisted_validation_data_hash = persisted_validation_data_hash; } + fn set_validation_code_hash(&mut self, validation_code_hash: ValidationCodeHash) { + self.validation_code_hash = validation_code_hash; + } + fn set_erasure_root(&mut self, erasure_root: Hash) { self.erasure_root = erasure_root; } @@ -424,49 +434,45 @@ pub enum UMPSignal { /// Separator between `XCM` and `UMPSignal`. pub const UMP_SEPARATOR: Vec = vec![]; -impl CandidateCommitments { - /// Returns the core selector and claim queue offset the candidate has committed to, if any. - pub fn selected_core(&self) -> Option<(CoreSelector, ClaimQueueOffset)> { - // We need at least 2 messages for the separator and core selector - if self.upward_messages.len() < 2 { - return None - } - - let separator_pos = - self.upward_messages.iter().rposition(|message| message == &UMP_SEPARATOR)?; - - // Use first commitment - let message = self.upward_messages.get(separator_pos + 1)?; +/// Utility function for skipping the ump signals. +pub fn skip_ump_signals<'a>( + upward_messages: impl Iterator>, +) -> impl Iterator> { + upward_messages.take_while(|message| *message != &UMP_SEPARATOR) +} - match UMPSignal::decode(&mut message.as_slice()).ok()? { - UMPSignal::SelectCore(core_selector, cq_offset) => Some((core_selector, cq_offset)), - } - } +impl CandidateCommitments { + /// Returns the core selector and claim queue offset determined by `UMPSignal::SelectCore` + /// commitment, if present. + pub fn core_selector( + &self, + ) -> Result, CommittedCandidateReceiptError> { + let mut signals_iter = + self.upward_messages.iter().skip_while(|message| *message != &UMP_SEPARATOR); + + if signals_iter.next().is_some() { + let Some(core_selector_message) = signals_iter.next() else { return Ok(None) }; + // We should have exactly one signal beyond the separator + if signals_iter.next().is_some() { + return Err(CommittedCandidateReceiptError::TooManyUMPSignals) + } - /// Returns the core index determined by `UMPSignal::SelectCore` commitment - /// and `assigned_cores`. - /// - /// Returns `None` if there is no `UMPSignal::SelectCore` commitment or - /// assigned cores is empty. - /// - /// `assigned_cores` must be a sorted vec of all core indices assigned to a parachain. - pub fn committed_core_index(&self, assigned_cores: &[&CoreIndex]) -> Option { - if assigned_cores.is_empty() { - return None + match UMPSignal::decode(&mut core_selector_message.as_slice()) + .map_err(|_| CommittedCandidateReceiptError::UmpSignalDecode)? + { + UMPSignal::SelectCore(core_index_selector, cq_offset) => + Ok(Some((core_index_selector, cq_offset))), + } + } else { + Ok(None) } - - self.selected_core().and_then(|(core_selector, _cq_offset)| { - let core_index = - **assigned_cores.get(core_selector.0 as usize % assigned_cores.len())?; - Some(core_index) - }) } } -/// CandidateReceipt construction errors. +/// CommittedCandidateReceiptError construction errors. #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(thiserror::Error))] -pub enum CandidateReceiptError { +pub enum CommittedCandidateReceiptError { /// The specified core index is invalid. #[cfg_attr(feature = "std", error("The specified core index is invalid"))] InvalidCoreIndex, @@ -479,6 +485,9 @@ pub enum CandidateReceiptError { /// The core selector or claim queue offset is invalid. #[cfg_attr(feature = "std", error("The core selector or claim queue offset is invalid"))] InvalidSelectedCore, + #[cfg_attr(feature = "std", error("Could not decode UMP signal"))] + /// Could not decode UMP signal. + UmpSignalDecode, /// The parachain is not assigned to any core at specified claim queue offset. #[cfg_attr( feature = "std", @@ -492,6 +501,10 @@ pub enum CandidateReceiptError { /// Unknown version. #[cfg_attr(feature = "std", error("Unknown internal version"))] UnknownVersion(InternalVersion), + /// The allowed number of `UMPSignal` messages in the queue was exceeded. + /// Currenly only one such message is allowed. + #[cfg_attr(feature = "std", error("Too many UMP signals"))] + TooManyUMPSignals, } macro_rules! impl_getter { @@ -584,57 +597,63 @@ impl CandidateDescriptorV2 { impl CommittedCandidateReceiptV2 { /// Checks if descriptor core index is equal to the committed core index. - /// Input `cores_per_para` is a claim queue snapshot stored as a mapping - /// between `ParaId` and the cores assigned per depth. + /// Input `cores_per_para` is a claim queue snapshot at the candidate's relay parent, stored as + /// a mapping between `ParaId` and the cores assigned per depth. pub fn check_core_index( &self, cores_per_para: &TransposedClaimQueue, - ) -> Result<(), CandidateReceiptError> { + ) -> Result<(), CommittedCandidateReceiptError> { match self.descriptor.version() { // Don't check v1 descriptors. CandidateDescriptorVersion::V1 => return Ok(()), CandidateDescriptorVersion::V2 => {}, CandidateDescriptorVersion::Unknown => - return Err(CandidateReceiptError::UnknownVersion(self.descriptor.version)), - } - - if cores_per_para.is_empty() { - return Err(CandidateReceiptError::NoAssignment) + return Err(CommittedCandidateReceiptError::UnknownVersion(self.descriptor.version)), } - let (offset, core_selected) = - if let Some((_core_selector, cq_offset)) = self.commitments.selected_core() { - (cq_offset.0, true) - } else { - // If no core has been selected then we use offset 0 (top of claim queue) - (0, false) - }; + let (maybe_core_index_selector, cq_offset) = self.commitments.core_selector()?.map_or_else( + || (None, ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)), + |(sel, off)| (Some(sel), off), + ); - // The cores assigned to the parachain at above computed offset. let assigned_cores = cores_per_para .get(&self.descriptor.para_id()) - .ok_or(CandidateReceiptError::NoAssignment)? - .get(&offset) - .ok_or(CandidateReceiptError::NoAssignment)? - .into_iter() - .collect::>(); - - let core_index = if core_selected { - self.commitments - .committed_core_index(assigned_cores.as_slice()) - .ok_or(CandidateReceiptError::NoAssignment)? - } else { - // `SelectCore` commitment is mandatory for elastic scaling parachains. - if assigned_cores.len() > 1 { - return Err(CandidateReceiptError::NoCoreSelected) - } + .ok_or(CommittedCandidateReceiptError::NoAssignment)? + .get(&cq_offset.0) + .ok_or(CommittedCandidateReceiptError::NoAssignment)?; - **assigned_cores.get(0).ok_or(CandidateReceiptError::NoAssignment)? - }; + if assigned_cores.is_empty() { + return Err(CommittedCandidateReceiptError::NoAssignment) + } let descriptor_core_index = CoreIndex(self.descriptor.core_index as u32); + + let core_index_selector = if let Some(core_index_selector) = maybe_core_index_selector { + // We have a committed core selector, we can use it. + core_index_selector + } else if assigned_cores.len() > 1 { + // We got more than one assigned core and no core selector. Special care is needed. + if !assigned_cores.contains(&descriptor_core_index) { + // core index in the descriptor is not assigned to the para. Error. + return Err(CommittedCandidateReceiptError::InvalidCoreIndex) + } else { + // the descriptor core index is indeed assigned to the para. This is the most we can + // check for now + return Ok(()) + } + } else { + // No core selector but there's only one assigned core, use it. + CoreSelector(0) + }; + + let core_index = assigned_cores + .iter() + .nth(core_index_selector.0 as usize % assigned_cores.len()) + .ok_or(CommittedCandidateReceiptError::InvalidSelectedCore) + .copied()?; + if core_index != descriptor_core_index { - return Err(CandidateReceiptError::CoreIndexMismatch) + return Err(CommittedCandidateReceiptError::CoreIndexMismatch) } Ok(()) @@ -1031,7 +1050,7 @@ mod tests { assert_eq!(new_ccr.descriptor.version(), CandidateDescriptorVersion::Unknown); assert_eq!( new_ccr.check_core_index(&BTreeMap::new()), - Err(CandidateReceiptError::UnknownVersion(InternalVersion(100))) + Err(CommittedCandidateReceiptError::UnknownVersion(InternalVersion(100))) ) } @@ -1069,7 +1088,6 @@ mod tests { new_ccr.descriptor.core_index = 0; new_ccr.descriptor.para_id = ParaId::new(1000); - new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); let mut cq = BTreeMap::new(); @@ -1083,7 +1101,14 @@ mod tests { new_ccr.commitments.upward_messages.force_push(vec![0, 13, 200].encode()); // No `SelectCore` can be decoded. - assert_eq!(new_ccr.commitments.selected_core(), None); + assert_eq!( + new_ccr.commitments.core_selector(), + Err(CommittedCandidateReceiptError::UmpSignalDecode) + ); + + // Has two cores assigned but no core commitment. Will pass the check if the descriptor core + // index is indeed assigned to the para. + new_ccr.commitments.upward_messages.clear(); let mut cq = BTreeMap::new(); cq.insert( @@ -1094,28 +1119,46 @@ mod tests { CoreIndex(100), vec![new_ccr.descriptor.para_id(), new_ccr.descriptor.para_id()].into(), ); + assert_eq!(new_ccr.check_core_index(&transpose_claim_queue(cq.clone())), Ok(())); + new_ccr.descriptor.set_core_index(CoreIndex(1)); assert_eq!( new_ccr.check_core_index(&transpose_claim_queue(cq.clone())), - Err(CandidateReceiptError::NoCoreSelected) + Err(CommittedCandidateReceiptError::InvalidCoreIndex) ); + new_ccr.descriptor.set_core_index(CoreIndex(0)); new_ccr.commitments.upward_messages.clear(); new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); - new_ccr .commitments .upward_messages .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(1)).encode()); - // Duplicate + // No assignments. + assert_eq!( + new_ccr.check_core_index(&transpose_claim_queue(Default::default())), + Err(CommittedCandidateReceiptError::NoAssignment) + ); + + // Mismatch between descriptor index and commitment. + new_ccr.descriptor.set_core_index(CoreIndex(1)); + assert_eq!( + new_ccr.check_core_index(&transpose_claim_queue(cq.clone())), + Err(CommittedCandidateReceiptError::CoreIndexMismatch) + ); + new_ccr.descriptor.set_core_index(CoreIndex(0)); + + // Too many UMP signals. new_ccr .commitments .upward_messages .force_push(UMPSignal::SelectCore(CoreSelector(1), ClaimQueueOffset(1)).encode()); - // Duplicate doesn't override first signal. - assert_eq!(new_ccr.check_core_index(&transpose_claim_queue(cq)), Ok(())); + assert_eq!( + new_ccr.check_core_index(&transpose_claim_queue(cq)), + Err(CommittedCandidateReceiptError::TooManyUMPSignals) + ); } #[test] @@ -1185,7 +1228,7 @@ mod tests { Decode::decode(&mut encoded_ccr.as_slice()).unwrap(); assert_eq!(v1_ccr.descriptor.version(), CandidateDescriptorVersion::V1); - assert!(v1_ccr.commitments.selected_core().is_some()); + assert!(v1_ccr.commitments.core_selector().unwrap().is_some()); let mut cq = BTreeMap::new(); cq.insert(CoreIndex(0), vec![v1_ccr.descriptor.para_id()].into()); @@ -1193,11 +1236,6 @@ mod tests { assert!(v1_ccr.check_core_index(&transpose_claim_queue(cq)).is_ok()); - assert_eq!( - v1_ccr.commitments.committed_core_index(&vec![&CoreIndex(10), &CoreIndex(5)]), - Some(CoreIndex(5)), - ); - assert_eq!(v1_ccr.descriptor.core_index(), None); } @@ -1222,11 +1260,9 @@ mod tests { cq.insert(CoreIndex(0), vec![new_ccr.descriptor.para_id()].into()); cq.insert(CoreIndex(1), vec![new_ccr.descriptor.para_id()].into()); - // Should fail because 2 cores are assigned, - assert_eq!( - new_ccr.check_core_index(&transpose_claim_queue(cq)), - Err(CandidateReceiptError::NoCoreSelected) - ); + // Passes even if 2 cores are assigned, because elastic scaling MVP could still inject the + // core index in the `BackedCandidate`. + assert_eq!(new_ccr.check_core_index(&transpose_claim_queue(cq)), Ok(())); // Adding collator signature should make it decode as v1. old_ccr.descriptor.signature = dummy_collator_signature(); diff --git a/polkadot/primitives/test-helpers/Cargo.toml b/polkadot/primitives/test-helpers/Cargo.toml index a44996ad6ef2..962b210848c8 100644 --- a/polkadot/primitives/test-helpers/Cargo.toml +++ b/polkadot/primitives/test-helpers/Cargo.toml @@ -10,9 +10,9 @@ license.workspace = true workspace = true [dependencies] -sp-keyring = { workspace = true, default-features = true } +polkadot-primitives = { features = ["test"], workspace = true, default-features = true } +rand = { workspace = true, default-features = true } sp-application-crypto = { workspace = true } -sp-runtime = { workspace = true, default-features = true } sp-core = { features = ["std"], workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -rand = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index c2eccafef788..1717dd5b0eda 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -23,13 +23,15 @@ //! Note that `dummy_` prefixed values are meant to be fillers, that should not matter, and will //! contain randomness based data. use polkadot_primitives::{ - vstaging::{CandidateDescriptorV2, CandidateReceiptV2, CommittedCandidateReceiptV2}, + vstaging::{ + CandidateDescriptorV2, CandidateReceiptV2, CommittedCandidateReceiptV2, MutateDescriptorV2, + }, CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorId, CollatorSignature, CommittedCandidateReceipt, CoreIndex, Hash, HeadData, Id as ParaId, PersistedValidationData, SessionIndex, ValidationCode, ValidationCodeHash, ValidatorId, }; pub use rand; -use sp_application_crypto::sr25519; +use sp_application_crypto::{sr25519, ByteArray}; use sp_keyring::Sr25519Keyring; use sp_runtime::generic::Digest; @@ -199,8 +201,15 @@ pub fn dummy_collator() -> CollatorId { CollatorId::from(sr25519::Public::default()) } -/// Create a meaningless collator signature. +/// Create a meaningless collator signature. It is important to not be 0, as we'd confuse +/// v1 and v2 descriptors. pub fn dummy_collator_signature() -> CollatorSignature { + CollatorSignature::from_slice(&mut (0..64).into_iter().collect::>().as_slice()) + .expect("64 bytes; qed") +} + +/// Create a zeroed collator signature. +pub fn zero_collator_signature() -> CollatorSignature { CollatorSignature::from(sr25519::Signature::default()) } @@ -250,6 +259,34 @@ pub fn make_candidate( (candidate, pvd) } +/// Create a meaningless v2 candidate, returning its receipt and PVD. +pub fn make_candidate_v2( + relay_parent_hash: Hash, + relay_parent_number: u32, + para_id: ParaId, + parent_head: HeadData, + head_data: HeadData, + validation_code_hash: ValidationCodeHash, +) -> (CommittedCandidateReceiptV2, PersistedValidationData) { + let pvd = dummy_pvd(parent_head, relay_parent_number); + let commitments = CandidateCommitments { + head_data, + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: relay_parent_number, + }; + + let mut descriptor = dummy_candidate_descriptor_v2(relay_parent_hash); + descriptor.set_para_id(para_id); + descriptor.set_persisted_validation_data_hash(pvd.hash()); + descriptor.set_validation_code_hash(validation_code_hash); + let candidate = CommittedCandidateReceiptV2 { descriptor, commitments }; + + (candidate, pvd) +} + /// Create a new candidate descriptor, and apply a valid signature /// using the provided `collator` key. pub fn make_valid_candidate_descriptor>( diff --git a/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md b/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md index 432d9ab69bab..586a4169b5bc 100644 --- a/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/node/collators/collator-protocol.md @@ -151,12 +151,6 @@ time per relay parent. This reduces the bandwidth requirements and as we can sec the others are probably not required anyway. If the request times out, we need to note the collator as being unreliable and reduce its priority relative to other collators. -As a validator, once the collation has been fetched some other subsystem will inspect and do deeper validation of the -collation. The subsystem will report to this subsystem with a [`CollatorProtocolMessage`][CPM]`::ReportCollator`. In -that case, if we are connected directly to the collator, we apply a cost to the `PeerId` associated with the collator -and potentially disconnect or blacklist it. If the collation is seconded, we notify the collator and apply a benefit to -the `PeerId` associated with the collator. - ### Interaction with [Candidate Backing][CB] As collators advertise the availability, a validator will simply second the first valid parablock candidate per relay diff --git a/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md b/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md index a3ca7347eb63..a96f3fa3d4a0 100644 --- a/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md +++ b/polkadot/roadmap/implementers-guide/src/node/subsystems-and-jobs.md @@ -129,7 +129,6 @@ digraph { cand_sel -> coll_prot [arrowhead = "diamond", label = "FetchCollation"] cand_sel -> cand_back [arrowhead = "onormal", label = "Second"] - cand_sel -> coll_prot [arrowhead = "onormal", label = "ReportCollator"] cand_val -> runt_api [arrowhead = "diamond", label = "Request::PersistedValidationData"] cand_val -> runt_api [arrowhead = "diamond", label = "Request::ValidationCode"] @@ -231,7 +230,7 @@ sequenceDiagram VS ->> CandidateSelection: Collation - Note over CandidateSelection: Lots of other machinery in play here,
but there are only three outcomes from the
perspective of the `CollatorProtocol`: + Note over CandidateSelection: Lots of other machinery in play here,
but there are only two outcomes from the
perspective of the `CollatorProtocol`: alt happy path CandidateSelection -->> VS: FetchCollation @@ -242,10 +241,6 @@ sequenceDiagram NB ->> VS: Collation Deactivate VS - else collation invalid or unexpected - CandidateSelection ->> VS: ReportCollator - VS ->> NB: ReportPeer - else CandidateSelection already selected a different candidate Note over CandidateSelection: silently drop end diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md b/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md index 64727d39fabe..0fe7fdd13653 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/provisioner.md @@ -74,9 +74,8 @@ Subsystem](../disputes/dispute-coordinator.md). Misbehavior reports are currentl subsystem](../backing/candidate-backing.md) and contain the following misbehaviors: 1. `Misbehavior::ValidityDoubleVote` -2. `Misbehavior::MultipleCandidates` -3. `Misbehavior::UnauthorizedStatement` -4. `Misbehavior::DoubleSign` +2. `Misbehavior::UnauthorizedStatement` +3. `Misbehavior::DoubleSign` But we choose not to punish these forms of misbehavior for the time being. Risks from misbehavior are sufficiently mitigated at the protocol level via reputation changes. Punitive actions here may become desirable enough to dedicate diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index 6e24d969dde4..cb862440727b 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -436,9 +436,6 @@ enum CollatorProtocolMessage { DistributeCollation(CandidateReceipt, PoV, Option>), /// Fetch a collation under the given relay-parent for the given ParaId. FetchCollation(Hash, ParaId, ResponseChannel<(CandidateReceipt, PoV)>), - /// Report a collator as having provided an invalid collation. This should lead to disconnect - /// and blacklist of the collator. - ReportCollator(CollatorId), /// Note a collator as having provided a good collation. NoteGoodCollation(CollatorId, SignedFullStatement), /// Notify a collator that its collation was seconded. @@ -697,14 +694,6 @@ mod generic { Invalidity(Digest, Signature, Signature), } - /// Misbehavior: declaring multiple candidates. - pub struct MultipleCandidates { - /// The first candidate seen. - pub first: (Candidate, Signature), - /// The second candidate seen. - pub second: (Candidate, Signature), - } - /// Misbehavior: submitted statement for wrong group. pub struct UnauthorizedStatement { /// A signed statement which was submitted without proper authority. @@ -714,8 +703,6 @@ mod generic { pub enum Misbehavior { /// Voted invalid and valid on validity. ValidityDoubleVote(ValidityDoubleVote), - /// Submitted multiple candidates. - MultipleCandidates(MultipleCandidates), /// Submitted a message that was unauthorized. UnauthorizedStatement(UnauthorizedStatement), /// Submitted two valid signatures for the same message. diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index d01528d4dee0..33ce3ff4acc6 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -5,25 +5,19 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Polkadot specific RPC functionality." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] jsonrpsee = { features = ["server"], workspace = true } +mmr-rpc = { workspace = true, default-features = true } +pallet-transaction-payment-rpc = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } -sp-consensus-babe = { workspace = true, default-features = true } -sp-consensus-beefy = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } -sc-rpc = { workspace = true, default-features = true } -sc-rpc-spec-v2 = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } sc-consensus-babe-rpc = { workspace = true, default-features = true } sc-consensus-beefy = { workspace = true, default-features = true } @@ -31,10 +25,18 @@ sc-consensus-beefy-rpc = { workspace = true, default-features = true } sc-consensus-epochs = { workspace = true, default-features = true } sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-grandpa-rpc = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-rpc-spec-v2 = { workspace = true, default-features = true } sc-sync-state-rpc = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } -substrate-frame-rpc-system = { workspace = true, default-features = true } -mmr-rpc = { workspace = true, default-features = true } -pallet-transaction-payment-rpc = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +substrate-frame-rpc-system = { workspace = true, default-features = true } substrate-state-trie-migration-rpc = { workspace = true, default-features = true } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 01b56b31cf20..4ffa5c475ed7 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -5,14 +5,16 @@ description = "Pallets and constants used in Relay Chain networks." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -impl-trait-for-tuples = { workspace = true } bitvec = { features = ["alloc"], workspace = true } codec = { features = ["derive"], workspace = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } rustc-hex = { workspace = true } scale-info = { features = ["derive"], workspace = true } @@ -21,55 +23,55 @@ serde_derive = { workspace = true } static_assertions = { workspace = true, default-features = true } sp-api = { workspace = true } +sp-core = { features = ["serde"], workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } +sp-keyring = { workspace = true } +sp-npos-elections = { features = ["serde"], workspace = true } sp-runtime = { features = ["serde"], workspace = true } sp-session = { workspace = true } sp-staking = { features = ["serde"], workspace = true } -sp-core = { features = ["serde"], workspace = true } -sp-keyring = { workspace = true } -sp-npos-elections = { features = ["serde"], workspace = true } +frame-election-provider-support = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-asset-rate = { optional = true, workspace = true } pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-broker = { workspace = true } +pallet-election-provider-multi-phase = { workspace = true } pallet-fast-unstake = { workspace = true } pallet-identity = { workspace = true } pallet-session = { workspace = true } -frame-support = { workspace = true } pallet-staking = { workspace = true } pallet-staking-reward-fn = { workspace = true } -frame-system = { workspace = true } pallet-timestamp = { workspace = true } -pallet-vesting = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-treasury = { workspace = true } -pallet-asset-rate = { optional = true, workspace = true } -pallet-election-provider-multi-phase = { workspace = true } -frame-election-provider-support = { workspace = true } +pallet-vesting = { workspace = true } frame-benchmarking = { optional = true, workspace = true } pallet-babe = { optional = true, workspace = true } -polkadot-primitives = { workspace = true } libsecp256k1 = { workspace = true } +polkadot-primitives = { workspace = true } polkadot-runtime-parachains = { workspace = true } slot-range-helper = { workspace = true } xcm = { workspace = true } -xcm-executor = { optional = true, workspace = true } xcm-builder = { workspace = true } +xcm-executor = { optional = true, workspace = true } [dev-dependencies] -hex-literal = { workspace = true, default-features = true } frame-support-test = { workspace = true } +hex-literal = { workspace = true, default-features = true } +libsecp256k1 = { workspace = true, default-features = true } pallet-babe = { workspace = true, default-features = true } pallet-treasury = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -libsecp256k1 = { workspace = true, default-features = true } polkadot-primitives-test-helpers = { workspace = true } +serde_json = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } [features] default = ["std"] @@ -140,6 +142,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index 02810b75283f..684cdcd01e14 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -5,14 +5,16 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Helper crate for generating slot ranges for the Polkadot runtime." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -paste = { workspace = true, default-features = true } -enumn = { workspace = true } codec = { features = ["derive"], workspace = true } +enumn = { workspace = true } +paste = { workspace = true, default-features = true } sp-runtime = { workspace = true } [features] diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs deleted file mode 100644 index 78f20d918bab..000000000000 --- a/polkadot/runtime/common/src/auctions.rs +++ /dev/null @@ -1,1934 +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 . - -//! Auctioning system to determine the set of Parachains in operation. This includes logic for the -//! auctioning mechanism and for reserving balance as part of the "payment". Unreserving the balance -//! happens elsewhere. - -use crate::{ - slot_range::SlotRange, - traits::{AuctionStatus, Auctioneer, LeaseError, Leaser, Registrar}, -}; -use alloc::{vec, vec::Vec}; -use codec::Decode; -use core::mem::swap; -use frame_support::{ - dispatch::DispatchResult, - ensure, - traits::{Currency, Get, Randomness, ReservableCurrency}, - weights::Weight, -}; -use frame_system::pallet_prelude::BlockNumberFor; -pub use pallet::*; -use polkadot_primitives::Id as ParaId; -use sp_runtime::traits::{CheckedSub, One, Saturating, Zero}; - -type CurrencyOf = <::Leaser as Leaser>>::Currency; -type BalanceOf = <<::Leaser as Leaser>>::Currency as Currency< - ::AccountId, ->>::Balance; - -pub trait WeightInfo { - fn new_auction() -> Weight; - fn bid() -> Weight; - fn cancel_auction() -> Weight; - fn on_initialize() -> Weight; -} - -pub struct TestWeightInfo; -impl WeightInfo for TestWeightInfo { - fn new_auction() -> Weight { - Weight::zero() - } - fn bid() -> Weight { - Weight::zero() - } - fn cancel_auction() -> Weight { - Weight::zero() - } - fn on_initialize() -> Weight { - Weight::zero() - } -} - -/// An auction index. We count auctions in this type. -pub type AuctionIndex = u32; - -type LeasePeriodOf = <::Leaser as Leaser>>::LeasePeriod; - -// Winning data type. This encodes the top bidders of each range together with their bid. -type WinningData = [Option<(::AccountId, ParaId, BalanceOf)>; - SlotRange::SLOT_RANGE_COUNT]; -// Winners data type. This encodes each of the final winners of a parachain auction, the parachain -// index assigned to them, their winning bid and the range that they won. -type WinnersData = - Vec<(::AccountId, ParaId, BalanceOf, SlotRange)>; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::{dispatch::DispatchClass, pallet_prelude::*, traits::EnsureOrigin}; - use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; - - #[pallet::pallet] - pub struct Pallet(_); - - /// The module's configuration trait. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The type representing the leasing system. - type Leaser: Leaser< - BlockNumberFor, - AccountId = Self::AccountId, - LeasePeriod = BlockNumberFor, - >; - - /// The parachain registrar type. - type Registrar: Registrar; - - /// The number of blocks over which an auction may be retroactively ended. - #[pallet::constant] - type EndingPeriod: Get>; - - /// The length of each sample to take during the ending period. - /// - /// `EndingPeriod` / `SampleLength` = Total # of Samples - #[pallet::constant] - type SampleLength: Get>; - - /// Something that provides randomness in the runtime. - type Randomness: Randomness>; - - /// The origin which may initiate auctions. - type InitiateOrigin: EnsureOrigin; - - /// Weight Information for the Extrinsics in the Pallet - type WeightInfo: WeightInfo; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// An auction started. Provides its index and the block number where it will begin to - /// close and the first lease period of the quadruplet that is auctioned. - AuctionStarted { - auction_index: AuctionIndex, - lease_period: LeasePeriodOf, - ending: BlockNumberFor, - }, - /// An auction ended. All funds become unreserved. - AuctionClosed { auction_index: AuctionIndex }, - /// Funds were reserved for a winning bid. First balance is the extra amount reserved. - /// Second is the total. - Reserved { bidder: T::AccountId, extra_reserved: BalanceOf, total_amount: BalanceOf }, - /// Funds were unreserved since bidder is no longer active. `[bidder, amount]` - Unreserved { bidder: T::AccountId, amount: BalanceOf }, - /// Someone attempted to lease the same slot twice for a parachain. The amount is held in - /// reserve but no parachain slot has been leased. - ReserveConfiscated { para_id: ParaId, leaser: T::AccountId, amount: BalanceOf }, - /// A new bid has been accepted as the current winner. - BidAccepted { - bidder: T::AccountId, - para_id: ParaId, - amount: BalanceOf, - first_slot: LeasePeriodOf, - last_slot: LeasePeriodOf, - }, - /// The winning offset was chosen for an auction. This will map into the `Winning` storage - /// map. - WinningOffset { auction_index: AuctionIndex, block_number: BlockNumberFor }, - } - - #[pallet::error] - pub enum Error { - /// This auction is already in progress. - AuctionInProgress, - /// The lease period is in the past. - LeasePeriodInPast, - /// Para is not registered - ParaNotRegistered, - /// Not a current auction. - NotCurrentAuction, - /// Not an auction. - NotAuction, - /// Auction has already ended. - AuctionEnded, - /// The para is already leased out for part of this range. - AlreadyLeasedOut, - } - - /// Number of auctions started so far. - #[pallet::storage] - pub type AuctionCounter = StorageValue<_, AuctionIndex, ValueQuery>; - - /// Information relating to the current auction, if there is one. - /// - /// The first item in the tuple is the lease period index that the first of the four - /// contiguous lease periods on auction is for. The second is the block number when the - /// auction will "begin to end", i.e. the first block of the Ending Period of the auction. - #[pallet::storage] - pub type AuctionInfo = StorageValue<_, (LeasePeriodOf, BlockNumberFor)>; - - /// Amounts currently reserved in the accounts of the bidders currently winning - /// (sub-)ranges. - #[pallet::storage] - pub type ReservedAmounts = - StorageMap<_, Twox64Concat, (T::AccountId, ParaId), BalanceOf>; - - /// The winning bids for each of the 10 ranges at each sample in the final Ending Period of - /// the current auction. The map's key is the 0-based index into the Sample Size. The - /// first sample of the ending period is 0; the last is `Sample Size - 1`. - #[pallet::storage] - pub type Winning = StorageMap<_, Twox64Concat, BlockNumberFor, WinningData>; - - #[pallet::extra_constants] - impl Pallet { - #[pallet::constant_name(SlotRangeCount)] - fn slot_range_count() -> u32 { - SlotRange::SLOT_RANGE_COUNT as u32 - } - - #[pallet::constant_name(LeasePeriodsPerSlot)] - fn lease_periods_per_slot() -> u32 { - SlotRange::LEASE_PERIODS_PER_SLOT as u32 - } - } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(n: BlockNumberFor) -> Weight { - let mut weight = T::DbWeight::get().reads(1); - - // If the current auction was in its ending period last block, then ensure that the - // (sub-)range winner information is duplicated from the previous block in case no bids - // happened in the last block. - if let AuctionStatus::EndingPeriod(offset, _sub_sample) = Self::auction_status(n) { - weight = weight.saturating_add(T::DbWeight::get().reads(1)); - if !Winning::::contains_key(&offset) { - weight = weight.saturating_add(T::DbWeight::get().writes(1)); - let winning_data = offset - .checked_sub(&One::one()) - .and_then(Winning::::get) - .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); - Winning::::insert(offset, winning_data); - } - } - - // Check to see if an auction just ended. - if let Some((winning_ranges, auction_lease_period_index)) = Self::check_auction_end(n) { - // Auction is ended now. We have the winning ranges and the lease period index which - // acts as the offset. Handle it. - Self::manage_auction_end(auction_lease_period_index, winning_ranges); - weight = weight.saturating_add(T::WeightInfo::on_initialize()); - } - - weight - } - } - - #[pallet::call] - impl Pallet { - /// Create a new auction. - /// - /// This can only happen when there isn't already an auction in progress and may only be - /// called by the root origin. Accepts the `duration` of this auction and the - /// `lease_period_index` of the initial lease period of the four that are to be auctioned. - #[pallet::call_index(0)] - #[pallet::weight((T::WeightInfo::new_auction(), DispatchClass::Operational))] - pub fn new_auction( - origin: OriginFor, - #[pallet::compact] duration: BlockNumberFor, - #[pallet::compact] lease_period_index: LeasePeriodOf, - ) -> DispatchResult { - T::InitiateOrigin::ensure_origin(origin)?; - Self::do_new_auction(duration, lease_period_index) - } - - /// Make a new bid from an account (including a parachain account) for deploying a new - /// parachain. - /// - /// Multiple simultaneous bids from the same bidder are allowed only as long as all active - /// bids overlap each other (i.e. are mutually exclusive). Bids cannot be redacted. - /// - /// - `sub` is the sub-bidder ID, allowing for multiple competing bids to be made by (and - /// funded by) the same account. - /// - `auction_index` is the index of the auction to bid on. Should just be the present - /// value of `AuctionCounter`. - /// - `first_slot` is the first lease period index of the range to bid on. This is the - /// absolute lease period index value, not an auction-specific offset. - /// - `last_slot` is the last lease period index of the range to bid on. This is the - /// absolute lease period index value, not an auction-specific offset. - /// - `amount` is the amount to bid to be held as deposit for the parachain should the - /// bid win. This amount is held throughout the range. - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::bid())] - pub fn bid( - origin: OriginFor, - #[pallet::compact] para: ParaId, - #[pallet::compact] auction_index: AuctionIndex, - #[pallet::compact] first_slot: LeasePeriodOf, - #[pallet::compact] last_slot: LeasePeriodOf, - #[pallet::compact] amount: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - Self::handle_bid(who, para, auction_index, first_slot, last_slot, amount)?; - Ok(()) - } - - /// Cancel an in-progress auction. - /// - /// Can only be called by Root origin. - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::cancel_auction())] - pub fn cancel_auction(origin: OriginFor) -> DispatchResult { - ensure_root(origin)?; - // Unreserve all bids. - for ((bidder, _), amount) in ReservedAmounts::::drain() { - CurrencyOf::::unreserve(&bidder, amount); - } - #[allow(deprecated)] - Winning::::remove_all(None); - AuctionInfo::::kill(); - Ok(()) - } - } -} - -impl Auctioneer> for Pallet { - type AccountId = T::AccountId; - type LeasePeriod = BlockNumberFor; - type Currency = CurrencyOf; - - fn new_auction( - duration: BlockNumberFor, - lease_period_index: LeasePeriodOf, - ) -> DispatchResult { - Self::do_new_auction(duration, lease_period_index) - } - - // Returns the status of the auction given the current block number. - fn auction_status(now: BlockNumberFor) -> AuctionStatus> { - let early_end = match AuctionInfo::::get() { - Some((_, early_end)) => early_end, - None => return AuctionStatus::NotStarted, - }; - - let after_early_end = match now.checked_sub(&early_end) { - Some(after_early_end) => after_early_end, - None => return AuctionStatus::StartingPeriod, - }; - - let ending_period = T::EndingPeriod::get(); - if after_early_end < ending_period { - let sample_length = T::SampleLength::get().max(One::one()); - let sample = after_early_end / sample_length; - let sub_sample = after_early_end % sample_length; - return AuctionStatus::EndingPeriod(sample, sub_sample) - } else { - // This is safe because of the comparison operator above - return AuctionStatus::VrfDelay(after_early_end - ending_period) - } - } - - fn place_bid( - bidder: T::AccountId, - para: ParaId, - first_slot: LeasePeriodOf, - last_slot: LeasePeriodOf, - amount: BalanceOf, - ) -> DispatchResult { - Self::handle_bid(bidder, para, AuctionCounter::::get(), first_slot, last_slot, amount) - } - - fn lease_period_index(b: BlockNumberFor) -> Option<(Self::LeasePeriod, bool)> { - T::Leaser::lease_period_index(b) - } - - #[cfg(any(feature = "runtime-benchmarks", test))] - fn lease_period_length() -> (BlockNumberFor, BlockNumberFor) { - T::Leaser::lease_period_length() - } - - fn has_won_an_auction(para: ParaId, bidder: &T::AccountId) -> bool { - !T::Leaser::deposit_held(para, bidder).is_zero() - } -} - -impl Pallet { - // A trick to allow me to initialize large arrays with nothing in them. - const EMPTY: Option<(::AccountId, ParaId, BalanceOf)> = None; - - /// Create a new auction. - /// - /// This can only happen when there isn't already an auction in progress. Accepts the `duration` - /// of this auction and the `lease_period_index` of the initial lease period of the four that - /// are to be auctioned. - fn do_new_auction( - duration: BlockNumberFor, - lease_period_index: LeasePeriodOf, - ) -> DispatchResult { - let maybe_auction = AuctionInfo::::get(); - ensure!(maybe_auction.is_none(), Error::::AuctionInProgress); - let now = frame_system::Pallet::::block_number(); - if let Some((current_lease_period, _)) = T::Leaser::lease_period_index(now) { - // If there is no active lease period, then we don't need to make this check. - ensure!(lease_period_index >= current_lease_period, Error::::LeasePeriodInPast); - } - - // Bump the counter. - let n = AuctionCounter::::mutate(|n| { - *n += 1; - *n - }); - - // Set the information. - let ending = frame_system::Pallet::::block_number().saturating_add(duration); - AuctionInfo::::put((lease_period_index, ending)); - - Self::deposit_event(Event::::AuctionStarted { - auction_index: n, - lease_period: lease_period_index, - ending, - }); - Ok(()) - } - - /// Actually place a bid in the current auction. - /// - /// - `bidder`: The account that will be funding this bid. - /// - `auction_index`: The auction index of the bid. For this to succeed, must equal - /// the current value of `AuctionCounter`. - /// - `first_slot`: The first lease period index of the range to be bid on. - /// - `last_slot`: The last lease period index of the range to be bid on (inclusive). - /// - `amount`: The total amount to be the bid for deposit over the range. - pub fn handle_bid( - bidder: T::AccountId, - para: ParaId, - auction_index: u32, - first_slot: LeasePeriodOf, - last_slot: LeasePeriodOf, - amount: BalanceOf, - ) -> DispatchResult { - // Ensure para is registered before placing a bid on it. - ensure!(T::Registrar::is_registered(para), Error::::ParaNotRegistered); - // Bidding on latest auction. - ensure!(auction_index == AuctionCounter::::get(), Error::::NotCurrentAuction); - // Assume it's actually an auction (this should never fail because of above). - let (first_lease_period, _) = AuctionInfo::::get().ok_or(Error::::NotAuction)?; - - // Get the auction status and the current sample block. For the starting period, the sample - // block is zero. - let auction_status = Self::auction_status(frame_system::Pallet::::block_number()); - // The offset into the ending samples of the auction. - let offset = match auction_status { - AuctionStatus::NotStarted => return Err(Error::::AuctionEnded.into()), - AuctionStatus::StartingPeriod => Zero::zero(), - AuctionStatus::EndingPeriod(o, _) => o, - AuctionStatus::VrfDelay(_) => return Err(Error::::AuctionEnded.into()), - }; - - // We also make sure that the bid is not for any existing leases the para already has. - ensure!( - !T::Leaser::already_leased(para, first_slot, last_slot), - Error::::AlreadyLeasedOut - ); - - // Our range. - let range = SlotRange::new_bounded(first_lease_period, first_slot, last_slot)?; - // Range as an array index. - let range_index = range as u8 as usize; - - // The current winning ranges. - let mut current_winning = Winning::::get(offset) - .or_else(|| offset.checked_sub(&One::one()).and_then(Winning::::get)) - .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); - - // If this bid beat the previous winner of our range. - if current_winning[range_index].as_ref().map_or(true, |last| amount > last.2) { - // Ok; we are the new winner of this range - reserve the additional amount and record. - - // Get the amount already held on deposit if this is a renewal bid (i.e. there's - // an existing lease on the same para by the same leaser). - let existing_lease_deposit = T::Leaser::deposit_held(para, &bidder); - let reserve_required = amount.saturating_sub(existing_lease_deposit); - - // Get the amount already reserved in any prior and still active bids by us. - let bidder_para = (bidder.clone(), para); - let already_reserved = ReservedAmounts::::get(&bidder_para).unwrap_or_default(); - - // If these don't already cover the bid... - if let Some(additional) = reserve_required.checked_sub(&already_reserved) { - // ...then reserve some more funds from their account, failing if there's not - // enough funds. - CurrencyOf::::reserve(&bidder, additional)?; - // ...and record the amount reserved. - ReservedAmounts::::insert(&bidder_para, reserve_required); - - Self::deposit_event(Event::::Reserved { - bidder: bidder.clone(), - extra_reserved: additional, - total_amount: reserve_required, - }); - } - - // Return any funds reserved for the previous winner if we are not in the ending period - // and they no longer have any active bids. - let mut outgoing_winner = Some((bidder.clone(), para, amount)); - swap(&mut current_winning[range_index], &mut outgoing_winner); - if let Some((who, para, _amount)) = outgoing_winner { - if auction_status.is_starting() && - current_winning - .iter() - .filter_map(Option::as_ref) - .all(|&(ref other, other_para, _)| other != &who || other_para != para) - { - // Previous bidder is no longer winning any ranges: unreserve their funds. - if let Some(amount) = ReservedAmounts::::take(&(who.clone(), para)) { - // It really should be reserved; there's not much we can do here on fail. - let err_amt = CurrencyOf::::unreserve(&who, amount); - debug_assert!(err_amt.is_zero()); - Self::deposit_event(Event::::Unreserved { bidder: who, amount }); - } - } - } - - // Update the range winner. - Winning::::insert(offset, ¤t_winning); - Self::deposit_event(Event::::BidAccepted { - bidder, - para_id: para, - amount, - first_slot, - last_slot, - }); - } - Ok(()) - } - - /// Some when the auction's end is known (with the end block number). None if it is unknown. - /// If `Some` then the block number must be at most the previous block and at least the - /// previous block minus `T::EndingPeriod::get()`. - /// - /// This mutates the state, cleaning up `AuctionInfo` and `Winning` in the case of an auction - /// ending. An immediately subsequent call with the same argument will always return `None`. - fn check_auction_end(now: BlockNumberFor) -> Option<(WinningData, LeasePeriodOf)> { - if let Some((lease_period_index, early_end)) = AuctionInfo::::get() { - let ending_period = T::EndingPeriod::get(); - let late_end = early_end.saturating_add(ending_period); - let is_ended = now >= late_end; - if is_ended { - // auction definitely ended. - // check to see if we can determine the actual ending point. - let (raw_offset, known_since) = T::Randomness::random(&b"para_auction"[..]); - - if late_end <= known_since { - // Our random seed was known only after the auction ended. Good to use. - let raw_offset_block_number = >::decode( - &mut raw_offset.as_ref(), - ) - .expect("secure hashes should always be bigger than the block number; qed"); - let offset = (raw_offset_block_number % ending_period) / - T::SampleLength::get().max(One::one()); - - let auction_counter = AuctionCounter::::get(); - Self::deposit_event(Event::::WinningOffset { - auction_index: auction_counter, - block_number: offset, - }); - let res = Winning::::get(offset) - .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); - // This `remove_all` statement should remove at most `EndingPeriod` / - // `SampleLength` items, which should be bounded and sensibly configured in the - // runtime. - #[allow(deprecated)] - Winning::::remove_all(None); - AuctionInfo::::kill(); - return Some((res, lease_period_index)) - } - } - } - None - } - - /// Auction just ended. We have the current lease period, the auction's lease period (which - /// is guaranteed to be at least the current period) and the bidders that were winning each - /// range at the time of the auction's close. - fn manage_auction_end( - auction_lease_period_index: LeasePeriodOf, - winning_ranges: WinningData, - ) { - // First, unreserve all amounts that were reserved for the bids. We will later re-reserve - // the amounts from the bidders that ended up being assigned the slot so there's no need to - // special-case them here. - for ((bidder, _), amount) in ReservedAmounts::::drain() { - CurrencyOf::::unreserve(&bidder, amount); - } - - // Next, calculate the winning combination of slots and thus the final winners of the - // auction. - let winners = Self::calculate_winners(winning_ranges); - - // Go through those winners and re-reserve their bid, updating our table of deposits - // accordingly. - for (leaser, para, amount, range) in winners.into_iter() { - let begin_offset = LeasePeriodOf::::from(range.as_pair().0 as u32); - let period_begin = auction_lease_period_index + begin_offset; - let period_count = LeasePeriodOf::::from(range.len() as u32); - - match T::Leaser::lease_out(para, &leaser, amount, period_begin, period_count) { - Err(LeaseError::ReserveFailed) | - Err(LeaseError::AlreadyEnded) | - Err(LeaseError::NoLeasePeriod) => { - // Should never happen since we just unreserved this amount (and our offset is - // from the present period). But if it does, there's not much we can do. - }, - Err(LeaseError::AlreadyLeased) => { - // The leaser attempted to get a second lease on the same para ID, possibly - // griefing us. Let's keep the amount reserved and let governance sort it out. - if CurrencyOf::::reserve(&leaser, amount).is_ok() { - Self::deposit_event(Event::::ReserveConfiscated { - para_id: para, - leaser, - amount, - }); - } - }, - Ok(()) => {}, // Nothing to report. - } - } - - Self::deposit_event(Event::::AuctionClosed { - auction_index: AuctionCounter::::get(), - }); - } - - /// Calculate the final winners from the winning slots. - /// - /// This is a simple dynamic programming algorithm designed by Al, the original code is at: - /// `https://github.com/w3f/consensus/blob/master/NPoS/auctiondynamicthing.py` - fn calculate_winners(mut winning: WinningData) -> WinnersData { - let winning_ranges = { - let mut best_winners_ending_at: [(Vec, BalanceOf); - SlotRange::LEASE_PERIODS_PER_SLOT] = Default::default(); - let best_bid = |range: SlotRange| { - winning[range as u8 as usize] - .as_ref() - .map(|(_, _, amount)| *amount * (range.len() as u32).into()) - }; - for i in 0..SlotRange::LEASE_PERIODS_PER_SLOT { - let r = SlotRange::new_bounded(0, 0, i as u32).expect("`i < LPPS`; qed"); - if let Some(bid) = best_bid(r) { - best_winners_ending_at[i] = (vec![r], bid); - } - for j in 0..i { - let r = SlotRange::new_bounded(0, j as u32 + 1, i as u32) - .expect("`i < LPPS`; `j < i`; `j + 1 < LPPS`; qed"); - if let Some(mut bid) = best_bid(r) { - bid += best_winners_ending_at[j].1; - if bid > best_winners_ending_at[i].1 { - let mut new_winners = best_winners_ending_at[j].0.clone(); - new_winners.push(r); - best_winners_ending_at[i] = (new_winners, bid); - } - } else { - if best_winners_ending_at[j].1 > best_winners_ending_at[i].1 { - best_winners_ending_at[i] = best_winners_ending_at[j].clone(); - } - } - } - } - best_winners_ending_at[SlotRange::LEASE_PERIODS_PER_SLOT - 1].0.clone() - }; - - winning_ranges - .into_iter() - .filter_map(|range| { - winning[range as u8 as usize] - .take() - .map(|(bidder, para, amount)| (bidder, para, amount, range)) - }) - .collect::>() - } -} - -/// tests for this module -#[cfg(test)] -mod tests { - use super::*; - use crate::{auctions, mock::TestRegistrar}; - use frame_support::{ - assert_noop, assert_ok, assert_storage_noop, derive_impl, ord_parameter_types, - parameter_types, - traits::{EitherOfDiverse, OnFinalize, OnInitialize}, - }; - use frame_system::{EnsureRoot, EnsureSignedBy}; - use pallet_balances; - use polkadot_primitives::{BlockNumber, Id as ParaId}; - use polkadot_primitives_test_helpers::{dummy_hash, dummy_head_data, dummy_validation_code}; - use sp_core::H256; - use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, - DispatchError::BadOrigin, - }; - use std::{cell::RefCell, collections::BTreeMap}; - - type Block = frame_system::mocking::MockBlockU32; - - frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Auctions: auctions, - } - ); - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] - impl pallet_balances::Config for Test { - type AccountStore = System; - } - - #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] - pub struct LeaseData { - leaser: u64, - amount: u64, - } - - thread_local! { - pub static LEASES: - RefCell> = RefCell::new(BTreeMap::new()); - } - - fn leases() -> Vec<((ParaId, BlockNumber), LeaseData)> { - LEASES.with(|p| (&*p.borrow()).clone().into_iter().collect::>()) - } - - pub struct TestLeaser; - impl Leaser for TestLeaser { - type AccountId = u64; - type LeasePeriod = BlockNumber; - type Currency = Balances; - - fn lease_out( - para: ParaId, - leaser: &Self::AccountId, - amount: >::Balance, - period_begin: Self::LeasePeriod, - period_count: Self::LeasePeriod, - ) -> Result<(), LeaseError> { - LEASES.with(|l| { - let mut leases = l.borrow_mut(); - let now = System::block_number(); - let (current_lease_period, _) = - Self::lease_period_index(now).ok_or(LeaseError::NoLeasePeriod)?; - if period_begin < current_lease_period { - return Err(LeaseError::AlreadyEnded) - } - for period in period_begin..(period_begin + period_count) { - if leases.contains_key(&(para, period)) { - return Err(LeaseError::AlreadyLeased) - } - leases.insert((para, period), LeaseData { leaser: *leaser, amount }); - } - Ok(()) - }) - } - - fn deposit_held( - para: ParaId, - leaser: &Self::AccountId, - ) -> >::Balance { - leases() - .iter() - .filter_map(|((id, _period), data)| { - if id == ¶ && &data.leaser == leaser { - Some(data.amount) - } else { - None - } - }) - .max() - .unwrap_or_default() - } - - fn lease_period_length() -> (BlockNumber, BlockNumber) { - (10, 0) - } - - fn lease_period_index(b: BlockNumber) -> Option<(Self::LeasePeriod, bool)> { - let (lease_period_length, offset) = Self::lease_period_length(); - let b = b.checked_sub(offset)?; - - let lease_period = b / lease_period_length; - let first_block = (b % lease_period_length).is_zero(); - - Some((lease_period, first_block)) - } - - fn already_leased( - para_id: ParaId, - first_period: Self::LeasePeriod, - last_period: Self::LeasePeriod, - ) -> bool { - leases().into_iter().any(|((para, period), _data)| { - para == para_id && first_period <= period && period <= last_period - }) - } - } - - ord_parameter_types! { - pub const Six: u64 = 6; - } - - type RootOrSix = EitherOfDiverse, EnsureSignedBy>; - - thread_local! { - pub static LAST_RANDOM: RefCell> = RefCell::new(None); - } - fn set_last_random(output: H256, known_since: u32) { - LAST_RANDOM.with(|p| *p.borrow_mut() = Some((output, known_since))) - } - pub struct TestPastRandomness; - impl Randomness for TestPastRandomness { - fn random(_subject: &[u8]) -> (H256, u32) { - LAST_RANDOM.with(|p| { - if let Some((output, known_since)) = &*p.borrow() { - (*output, *known_since) - } else { - (H256::zero(), frame_system::Pallet::::block_number()) - } - }) - } - } - - parameter_types! { - pub static EndingPeriod: BlockNumber = 3; - pub static SampleLength: BlockNumber = 1; - } - - impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Leaser = TestLeaser; - type Registrar = TestRegistrar; - type EndingPeriod = EndingPeriod; - type SampleLength = SampleLength; - type Randomness = TestPastRandomness; - type InitiateOrigin = RootOrSix; - type WeightInfo = crate::auctions::TestWeightInfo; - } - - // This function basically just builds a genesis storage key/value store according to - // our desired mock up. - pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext: sp_io::TestExternalities = t.into(); - ext.execute_with(|| { - // Register para 0, 1, 2, and 3 for tests - assert_ok!(TestRegistrar::::register( - 1, - 0.into(), - dummy_head_data(), - dummy_validation_code() - )); - assert_ok!(TestRegistrar::::register( - 1, - 1.into(), - dummy_head_data(), - dummy_validation_code() - )); - assert_ok!(TestRegistrar::::register( - 1, - 2.into(), - dummy_head_data(), - dummy_validation_code() - )); - assert_ok!(TestRegistrar::::register( - 1, - 3.into(), - dummy_head_data(), - dummy_validation_code() - )); - }); - ext - } - - fn run_to_block(n: BlockNumber) { - while System::block_number() < n { - Auctions::on_finalize(System::block_number()); - Balances::on_finalize(System::block_number()); - System::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - System::on_initialize(System::block_number()); - Balances::on_initialize(System::block_number()); - Auctions::on_initialize(System::block_number()); - } - } - - #[test] - fn basic_setup_works() { - new_test_ext().execute_with(|| { - assert_eq!(AuctionCounter::::get(), 0); - assert_eq!(TestLeaser::deposit_held(0u32.into(), &1), 0); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - - run_to_block(10); - - assert_eq!(AuctionCounter::::get(), 0); - assert_eq!(TestLeaser::deposit_held(0u32.into(), &1), 0); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - }); - } - - #[test] - fn can_start_auction() { - new_test_ext().execute_with(|| { - run_to_block(1); - - assert_noop!(Auctions::new_auction(RuntimeOrigin::signed(1), 5, 1), BadOrigin); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - - assert_eq!(AuctionCounter::::get(), 1); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - }); - } - - #[test] - fn bidding_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 5)); - - assert_eq!(Balances::reserved_balance(1), 5); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!( - Winning::::get(0).unwrap()[SlotRange::ZeroThree as u8 as usize], - Some((1, 0.into(), 5)) - ); - }); - } - - #[test] - fn under_bidding_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 5)); - - assert_storage_noop!({ - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 0.into(), 1, 1, 4, 1)); - }); - }); - } - - #[test] - fn over_bidding_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 5)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 0.into(), 1, 1, 4, 6)); - - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::reserved_balance(2), 6); - assert_eq!(Balances::free_balance(2), 14); - assert_eq!( - Winning::::get(0).unwrap()[SlotRange::ZeroThree as u8 as usize], - Some((2, 0.into(), 6)) - ); - }); - } - - #[test] - fn auction_proceeds_correctly() { - new_test_ext().execute_with(|| { - run_to_block(1); - - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - - assert_eq!(AuctionCounter::::get(), 1); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(2); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(3); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(4); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(5); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(6); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(0, 0) - ); - - run_to_block(7); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(1, 0) - ); - - run_to_block(8); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(2, 0) - ); - - run_to_block(9); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - }); - } - - #[test] - fn can_win_auction() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 1)); - assert_eq!(Balances::reserved_balance(1), 1); - assert_eq!(Balances::free_balance(1), 9); - run_to_block(9); - - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 2), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 3), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 4), LeaseData { leaser: 1, amount: 1 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); - }); - } - - #[test] - fn can_win_auction_with_late_randomness() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 1)); - assert_eq!(Balances::reserved_balance(1), 1); - assert_eq!(Balances::free_balance(1), 9); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - run_to_block(8); - // Auction has not yet ended. - assert_eq!(leases(), vec![]); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(2, 0) - ); - // This will prevent the auction's winner from being decided in the next block, since - // the random seed was known before the final bids were made. - set_last_random(H256::zero(), 8); - // Auction definitely ended now, but we don't know exactly when in the last 3 blocks yet - // since no randomness available yet. - run_to_block(9); - // Auction has now ended... But auction winner still not yet decided, so no leases yet. - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::VrfDelay(0) - ); - assert_eq!(leases(), vec![]); - - // Random seed now updated to a value known at block 9, when the auction ended. This - // means that the winner can now be chosen. - set_last_random(H256::zero(), 9); - run_to_block(10); - // Auction ended and winner selected - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 2), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 3), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 4), LeaseData { leaser: 1, amount: 1 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); - }); - } - - #[test] - fn can_win_incomplete_auction() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 4, 4, 5)); - run_to_block(9); - - assert_eq!(leases(), vec![((0.into(), 4), LeaseData { leaser: 1, amount: 5 }),]); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); - }); - } - - #[test] - fn should_choose_best_combination() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 0.into(), 1, 2, 3, 4)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), 0.into(), 1, 4, 4, 2)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 1.into(), 1, 1, 4, 2)); - run_to_block(9); - - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 2), LeaseData { leaser: 2, amount: 4 }), - ((0.into(), 3), LeaseData { leaser: 2, amount: 4 }), - ((0.into(), 4), LeaseData { leaser: 3, amount: 2 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); - assert_eq!(TestLeaser::deposit_held(1.into(), &1), 0); - assert_eq!(TestLeaser::deposit_held(0.into(), &2), 4); - assert_eq!(TestLeaser::deposit_held(0.into(), &3), 2); - }); - } - - #[test] - fn gap_bid_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - - // User 1 will make a bid for period 1 and 4 for the same Para 0 - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 4, 4, 4)); - - // User 2 and 3 will make a bid for para 1 on period 2 and 3 respectively - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 1.into(), 1, 2, 2, 2)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), 1.into(), 1, 3, 3, 3)); - - // Total reserved should be the max of the two - assert_eq!(Balances::reserved_balance(1), 4); - - // Other people are reserved correctly too - assert_eq!(Balances::reserved_balance(2), 2); - assert_eq!(Balances::reserved_balance(3), 3); - - // End the auction. - run_to_block(9); - - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 4), LeaseData { leaser: 1, amount: 4 }), - ((1.into(), 2), LeaseData { leaser: 2, amount: 2 }), - ((1.into(), 3), LeaseData { leaser: 3, amount: 3 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 4); - assert_eq!(TestLeaser::deposit_held(1.into(), &2), 2); - assert_eq!(TestLeaser::deposit_held(1.into(), &3), 3); - }); - } - - #[test] - fn deposit_credit_should_work() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 5)); - assert_eq!(Balances::reserved_balance(1), 5); - run_to_block(10); - - assert_eq!(leases(), vec![((0.into(), 1), LeaseData { leaser: 1, amount: 5 }),]); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); - - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 2)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 2, 2, 6)); - // Only 1 reserved since we have a deposit credit of 5. - assert_eq!(Balances::reserved_balance(1), 1); - run_to_block(20); - - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 1, amount: 5 }), - ((0.into(), 2), LeaseData { leaser: 1, amount: 6 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 6); - }); - } - - #[test] - fn deposit_credit_on_alt_para_should_not_count() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 5)); - assert_eq!(Balances::reserved_balance(1), 5); - run_to_block(10); - - assert_eq!(leases(), vec![((0.into(), 1), LeaseData { leaser: 1, amount: 5 }),]); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); - - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 2)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 1.into(), 2, 2, 2, 6)); - // 6 reserved since we are bidding on a new para; only works because we don't - assert_eq!(Balances::reserved_balance(1), 6); - run_to_block(20); - - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 1, amount: 5 }), - ((1.into(), 2), LeaseData { leaser: 1, amount: 6 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); - assert_eq!(TestLeaser::deposit_held(1.into(), &1), 6); - }); - } - - #[test] - fn multiple_bids_work_pre_ending() { - new_test_ext().execute_with(|| { - run_to_block(1); - - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - - for i in 1..6u64 { - run_to_block(i as _); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(i), 0.into(), 1, 1, 4, i)); - for j in 1..6 { - assert_eq!(Balances::reserved_balance(j), if j == i { j } else { 0 }); - assert_eq!(Balances::free_balance(j), if j == i { j * 9 } else { j * 10 }); - } - } - - run_to_block(9); - assert_eq!( - leases(), - vec![ - ((0.into(), 1), LeaseData { leaser: 5, amount: 5 }), - ((0.into(), 2), LeaseData { leaser: 5, amount: 5 }), - ((0.into(), 3), LeaseData { leaser: 5, amount: 5 }), - ((0.into(), 4), LeaseData { leaser: 5, amount: 5 }), - ] - ); - }); - } - - #[test] - fn multiple_bids_work_post_ending() { - new_test_ext().execute_with(|| { - run_to_block(1); - - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 0, 1)); - - for i in 1..6u64 { - run_to_block(((i - 1) / 2 + 1) as _); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(i), 0.into(), 1, 1, 4, i)); - for j in 1..6 { - assert_eq!(Balances::reserved_balance(j), if j <= i { j } else { 0 }); - assert_eq!(Balances::free_balance(j), if j <= i { j * 9 } else { j * 10 }); - } - } - for i in 1..6u64 { - assert_eq!(ReservedAmounts::::get((i, ParaId::from(0))).unwrap(), i); - } - - run_to_block(5); - assert_eq!( - leases(), - (1..=4) - .map(|i| ((0.into(), i), LeaseData { leaser: 2, amount: 2 })) - .collect::>() - ); - }); - } - - #[test] - fn incomplete_calculate_winners_works() { - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[SlotRange::ThreeThree as u8 as usize] = Some((1, 0.into(), 1)); - - let winners = vec![(1, 0.into(), 1, SlotRange::ThreeThree)]; - - assert_eq!(Auctions::calculate_winners(winning), winners); - } - - #[test] - fn first_incomplete_calculate_winners_works() { - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[0] = Some((1, 0.into(), 1)); - - let winners = vec![(1, 0.into(), 1, SlotRange::ZeroZero)]; - - assert_eq!(Auctions::calculate_winners(winning), winners); - } - - #[test] - fn calculate_winners_works() { - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[SlotRange::ZeroZero as u8 as usize] = Some((2, 0.into(), 2)); - winning[SlotRange::ZeroThree as u8 as usize] = Some((1, 100.into(), 1)); - winning[SlotRange::OneOne as u8 as usize] = Some((3, 1.into(), 1)); - winning[SlotRange::TwoTwo as u8 as usize] = Some((1, 2.into(), 53)); - winning[SlotRange::ThreeThree as u8 as usize] = Some((5, 3.into(), 1)); - - let winners = vec![ - (2, 0.into(), 2, SlotRange::ZeroZero), - (3, 1.into(), 1, SlotRange::OneOne), - (1, 2.into(), 53, SlotRange::TwoTwo), - (5, 3.into(), 1, SlotRange::ThreeThree), - ]; - assert_eq!(Auctions::calculate_winners(winning), winners); - - winning[SlotRange::ZeroOne as u8 as usize] = Some((4, 10.into(), 3)); - let winners = vec![ - (4, 10.into(), 3, SlotRange::ZeroOne), - (1, 2.into(), 53, SlotRange::TwoTwo), - (5, 3.into(), 1, SlotRange::ThreeThree), - ]; - assert_eq!(Auctions::calculate_winners(winning), winners); - - winning[SlotRange::ZeroThree as u8 as usize] = Some((1, 100.into(), 100)); - let winners = vec![(1, 100.into(), 100, SlotRange::ZeroThree)]; - assert_eq!(Auctions::calculate_winners(winning), winners); - } - - #[test] - fn lower_bids_are_correctly_refunded() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 1, 1)); - let para_1 = ParaId::from(1_u32); - let para_2 = ParaId::from(2_u32); - - // Make a bid and reserve a balance - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), para_1, 1, 1, 4, 9)); - assert_eq!(Balances::reserved_balance(1), 9); - assert_eq!(ReservedAmounts::::get((1, para_1)), Some(9)); - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(ReservedAmounts::::get((2, para_2)), None); - - // Bigger bid, reserves new balance and returns funds - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), para_2, 1, 1, 4, 19)); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(ReservedAmounts::::get((1, para_1)), None); - assert_eq!(Balances::reserved_balance(2), 19); - assert_eq!(ReservedAmounts::::get((2, para_2)), Some(19)); - }); - } - - #[test] - fn initialize_winners_in_ending_period_works() { - new_test_ext().execute_with(|| { - let ed: u64 = ::ExistentialDeposit::get(); - assert_eq!(ed, 1); - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 9, 1)); - let para_1 = ParaId::from(1_u32); - let para_2 = ParaId::from(2_u32); - let para_3 = ParaId::from(3_u32); - - // Make bids - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), para_1, 1, 1, 4, 9)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), para_2, 1, 3, 4, 19)); - - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[SlotRange::ZeroThree as u8 as usize] = Some((1, para_1, 9)); - winning[SlotRange::TwoThree as u8 as usize] = Some((2, para_2, 19)); - assert_eq!(Winning::::get(0), Some(winning)); - - run_to_block(9); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(10); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(0, 0) - ); - assert_eq!(Winning::::get(0), Some(winning)); - - run_to_block(11); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(1, 0) - ); - assert_eq!(Winning::::get(1), Some(winning)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), para_3, 1, 3, 4, 29)); - - run_to_block(12); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(2, 0) - ); - winning[SlotRange::TwoThree as u8 as usize] = Some((3, para_3, 29)); - assert_eq!(Winning::::get(2), Some(winning)); - }); - } - - #[test] - fn handle_bid_requires_registered_para() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_noop!( - Auctions::bid(RuntimeOrigin::signed(1), 1337.into(), 1, 1, 4, 1), - Error::::ParaNotRegistered - ); - assert_ok!(TestRegistrar::::register( - 1, - 1337.into(), - dummy_head_data(), - dummy_validation_code() - )); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 1337.into(), 1, 1, 4, 1)); - }); - } - - #[test] - fn handle_bid_checks_existing_lease_periods() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 2, 3, 1)); - assert_eq!(Balances::reserved_balance(1), 1); - assert_eq!(Balances::free_balance(1), 9); - run_to_block(9); - - assert_eq!( - leases(), - vec![ - ((0.into(), 2), LeaseData { leaser: 1, amount: 1 }), - ((0.into(), 3), LeaseData { leaser: 1, amount: 1 }), - ] - ); - assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); - - // Para 1 just won an auction above and won some lease periods. - // No bids can work which overlap these periods. - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_noop!( - Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 1, 4, 1), - Error::::AlreadyLeasedOut, - ); - assert_noop!( - Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 1, 2, 1), - Error::::AlreadyLeasedOut, - ); - assert_noop!( - Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 3, 4, 1), - Error::::AlreadyLeasedOut, - ); - // This is okay, not an overlapping bid. - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 1, 1, 1)); - }); - } - - // Here we will test that taking only 10 samples during the ending period works as expected. - #[test] - fn less_winning_samples_work() { - new_test_ext().execute_with(|| { - let ed: u64 = ::ExistentialDeposit::get(); - assert_eq!(ed, 1); - EndingPeriod::set(30); - SampleLength::set(10); - - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 9, 11)); - let para_1 = ParaId::from(1_u32); - let para_2 = ParaId::from(2_u32); - let para_3 = ParaId::from(3_u32); - - // Make bids - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), para_1, 1, 11, 14, 9)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), para_2, 1, 13, 14, 19)); - - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; - winning[SlotRange::ZeroThree as u8 as usize] = Some((1, para_1, 9)); - winning[SlotRange::TwoThree as u8 as usize] = Some((2, para_2, 19)); - assert_eq!(Winning::::get(0), Some(winning)); - - run_to_block(9); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(10); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(0, 0) - ); - assert_eq!(Winning::::get(0), Some(winning)); - - // New bids update the current winning - assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), para_3, 1, 14, 14, 29)); - winning[SlotRange::ThreeThree as u8 as usize] = Some((3, para_3, 29)); - assert_eq!(Winning::::get(0), Some(winning)); - - run_to_block(20); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(1, 0) - ); - assert_eq!(Winning::::get(1), Some(winning)); - run_to_block(25); - // Overbid mid sample - assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), para_3, 1, 13, 14, 29)); - winning[SlotRange::TwoThree as u8 as usize] = Some((3, para_3, 29)); - assert_eq!(Winning::::get(1), Some(winning)); - - run_to_block(30); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(2, 0) - ); - assert_eq!(Winning::::get(2), Some(winning)); - - set_last_random(H256::from([254; 32]), 40); - run_to_block(40); - // Auction ended and winner selected - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - assert_eq!( - leases(), - vec![ - ((3.into(), 13), LeaseData { leaser: 3, amount: 29 }), - ((3.into(), 14), LeaseData { leaser: 3, amount: 29 }), - ] - ); - }); - } - - #[test] - fn auction_status_works() { - new_test_ext().execute_with(|| { - EndingPeriod::set(30); - SampleLength::set(10); - set_last_random(dummy_hash(), 0); - - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 9, 11)); - - run_to_block(9); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::StartingPeriod - ); - - run_to_block(10); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(0, 0) - ); - - run_to_block(11); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(0, 1) - ); - - run_to_block(19); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(0, 9) - ); - - run_to_block(20); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(1, 0) - ); - - run_to_block(25); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(1, 5) - ); - - run_to_block(30); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(2, 0) - ); - - run_to_block(39); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::EndingPeriod(2, 9) - ); - - run_to_block(40); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::VrfDelay(0) - ); - - run_to_block(44); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::VrfDelay(4) - ); - - set_last_random(dummy_hash(), 45); - run_to_block(45); - assert_eq!( - Auctions::auction_status(System::block_number()), - AuctionStatus::::NotStarted - ); - }); - } - - #[test] - fn can_cancel_auction() { - new_test_ext().execute_with(|| { - run_to_block(1); - assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); - assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 1)); - assert_eq!(Balances::reserved_balance(1), 1); - assert_eq!(Balances::free_balance(1), 9); - - assert_noop!(Auctions::cancel_auction(RuntimeOrigin::signed(6)), BadOrigin); - assert_ok!(Auctions::cancel_auction(RuntimeOrigin::root())); - - assert!(AuctionInfo::::get().is_none()); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(ReservedAmounts::::iter().count(), 0); - assert_eq!(Winning::::iter().count(), 0); - }); - } -} - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking { - use super::{Pallet as Auctions, *}; - use frame_support::{ - assert_ok, - traits::{EnsureOrigin, OnInitialize}, - }; - use frame_system::RawOrigin; - use polkadot_runtime_parachains::paras; - use sp_runtime::{traits::Bounded, SaturatedConversion}; - - use frame_benchmarking::{account, benchmarks, whitelisted_caller, BenchmarkError}; - - fn assert_last_event(generic_event: ::RuntimeEvent) { - let events = frame_system::Pallet::::events(); - let system_event: ::RuntimeEvent = generic_event.into(); - // compare to the last event record - let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; - assert_eq!(event, &system_event); - } - - fn fill_winners(lease_period_index: LeasePeriodOf) { - let auction_index = AuctionCounter::::get(); - let minimum_balance = CurrencyOf::::minimum_balance(); - - for n in 1..=SlotRange::SLOT_RANGE_COUNT as u32 { - let owner = account("owner", n, 0); - let worst_validation_code = T::Registrar::worst_validation_code(); - let worst_head_data = T::Registrar::worst_head_data(); - CurrencyOf::::make_free_balance_be(&owner, BalanceOf::::max_value()); - - assert!(T::Registrar::register( - owner, - ParaId::from(n), - worst_head_data, - worst_validation_code - ) - .is_ok()); - } - assert_ok!(paras::Pallet::::add_trusted_validation_code( - frame_system::Origin::::Root.into(), - T::Registrar::worst_validation_code(), - )); - - T::Registrar::execute_pending_transitions(); - - for n in 1..=SlotRange::SLOT_RANGE_COUNT as u32 { - let bidder = account("bidder", n, 0); - CurrencyOf::::make_free_balance_be(&bidder, BalanceOf::::max_value()); - - let slot_range = SlotRange::n((n - 1) as u8).unwrap(); - let (start, end) = slot_range.as_pair(); - - assert!(Auctions::::bid( - RawOrigin::Signed(bidder).into(), - ParaId::from(n), - auction_index, - lease_period_index + start.into(), // First Slot - lease_period_index + end.into(), // Last slot - minimum_balance.saturating_mul(n.into()), // Amount - ) - .is_ok()); - } - } - - benchmarks! { - where_clause { where T: pallet_babe::Config + paras::Config } - - new_auction { - let duration = BlockNumberFor::::max_value(); - let lease_period_index = LeasePeriodOf::::max_value(); - let origin = - T::InitiateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(origin, duration, lease_period_index) - verify { - assert_last_event::(Event::::AuctionStarted { - auction_index: AuctionCounter::::get(), - lease_period: LeasePeriodOf::::max_value(), - ending: BlockNumberFor::::max_value(), - }.into()); - } - - // Worst case scenario a new bid comes in which kicks out an existing bid for the same slot. - bid { - // If there is an offset, we need to be on that block to be able to do lease things. - let (_, offset) = T::Leaser::lease_period_length(); - frame_system::Pallet::::set_block_number(offset + One::one()); - - // Create a new auction - let duration = BlockNumberFor::::max_value(); - let lease_period_index = LeasePeriodOf::::zero(); - let origin = T::InitiateOrigin::try_successful_origin() - .expect("InitiateOrigin has no successful origin required for the benchmark"); - Auctions::::new_auction(origin, duration, lease_period_index)?; - - let para = ParaId::from(0); - let new_para = ParaId::from(1_u32); - - // Register the paras - let owner = account("owner", 0, 0); - CurrencyOf::::make_free_balance_be(&owner, BalanceOf::::max_value()); - let worst_head_data = T::Registrar::worst_head_data(); - let worst_validation_code = T::Registrar::worst_validation_code(); - T::Registrar::register(owner.clone(), para, worst_head_data.clone(), worst_validation_code.clone())?; - T::Registrar::register(owner, new_para, worst_head_data, worst_validation_code.clone())?; - assert_ok!(paras::Pallet::::add_trusted_validation_code( - frame_system::Origin::::Root.into(), - worst_validation_code, - )); - - T::Registrar::execute_pending_transitions(); - - // Make an existing bid - let auction_index = AuctionCounter::::get(); - let first_slot = AuctionInfo::::get().unwrap().0; - let last_slot = first_slot + 3u32.into(); - let first_amount = CurrencyOf::::minimum_balance(); - let first_bidder: T::AccountId = account("first_bidder", 0, 0); - CurrencyOf::::make_free_balance_be(&first_bidder, BalanceOf::::max_value()); - Auctions::::bid( - RawOrigin::Signed(first_bidder.clone()).into(), - para, - auction_index, - first_slot, - last_slot, - first_amount, - )?; - - let caller: T::AccountId = whitelisted_caller(); - CurrencyOf::::make_free_balance_be(&caller, BalanceOf::::max_value()); - let bigger_amount = CurrencyOf::::minimum_balance().saturating_mul(10u32.into()); - assert_eq!(CurrencyOf::::reserved_balance(&first_bidder), first_amount); - }: _(RawOrigin::Signed(caller.clone()), new_para, auction_index, first_slot, last_slot, bigger_amount) - verify { - // Confirms that we unreserved funds from a previous bidder, which is worst case scenario. - assert_eq!(CurrencyOf::::reserved_balance(&caller), bigger_amount); - } - - // Worst case: 10 bidders taking all wining spots, and we need to calculate the winner for auction end. - // Entire winner map should be full and removed at the end of the benchmark. - on_initialize { - // If there is an offset, we need to be on that block to be able to do lease things. - let (lease_length, offset) = T::Leaser::lease_period_length(); - frame_system::Pallet::::set_block_number(offset + One::one()); - - // Create a new auction - let duration: BlockNumberFor = lease_length / 2u32.into(); - let lease_period_index = LeasePeriodOf::::zero(); - let now = frame_system::Pallet::::block_number(); - let origin = T::InitiateOrigin::try_successful_origin() - .expect("InitiateOrigin has no successful origin required for the benchmark"); - Auctions::::new_auction(origin, duration, lease_period_index)?; - - fill_winners::(lease_period_index); - - for winner in Winning::::get(BlockNumberFor::::from(0u32)).unwrap().iter() { - assert!(winner.is_some()); - } - - let winning_data = Winning::::get(BlockNumberFor::::from(0u32)).unwrap(); - // Make winning map full - for i in 0u32 .. (T::EndingPeriod::get() / T::SampleLength::get()).saturated_into() { - Winning::::insert(BlockNumberFor::::from(i), winning_data.clone()); - } - - // Move ahead to the block we want to initialize - frame_system::Pallet::::set_block_number(duration + now + T::EndingPeriod::get()); - - // Trigger epoch change for new random number value: - { - pallet_babe::EpochStart::::set((Zero::zero(), u32::MAX.into())); - pallet_babe::Pallet::::on_initialize(duration + now + T::EndingPeriod::get()); - let authorities = pallet_babe::Pallet::::authorities(); - // Check for non empty authority set since it otherwise emits a No-OP warning. - if !authorities.is_empty() { - pallet_babe::Pallet::::enact_epoch_change(authorities.clone(), authorities, None); - } - } - - }: { - Auctions::::on_initialize(duration + now + T::EndingPeriod::get()); - } verify { - let auction_index = AuctionCounter::::get(); - assert_last_event::(Event::::AuctionClosed { auction_index }.into()); - assert!(Winning::::iter().count().is_zero()); - } - - // Worst case: 10 bidders taking all wining spots, and winning data is full. - cancel_auction { - // If there is an offset, we need to be on that block to be able to do lease things. - let (lease_length, offset) = T::Leaser::lease_period_length(); - frame_system::Pallet::::set_block_number(offset + One::one()); - - // Create a new auction - let duration: BlockNumberFor = lease_length / 2u32.into(); - let lease_period_index = LeasePeriodOf::::zero(); - let now = frame_system::Pallet::::block_number(); - let origin = T::InitiateOrigin::try_successful_origin() - .expect("InitiateOrigin has no successful origin required for the benchmark"); - Auctions::::new_auction(origin, duration, lease_period_index)?; - - fill_winners::(lease_period_index); - - let winning_data = Winning::::get(BlockNumberFor::::from(0u32)).unwrap(); - for winner in winning_data.iter() { - assert!(winner.is_some()); - } - - // Make winning map full - for i in 0u32 .. (T::EndingPeriod::get() / T::SampleLength::get()).saturated_into() { - Winning::::insert(BlockNumberFor::::from(i), winning_data.clone()); - } - assert!(AuctionInfo::::get().is_some()); - }: _(RawOrigin::Root) - verify { - assert!(AuctionInfo::::get().is_none()); - } - - impl_benchmark_test_suite!( - Auctions, - crate::integration_tests::new_test_ext(), - crate::integration_tests::Test, - ); - } -} diff --git a/polkadot/runtime/common/src/auctions/benchmarking.rs b/polkadot/runtime/common/src/auctions/benchmarking.rs new file mode 100644 index 000000000000..6d52cd850b6f --- /dev/null +++ b/polkadot/runtime/common/src/auctions/benchmarking.rs @@ -0,0 +1,282 @@ +// 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 . + +//! Benchmarking for auctions pallet + +#![cfg(feature = "runtime-benchmarks")] +use super::{Pallet as Auctions, *}; +use frame_support::{ + assert_ok, + traits::{EnsureOrigin, OnInitialize}, +}; +use frame_system::RawOrigin; +use polkadot_runtime_parachains::paras; +use sp_runtime::{traits::Bounded, SaturatedConversion}; + +use frame_benchmarking::v2::*; + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +fn fill_winners(lease_period_index: LeasePeriodOf) { + let auction_index = AuctionCounter::::get(); + let minimum_balance = CurrencyOf::::minimum_balance(); + + for n in 1..=SlotRange::SLOT_RANGE_COUNT as u32 { + let owner = account("owner", n, 0); + let worst_validation_code = T::Registrar::worst_validation_code(); + let worst_head_data = T::Registrar::worst_head_data(); + CurrencyOf::::make_free_balance_be(&owner, BalanceOf::::max_value()); + + assert!(T::Registrar::register( + owner, + ParaId::from(n), + worst_head_data, + worst_validation_code + ) + .is_ok()); + } + assert_ok!(paras::Pallet::::add_trusted_validation_code( + frame_system::Origin::::Root.into(), + T::Registrar::worst_validation_code(), + )); + + T::Registrar::execute_pending_transitions(); + + for n in 1..=SlotRange::SLOT_RANGE_COUNT as u32 { + let bidder = account("bidder", n, 0); + CurrencyOf::::make_free_balance_be(&bidder, BalanceOf::::max_value()); + + let slot_range = SlotRange::n((n - 1) as u8).unwrap(); + let (start, end) = slot_range.as_pair(); + + assert!(Auctions::::bid( + RawOrigin::Signed(bidder).into(), + ParaId::from(n), + auction_index, + lease_period_index + start.into(), // First Slot + lease_period_index + end.into(), // Last slot + minimum_balance.saturating_mul(n.into()), // Amount + ) + .is_ok()); + } +} + +#[benchmarks( + where T: pallet_babe::Config + paras::Config, + )] +mod benchmarks { + use super::*; + + #[benchmark] + fn new_auction() -> Result<(), BenchmarkError> { + let duration = BlockNumberFor::::max_value(); + let lease_period_index = LeasePeriodOf::::max_value(); + let origin = + T::InitiateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, duration, lease_period_index); + + assert_last_event::( + Event::::AuctionStarted { + auction_index: AuctionCounter::::get(), + lease_period: LeasePeriodOf::::max_value(), + ending: BlockNumberFor::::max_value(), + } + .into(), + ); + + Ok(()) + } + + // Worst case scenario a new bid comes in which kicks out an existing bid for the same slot. + #[benchmark] + fn bid() -> Result<(), BenchmarkError> { + // If there is an offset, we need to be on that block to be able to do lease things. + let (_, offset) = T::Leaser::lease_period_length(); + frame_system::Pallet::::set_block_number(offset + One::one()); + + // Create a new auction + let duration = BlockNumberFor::::max_value(); + let lease_period_index = LeasePeriodOf::::zero(); + let origin = T::InitiateOrigin::try_successful_origin() + .expect("InitiateOrigin has no successful origin required for the benchmark"); + Auctions::::new_auction(origin, duration, lease_period_index)?; + + let para = ParaId::from(0); + let new_para = ParaId::from(1_u32); + + // Register the paras + let owner = account("owner", 0, 0); + CurrencyOf::::make_free_balance_be(&owner, BalanceOf::::max_value()); + let worst_head_data = T::Registrar::worst_head_data(); + let worst_validation_code = T::Registrar::worst_validation_code(); + T::Registrar::register( + owner.clone(), + para, + worst_head_data.clone(), + worst_validation_code.clone(), + )?; + T::Registrar::register(owner, new_para, worst_head_data, worst_validation_code.clone())?; + assert_ok!(paras::Pallet::::add_trusted_validation_code( + frame_system::Origin::::Root.into(), + worst_validation_code, + )); + + T::Registrar::execute_pending_transitions(); + + // Make an existing bid + let auction_index = AuctionCounter::::get(); + let first_slot = AuctionInfo::::get().unwrap().0; + let last_slot = first_slot + 3u32.into(); + let first_amount = CurrencyOf::::minimum_balance(); + let first_bidder: T::AccountId = account("first_bidder", 0, 0); + CurrencyOf::::make_free_balance_be(&first_bidder, BalanceOf::::max_value()); + Auctions::::bid( + RawOrigin::Signed(first_bidder.clone()).into(), + para, + auction_index, + first_slot, + last_slot, + first_amount, + )?; + + let caller: T::AccountId = whitelisted_caller(); + CurrencyOf::::make_free_balance_be(&caller, BalanceOf::::max_value()); + let bigger_amount = CurrencyOf::::minimum_balance().saturating_mul(10u32.into()); + assert_eq!(CurrencyOf::::reserved_balance(&first_bidder), first_amount); + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + new_para, + auction_index, + first_slot, + last_slot, + bigger_amount, + ); + + // Confirms that we unreserved funds from a previous bidder, which is worst case + // scenario. + assert_eq!(CurrencyOf::::reserved_balance(&caller), bigger_amount); + + Ok(()) + } + + // Worst case: 10 bidders taking all wining spots, and we need to calculate the winner for + // auction end. Entire winner map should be full and removed at the end of the benchmark. + #[benchmark] + fn on_initialize() -> Result<(), BenchmarkError> { + // If there is an offset, we need to be on that block to be able to do lease things. + let (lease_length, offset) = T::Leaser::lease_period_length(); + frame_system::Pallet::::set_block_number(offset + One::one()); + + // Create a new auction + let duration: BlockNumberFor = lease_length / 2u32.into(); + let lease_period_index = LeasePeriodOf::::zero(); + let now = frame_system::Pallet::::block_number(); + let origin = T::InitiateOrigin::try_successful_origin() + .expect("InitiateOrigin has no successful origin required for the benchmark"); + Auctions::::new_auction(origin, duration, lease_period_index)?; + + fill_winners::(lease_period_index); + + for winner in Winning::::get(BlockNumberFor::::from(0u32)).unwrap().iter() { + assert!(winner.is_some()); + } + + let winning_data = Winning::::get(BlockNumberFor::::from(0u32)).unwrap(); + // Make winning map full + for i in 0u32..(T::EndingPeriod::get() / T::SampleLength::get()).saturated_into() { + Winning::::insert(BlockNumberFor::::from(i), winning_data.clone()); + } + + // Move ahead to the block we want to initialize + frame_system::Pallet::::set_block_number(duration + now + T::EndingPeriod::get()); + + // Trigger epoch change for new random number value: + { + pallet_babe::EpochStart::::set((Zero::zero(), u32::MAX.into())); + pallet_babe::Pallet::::on_initialize(duration + now + T::EndingPeriod::get()); + let authorities = pallet_babe::Pallet::::authorities(); + // Check for non empty authority set since it otherwise emits a No-OP warning. + if !authorities.is_empty() { + pallet_babe::Pallet::::enact_epoch_change( + authorities.clone(), + authorities, + None, + ); + } + } + + #[block] + { + Auctions::::on_initialize(duration + now + T::EndingPeriod::get()); + } + + let auction_index = AuctionCounter::::get(); + assert_last_event::(Event::::AuctionClosed { auction_index }.into()); + assert!(Winning::::iter().count().is_zero()); + + Ok(()) + } + + // Worst case: 10 bidders taking all wining spots, and winning data is full. + #[benchmark] + fn cancel_auction() -> Result<(), BenchmarkError> { + // If there is an offset, we need to be on that block to be able to do lease things. + let (lease_length, offset) = T::Leaser::lease_period_length(); + frame_system::Pallet::::set_block_number(offset + One::one()); + + // Create a new auction + let duration: BlockNumberFor = lease_length / 2u32.into(); + let lease_period_index = LeasePeriodOf::::zero(); + let origin = T::InitiateOrigin::try_successful_origin() + .expect("InitiateOrigin has no successful origin required for the benchmark"); + Auctions::::new_auction(origin, duration, lease_period_index)?; + + fill_winners::(lease_period_index); + + let winning_data = Winning::::get(BlockNumberFor::::from(0u32)).unwrap(); + for winner in winning_data.iter() { + assert!(winner.is_some()); + } + + // Make winning map full + for i in 0u32..(T::EndingPeriod::get() / T::SampleLength::get()).saturated_into() { + Winning::::insert(BlockNumberFor::::from(i), winning_data.clone()); + } + assert!(AuctionInfo::::get().is_some()); + + #[extrinsic_call] + _(RawOrigin::Root); + + assert!(AuctionInfo::::get().is_none()); + Ok(()) + } + + impl_benchmark_test_suite!( + Auctions, + crate::integration_tests::new_test_ext(), + crate::integration_tests::Test, + ); +} diff --git a/polkadot/runtime/common/src/auctions/mock.rs b/polkadot/runtime/common/src/auctions/mock.rs new file mode 100644 index 000000000000..9fe19e579cfa --- /dev/null +++ b/polkadot/runtime/common/src/auctions/mock.rs @@ -0,0 +1,258 @@ +// 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 . + +//! Mocking utilities for testing in auctions pallet. + +#[cfg(test)] +use super::*; +use crate::{auctions, mock::TestRegistrar}; +use frame_support::{ + assert_ok, derive_impl, ord_parameter_types, parameter_types, + traits::{EitherOfDiverse, OnFinalize, OnInitialize}, +}; +use frame_system::{EnsureRoot, EnsureSignedBy}; +use pallet_balances; +use polkadot_primitives::{BlockNumber, Id as ParaId}; +use polkadot_primitives_test_helpers::{dummy_head_data, dummy_validation_code}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; +use std::{cell::RefCell, collections::BTreeMap}; + +type Block = frame_system::mocking::MockBlockU32; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Auctions: auctions, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type AccountStore = System; +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] +pub struct LeaseData { + pub leaser: u64, + pub amount: u64, +} + +thread_local! { + pub static LEASES: + RefCell> = RefCell::new(BTreeMap::new()); +} + +pub fn leases() -> Vec<((ParaId, BlockNumber), LeaseData)> { + LEASES.with(|p| (&*p.borrow()).clone().into_iter().collect::>()) +} + +pub struct TestLeaser; +impl Leaser for TestLeaser { + type AccountId = u64; + type LeasePeriod = BlockNumber; + type Currency = Balances; + + fn lease_out( + para: ParaId, + leaser: &Self::AccountId, + amount: >::Balance, + period_begin: Self::LeasePeriod, + period_count: Self::LeasePeriod, + ) -> Result<(), LeaseError> { + LEASES.with(|l| { + let mut leases = l.borrow_mut(); + let now = System::block_number(); + let (current_lease_period, _) = + Self::lease_period_index(now).ok_or(LeaseError::NoLeasePeriod)?; + if period_begin < current_lease_period { + return Err(LeaseError::AlreadyEnded); + } + for period in period_begin..(period_begin + period_count) { + if leases.contains_key(&(para, period)) { + return Err(LeaseError::AlreadyLeased); + } + leases.insert((para, period), LeaseData { leaser: *leaser, amount }); + } + Ok(()) + }) + } + + fn deposit_held( + para: ParaId, + leaser: &Self::AccountId, + ) -> >::Balance { + leases() + .iter() + .filter_map(|((id, _period), data)| { + if id == ¶ && &data.leaser == leaser { + Some(data.amount) + } else { + None + } + }) + .max() + .unwrap_or_default() + } + + fn lease_period_length() -> (BlockNumber, BlockNumber) { + (10, 0) + } + + fn lease_period_index(b: BlockNumber) -> Option<(Self::LeasePeriod, bool)> { + let (lease_period_length, offset) = Self::lease_period_length(); + let b = b.checked_sub(offset)?; + + let lease_period = b / lease_period_length; + let first_block = (b % lease_period_length).is_zero(); + + Some((lease_period, first_block)) + } + + fn already_leased( + para_id: ParaId, + first_period: Self::LeasePeriod, + last_period: Self::LeasePeriod, + ) -> bool { + leases().into_iter().any(|((para, period), _data)| { + para == para_id && first_period <= period && period <= last_period + }) + } +} + +ord_parameter_types! { + pub const Six: u64 = 6; +} + +type RootOrSix = EitherOfDiverse, EnsureSignedBy>; + +thread_local! { + pub static LAST_RANDOM: RefCell> = RefCell::new(None); +} +pub fn set_last_random(output: H256, known_since: u32) { + LAST_RANDOM.with(|p| *p.borrow_mut() = Some((output, known_since))) +} +pub struct TestPastRandomness; +impl Randomness for TestPastRandomness { + fn random(_subject: &[u8]) -> (H256, u32) { + LAST_RANDOM.with(|p| { + if let Some((output, known_since)) = &*p.borrow() { + (*output, *known_since) + } else { + (H256::zero(), frame_system::Pallet::::block_number()) + } + }) + } +} + +parameter_types! { + pub static EndingPeriod: BlockNumber = 3; + pub static SampleLength: BlockNumber = 1; +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type Leaser = TestLeaser; + type Registrar = TestRegistrar; + type EndingPeriod = EndingPeriod; + type SampleLength = SampleLength; + type Randomness = TestPastRandomness; + type InitiateOrigin = RootOrSix; + type WeightInfo = crate::auctions::TestWeightInfo; +} + +// This function basically just builds a genesis storage key/value store according to +// our desired mock up. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext: sp_io::TestExternalities = t.into(); + ext.execute_with(|| { + // Register para 0, 1, 2, and 3 for tests + assert_ok!(TestRegistrar::::register( + 1, + 0.into(), + dummy_head_data(), + dummy_validation_code() + )); + assert_ok!(TestRegistrar::::register( + 1, + 1.into(), + dummy_head_data(), + dummy_validation_code() + )); + assert_ok!(TestRegistrar::::register( + 1, + 2.into(), + dummy_head_data(), + dummy_validation_code() + )); + assert_ok!(TestRegistrar::::register( + 1, + 3.into(), + dummy_head_data(), + dummy_validation_code() + )); + }); + ext +} + +pub fn run_to_block(n: BlockNumber) { + while System::block_number() < n { + Auctions::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + Auctions::on_initialize(System::block_number()); + } +} diff --git a/polkadot/runtime/common/src/auctions/mod.rs b/polkadot/runtime/common/src/auctions/mod.rs new file mode 100644 index 000000000000..84d8a3846d40 --- /dev/null +++ b/polkadot/runtime/common/src/auctions/mod.rs @@ -0,0 +1,677 @@ +// 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 . + +//! Auctioning system to determine the set of Parachains in operation. This includes logic for the +//! auctioning mechanism and for reserving balance as part of the "payment". Unreserving the balance +//! happens elsewhere. + +use crate::{ + slot_range::SlotRange, + traits::{AuctionStatus, Auctioneer, LeaseError, Leaser, Registrar}, +}; +use alloc::{vec, vec::Vec}; +use codec::Decode; +use core::mem::swap; +use frame_support::{ + dispatch::DispatchResult, + ensure, + traits::{Currency, Get, Randomness, ReservableCurrency}, + weights::Weight, +}; +use frame_system::pallet_prelude::BlockNumberFor; +pub use pallet::*; +use polkadot_primitives::Id as ParaId; +use sp_runtime::traits::{CheckedSub, One, Saturating, Zero}; + +type CurrencyOf = <::Leaser as Leaser>>::Currency; +type BalanceOf = <<::Leaser as Leaser>>::Currency as Currency< + ::AccountId, +>>::Balance; + +pub trait WeightInfo { + fn new_auction() -> Weight; + fn bid() -> Weight; + fn cancel_auction() -> Weight; + fn on_initialize() -> Weight; +} + +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn new_auction() -> Weight { + Weight::zero() + } + fn bid() -> Weight { + Weight::zero() + } + fn cancel_auction() -> Weight { + Weight::zero() + } + fn on_initialize() -> Weight { + Weight::zero() + } +} + +/// An auction index. We count auctions in this type. +pub type AuctionIndex = u32; + +type LeasePeriodOf = <::Leaser as Leaser>>::LeasePeriod; + +// Winning data type. This encodes the top bidders of each range together with their bid. +type WinningData = [Option<(::AccountId, ParaId, BalanceOf)>; + SlotRange::SLOT_RANGE_COUNT]; +// Winners data type. This encodes each of the final winners of a parachain auction, the parachain +// index assigned to them, their winning bid and the range that they won. +type WinnersData = + Vec<(::AccountId, ParaId, BalanceOf, SlotRange)>; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{dispatch::DispatchClass, pallet_prelude::*, traits::EnsureOrigin}; + use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; + + #[pallet::pallet] + pub struct Pallet(_); + + /// The module's configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The type representing the leasing system. + type Leaser: Leaser< + BlockNumberFor, + AccountId = Self::AccountId, + LeasePeriod = BlockNumberFor, + >; + + /// The parachain registrar type. + type Registrar: Registrar; + + /// The number of blocks over which an auction may be retroactively ended. + #[pallet::constant] + type EndingPeriod: Get>; + + /// The length of each sample to take during the ending period. + /// + /// `EndingPeriod` / `SampleLength` = Total # of Samples + #[pallet::constant] + type SampleLength: Get>; + + /// Something that provides randomness in the runtime. + type Randomness: Randomness>; + + /// The origin which may initiate auctions. + type InitiateOrigin: EnsureOrigin; + + /// Weight Information for the Extrinsics in the Pallet + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// An auction started. Provides its index and the block number where it will begin to + /// close and the first lease period of the quadruplet that is auctioned. + AuctionStarted { + auction_index: AuctionIndex, + lease_period: LeasePeriodOf, + ending: BlockNumberFor, + }, + /// An auction ended. All funds become unreserved. + AuctionClosed { auction_index: AuctionIndex }, + /// Funds were reserved for a winning bid. First balance is the extra amount reserved. + /// Second is the total. + Reserved { bidder: T::AccountId, extra_reserved: BalanceOf, total_amount: BalanceOf }, + /// Funds were unreserved since bidder is no longer active. `[bidder, amount]` + Unreserved { bidder: T::AccountId, amount: BalanceOf }, + /// Someone attempted to lease the same slot twice for a parachain. The amount is held in + /// reserve but no parachain slot has been leased. + ReserveConfiscated { para_id: ParaId, leaser: T::AccountId, amount: BalanceOf }, + /// A new bid has been accepted as the current winner. + BidAccepted { + bidder: T::AccountId, + para_id: ParaId, + amount: BalanceOf, + first_slot: LeasePeriodOf, + last_slot: LeasePeriodOf, + }, + /// The winning offset was chosen for an auction. This will map into the `Winning` storage + /// map. + WinningOffset { auction_index: AuctionIndex, block_number: BlockNumberFor }, + } + + #[pallet::error] + pub enum Error { + /// This auction is already in progress. + AuctionInProgress, + /// The lease period is in the past. + LeasePeriodInPast, + /// Para is not registered + ParaNotRegistered, + /// Not a current auction. + NotCurrentAuction, + /// Not an auction. + NotAuction, + /// Auction has already ended. + AuctionEnded, + /// The para is already leased out for part of this range. + AlreadyLeasedOut, + } + + /// Number of auctions started so far. + #[pallet::storage] + pub type AuctionCounter = StorageValue<_, AuctionIndex, ValueQuery>; + + /// Information relating to the current auction, if there is one. + /// + /// The first item in the tuple is the lease period index that the first of the four + /// contiguous lease periods on auction is for. The second is the block number when the + /// auction will "begin to end", i.e. the first block of the Ending Period of the auction. + #[pallet::storage] + pub type AuctionInfo = StorageValue<_, (LeasePeriodOf, BlockNumberFor)>; + + /// Amounts currently reserved in the accounts of the bidders currently winning + /// (sub-)ranges. + #[pallet::storage] + pub type ReservedAmounts = + StorageMap<_, Twox64Concat, (T::AccountId, ParaId), BalanceOf>; + + /// The winning bids for each of the 10 ranges at each sample in the final Ending Period of + /// the current auction. The map's key is the 0-based index into the Sample Size. The + /// first sample of the ending period is 0; the last is `Sample Size - 1`. + #[pallet::storage] + pub type Winning = StorageMap<_, Twox64Concat, BlockNumberFor, WinningData>; + + #[pallet::extra_constants] + impl Pallet { + #[pallet::constant_name(SlotRangeCount)] + fn slot_range_count() -> u32 { + SlotRange::SLOT_RANGE_COUNT as u32 + } + + #[pallet::constant_name(LeasePeriodsPerSlot)] + fn lease_periods_per_slot() -> u32 { + SlotRange::LEASE_PERIODS_PER_SLOT as u32 + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(n: BlockNumberFor) -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // If the current auction was in its ending period last block, then ensure that the + // (sub-)range winner information is duplicated from the previous block in case no bids + // happened in the last block. + if let AuctionStatus::EndingPeriod(offset, _sub_sample) = Self::auction_status(n) { + weight = weight.saturating_add(T::DbWeight::get().reads(1)); + if !Winning::::contains_key(&offset) { + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + let winning_data = offset + .checked_sub(&One::one()) + .and_then(Winning::::get) + .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); + Winning::::insert(offset, winning_data); + } + } + + // Check to see if an auction just ended. + if let Some((winning_ranges, auction_lease_period_index)) = Self::check_auction_end(n) { + // Auction is ended now. We have the winning ranges and the lease period index which + // acts as the offset. Handle it. + Self::manage_auction_end(auction_lease_period_index, winning_ranges); + weight = weight.saturating_add(T::WeightInfo::on_initialize()); + } + + weight + } + } + + #[pallet::call] + impl Pallet { + /// Create a new auction. + /// + /// This can only happen when there isn't already an auction in progress and may only be + /// called by the root origin. Accepts the `duration` of this auction and the + /// `lease_period_index` of the initial lease period of the four that are to be auctioned. + #[pallet::call_index(0)] + #[pallet::weight((T::WeightInfo::new_auction(), DispatchClass::Operational))] + pub fn new_auction( + origin: OriginFor, + #[pallet::compact] duration: BlockNumberFor, + #[pallet::compact] lease_period_index: LeasePeriodOf, + ) -> DispatchResult { + T::InitiateOrigin::ensure_origin(origin)?; + Self::do_new_auction(duration, lease_period_index) + } + + /// Make a new bid from an account (including a parachain account) for deploying a new + /// parachain. + /// + /// Multiple simultaneous bids from the same bidder are allowed only as long as all active + /// bids overlap each other (i.e. are mutually exclusive). Bids cannot be redacted. + /// + /// - `sub` is the sub-bidder ID, allowing for multiple competing bids to be made by (and + /// funded by) the same account. + /// - `auction_index` is the index of the auction to bid on. Should just be the present + /// value of `AuctionCounter`. + /// - `first_slot` is the first lease period index of the range to bid on. This is the + /// absolute lease period index value, not an auction-specific offset. + /// - `last_slot` is the last lease period index of the range to bid on. This is the + /// absolute lease period index value, not an auction-specific offset. + /// - `amount` is the amount to bid to be held as deposit for the parachain should the + /// bid win. This amount is held throughout the range. + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::bid())] + pub fn bid( + origin: OriginFor, + #[pallet::compact] para: ParaId, + #[pallet::compact] auction_index: AuctionIndex, + #[pallet::compact] first_slot: LeasePeriodOf, + #[pallet::compact] last_slot: LeasePeriodOf, + #[pallet::compact] amount: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::handle_bid(who, para, auction_index, first_slot, last_slot, amount)?; + Ok(()) + } + + /// Cancel an in-progress auction. + /// + /// Can only be called by Root origin. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::cancel_auction())] + pub fn cancel_auction(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + // Unreserve all bids. + for ((bidder, _), amount) in ReservedAmounts::::drain() { + CurrencyOf::::unreserve(&bidder, amount); + } + #[allow(deprecated)] + Winning::::remove_all(None); + AuctionInfo::::kill(); + Ok(()) + } + } +} + +impl Auctioneer> for Pallet { + type AccountId = T::AccountId; + type LeasePeriod = BlockNumberFor; + type Currency = CurrencyOf; + + fn new_auction( + duration: BlockNumberFor, + lease_period_index: LeasePeriodOf, + ) -> DispatchResult { + Self::do_new_auction(duration, lease_period_index) + } + + // Returns the status of the auction given the current block number. + fn auction_status(now: BlockNumberFor) -> AuctionStatus> { + let early_end = match AuctionInfo::::get() { + Some((_, early_end)) => early_end, + None => return AuctionStatus::NotStarted, + }; + + let after_early_end = match now.checked_sub(&early_end) { + Some(after_early_end) => after_early_end, + None => return AuctionStatus::StartingPeriod, + }; + + let ending_period = T::EndingPeriod::get(); + if after_early_end < ending_period { + let sample_length = T::SampleLength::get().max(One::one()); + let sample = after_early_end / sample_length; + let sub_sample = after_early_end % sample_length; + return AuctionStatus::EndingPeriod(sample, sub_sample) + } else { + // This is safe because of the comparison operator above + return AuctionStatus::VrfDelay(after_early_end - ending_period) + } + } + + fn place_bid( + bidder: T::AccountId, + para: ParaId, + first_slot: LeasePeriodOf, + last_slot: LeasePeriodOf, + amount: BalanceOf, + ) -> DispatchResult { + Self::handle_bid(bidder, para, AuctionCounter::::get(), first_slot, last_slot, amount) + } + + fn lease_period_index(b: BlockNumberFor) -> Option<(Self::LeasePeriod, bool)> { + T::Leaser::lease_period_index(b) + } + + #[cfg(any(feature = "runtime-benchmarks", test))] + fn lease_period_length() -> (BlockNumberFor, BlockNumberFor) { + T::Leaser::lease_period_length() + } + + fn has_won_an_auction(para: ParaId, bidder: &T::AccountId) -> bool { + !T::Leaser::deposit_held(para, bidder).is_zero() + } +} + +impl Pallet { + // A trick to allow me to initialize large arrays with nothing in them. + const EMPTY: Option<(::AccountId, ParaId, BalanceOf)> = None; + + /// Create a new auction. + /// + /// This can only happen when there isn't already an auction in progress. Accepts the `duration` + /// of this auction and the `lease_period_index` of the initial lease period of the four that + /// are to be auctioned. + fn do_new_auction( + duration: BlockNumberFor, + lease_period_index: LeasePeriodOf, + ) -> DispatchResult { + let maybe_auction = AuctionInfo::::get(); + ensure!(maybe_auction.is_none(), Error::::AuctionInProgress); + let now = frame_system::Pallet::::block_number(); + if let Some((current_lease_period, _)) = T::Leaser::lease_period_index(now) { + // If there is no active lease period, then we don't need to make this check. + ensure!(lease_period_index >= current_lease_period, Error::::LeasePeriodInPast); + } + + // Bump the counter. + let n = AuctionCounter::::mutate(|n| { + *n += 1; + *n + }); + + // Set the information. + let ending = frame_system::Pallet::::block_number().saturating_add(duration); + AuctionInfo::::put((lease_period_index, ending)); + + Self::deposit_event(Event::::AuctionStarted { + auction_index: n, + lease_period: lease_period_index, + ending, + }); + Ok(()) + } + + /// Actually place a bid in the current auction. + /// + /// - `bidder`: The account that will be funding this bid. + /// - `auction_index`: The auction index of the bid. For this to succeed, must equal + /// the current value of `AuctionCounter`. + /// - `first_slot`: The first lease period index of the range to be bid on. + /// - `last_slot`: The last lease period index of the range to be bid on (inclusive). + /// - `amount`: The total amount to be the bid for deposit over the range. + pub fn handle_bid( + bidder: T::AccountId, + para: ParaId, + auction_index: u32, + first_slot: LeasePeriodOf, + last_slot: LeasePeriodOf, + amount: BalanceOf, + ) -> DispatchResult { + // Ensure para is registered before placing a bid on it. + ensure!(T::Registrar::is_registered(para), Error::::ParaNotRegistered); + // Bidding on latest auction. + ensure!(auction_index == AuctionCounter::::get(), Error::::NotCurrentAuction); + // Assume it's actually an auction (this should never fail because of above). + let (first_lease_period, _) = AuctionInfo::::get().ok_or(Error::::NotAuction)?; + + // Get the auction status and the current sample block. For the starting period, the sample + // block is zero. + let auction_status = Self::auction_status(frame_system::Pallet::::block_number()); + // The offset into the ending samples of the auction. + let offset = match auction_status { + AuctionStatus::NotStarted => return Err(Error::::AuctionEnded.into()), + AuctionStatus::StartingPeriod => Zero::zero(), + AuctionStatus::EndingPeriod(o, _) => o, + AuctionStatus::VrfDelay(_) => return Err(Error::::AuctionEnded.into()), + }; + + // We also make sure that the bid is not for any existing leases the para already has. + ensure!( + !T::Leaser::already_leased(para, first_slot, last_slot), + Error::::AlreadyLeasedOut + ); + + // Our range. + let range = SlotRange::new_bounded(first_lease_period, first_slot, last_slot)?; + // Range as an array index. + let range_index = range as u8 as usize; + + // The current winning ranges. + let mut current_winning = Winning::::get(offset) + .or_else(|| offset.checked_sub(&One::one()).and_then(Winning::::get)) + .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); + + // If this bid beat the previous winner of our range. + if current_winning[range_index].as_ref().map_or(true, |last| amount > last.2) { + // Ok; we are the new winner of this range - reserve the additional amount and record. + + // Get the amount already held on deposit if this is a renewal bid (i.e. there's + // an existing lease on the same para by the same leaser). + let existing_lease_deposit = T::Leaser::deposit_held(para, &bidder); + let reserve_required = amount.saturating_sub(existing_lease_deposit); + + // Get the amount already reserved in any prior and still active bids by us. + let bidder_para = (bidder.clone(), para); + let already_reserved = ReservedAmounts::::get(&bidder_para).unwrap_or_default(); + + // If these don't already cover the bid... + if let Some(additional) = reserve_required.checked_sub(&already_reserved) { + // ...then reserve some more funds from their account, failing if there's not + // enough funds. + CurrencyOf::::reserve(&bidder, additional)?; + // ...and record the amount reserved. + ReservedAmounts::::insert(&bidder_para, reserve_required); + + Self::deposit_event(Event::::Reserved { + bidder: bidder.clone(), + extra_reserved: additional, + total_amount: reserve_required, + }); + } + + // Return any funds reserved for the previous winner if we are not in the ending period + // and they no longer have any active bids. + let mut outgoing_winner = Some((bidder.clone(), para, amount)); + swap(&mut current_winning[range_index], &mut outgoing_winner); + if let Some((who, para, _amount)) = outgoing_winner { + if auction_status.is_starting() && + current_winning + .iter() + .filter_map(Option::as_ref) + .all(|&(ref other, other_para, _)| other != &who || other_para != para) + { + // Previous bidder is no longer winning any ranges: unreserve their funds. + if let Some(amount) = ReservedAmounts::::take(&(who.clone(), para)) { + // It really should be reserved; there's not much we can do here on fail. + let err_amt = CurrencyOf::::unreserve(&who, amount); + debug_assert!(err_amt.is_zero()); + Self::deposit_event(Event::::Unreserved { bidder: who, amount }); + } + } + } + + // Update the range winner. + Winning::::insert(offset, ¤t_winning); + Self::deposit_event(Event::::BidAccepted { + bidder, + para_id: para, + amount, + first_slot, + last_slot, + }); + } + Ok(()) + } + + /// Some when the auction's end is known (with the end block number). None if it is unknown. + /// If `Some` then the block number must be at most the previous block and at least the + /// previous block minus `T::EndingPeriod::get()`. + /// + /// This mutates the state, cleaning up `AuctionInfo` and `Winning` in the case of an auction + /// ending. An immediately subsequent call with the same argument will always return `None`. + fn check_auction_end(now: BlockNumberFor) -> Option<(WinningData, LeasePeriodOf)> { + if let Some((lease_period_index, early_end)) = AuctionInfo::::get() { + let ending_period = T::EndingPeriod::get(); + let late_end = early_end.saturating_add(ending_period); + let is_ended = now >= late_end; + if is_ended { + // auction definitely ended. + // check to see if we can determine the actual ending point. + let (raw_offset, known_since) = T::Randomness::random(&b"para_auction"[..]); + + if late_end <= known_since { + // Our random seed was known only after the auction ended. Good to use. + let raw_offset_block_number = >::decode( + &mut raw_offset.as_ref(), + ) + .expect("secure hashes should always be bigger than the block number; qed"); + let offset = (raw_offset_block_number % ending_period) / + T::SampleLength::get().max(One::one()); + + let auction_counter = AuctionCounter::::get(); + Self::deposit_event(Event::::WinningOffset { + auction_index: auction_counter, + block_number: offset, + }); + let res = Winning::::get(offset) + .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); + // This `remove_all` statement should remove at most `EndingPeriod` / + // `SampleLength` items, which should be bounded and sensibly configured in the + // runtime. + #[allow(deprecated)] + Winning::::remove_all(None); + AuctionInfo::::kill(); + return Some((res, lease_period_index)) + } + } + } + None + } + + /// Auction just ended. We have the current lease period, the auction's lease period (which + /// is guaranteed to be at least the current period) and the bidders that were winning each + /// range at the time of the auction's close. + fn manage_auction_end( + auction_lease_period_index: LeasePeriodOf, + winning_ranges: WinningData, + ) { + // First, unreserve all amounts that were reserved for the bids. We will later re-reserve + // the amounts from the bidders that ended up being assigned the slot so there's no need to + // special-case them here. + for ((bidder, _), amount) in ReservedAmounts::::drain() { + CurrencyOf::::unreserve(&bidder, amount); + } + + // Next, calculate the winning combination of slots and thus the final winners of the + // auction. + let winners = Self::calculate_winners(winning_ranges); + + // Go through those winners and re-reserve their bid, updating our table of deposits + // accordingly. + for (leaser, para, amount, range) in winners.into_iter() { + let begin_offset = LeasePeriodOf::::from(range.as_pair().0 as u32); + let period_begin = auction_lease_period_index + begin_offset; + let period_count = LeasePeriodOf::::from(range.len() as u32); + + match T::Leaser::lease_out(para, &leaser, amount, period_begin, period_count) { + Err(LeaseError::ReserveFailed) | + Err(LeaseError::AlreadyEnded) | + Err(LeaseError::NoLeasePeriod) => { + // Should never happen since we just unreserved this amount (and our offset is + // from the present period). But if it does, there's not much we can do. + }, + Err(LeaseError::AlreadyLeased) => { + // The leaser attempted to get a second lease on the same para ID, possibly + // griefing us. Let's keep the amount reserved and let governance sort it out. + if CurrencyOf::::reserve(&leaser, amount).is_ok() { + Self::deposit_event(Event::::ReserveConfiscated { + para_id: para, + leaser, + amount, + }); + } + }, + Ok(()) => {}, // Nothing to report. + } + } + + Self::deposit_event(Event::::AuctionClosed { + auction_index: AuctionCounter::::get(), + }); + } + + /// Calculate the final winners from the winning slots. + /// + /// This is a simple dynamic programming algorithm designed by Al, the original code is at: + /// `https://github.com/w3f/consensus/blob/master/NPoS/auctiondynamicthing.py` + fn calculate_winners(mut winning: WinningData) -> WinnersData { + let winning_ranges = { + let mut best_winners_ending_at: [(Vec, BalanceOf); + SlotRange::LEASE_PERIODS_PER_SLOT] = Default::default(); + let best_bid = |range: SlotRange| { + winning[range as u8 as usize] + .as_ref() + .map(|(_, _, amount)| *amount * (range.len() as u32).into()) + }; + for i in 0..SlotRange::LEASE_PERIODS_PER_SLOT { + let r = SlotRange::new_bounded(0, 0, i as u32).expect("`i < LPPS`; qed"); + if let Some(bid) = best_bid(r) { + best_winners_ending_at[i] = (vec![r], bid); + } + for j in 0..i { + let r = SlotRange::new_bounded(0, j as u32 + 1, i as u32) + .expect("`i < LPPS`; `j < i`; `j + 1 < LPPS`; qed"); + if let Some(mut bid) = best_bid(r) { + bid += best_winners_ending_at[j].1; + if bid > best_winners_ending_at[i].1 { + let mut new_winners = best_winners_ending_at[j].0.clone(); + new_winners.push(r); + best_winners_ending_at[i] = (new_winners, bid); + } + } else { + if best_winners_ending_at[j].1 > best_winners_ending_at[i].1 { + best_winners_ending_at[i] = best_winners_ending_at[j].clone(); + } + } + } + } + best_winners_ending_at[SlotRange::LEASE_PERIODS_PER_SLOT - 1].0.clone() + }; + + winning_ranges + .into_iter() + .filter_map(|range| { + winning[range as u8 as usize] + .take() + .map(|(bidder, para, amount)| (bidder, para, amount, range)) + }) + .collect::>() + } +} + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; diff --git a/polkadot/runtime/common/src/auctions/tests.rs b/polkadot/runtime/common/src/auctions/tests.rs new file mode 100644 index 000000000000..07574eeb295d --- /dev/null +++ b/polkadot/runtime/common/src/auctions/tests.rs @@ -0,0 +1,821 @@ +// 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 . + +//! Tests for the auctions pallet. + +#[cfg(test)] +use super::*; +use crate::{auctions::mock::*, mock::TestRegistrar}; +use frame_support::{assert_noop, assert_ok, assert_storage_noop}; +use pallet_balances; +use polkadot_primitives::Id as ParaId; +use polkadot_primitives_test_helpers::{dummy_hash, dummy_head_data, dummy_validation_code}; +use sp_core::H256; +use sp_runtime::DispatchError::BadOrigin; + +#[test] +fn basic_setup_works() { + new_test_ext().execute_with(|| { + assert_eq!(AuctionCounter::::get(), 0); + assert_eq!(TestLeaser::deposit_held(0u32.into(), &1), 0); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + + run_to_block(10); + + assert_eq!(AuctionCounter::::get(), 0); + assert_eq!(TestLeaser::deposit_held(0u32.into(), &1), 0); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + }); +} + +#[test] +fn can_start_auction() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_noop!(Auctions::new_auction(RuntimeOrigin::signed(1), 5, 1), BadOrigin); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + + assert_eq!(AuctionCounter::::get(), 1); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + }); +} + +#[test] +fn bidding_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 5)); + + assert_eq!(Balances::reserved_balance(1), 5); + assert_eq!(Balances::free_balance(1), 5); + assert_eq!( + Winning::::get(0).unwrap()[SlotRange::ZeroThree as u8 as usize], + Some((1, 0.into(), 5)) + ); + }); +} + +#[test] +fn under_bidding_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 5)); + + assert_storage_noop!({ + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 0.into(), 1, 1, 4, 1)); + }); + }); +} + +#[test] +fn over_bidding_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 5)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 0.into(), 1, 1, 4, 6)); + + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::reserved_balance(2), 6); + assert_eq!(Balances::free_balance(2), 14); + assert_eq!( + Winning::::get(0).unwrap()[SlotRange::ZeroThree as u8 as usize], + Some((2, 0.into(), 6)) + ); + }); +} + +#[test] +fn auction_proceeds_correctly() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + + assert_eq!(AuctionCounter::::get(), 1); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(2); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(3); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(4); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(5); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(6); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(0, 0) + ); + + run_to_block(7); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(1, 0) + ); + + run_to_block(8); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(2, 0) + ); + + run_to_block(9); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + }); +} + +#[test] +fn can_win_auction() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 1)); + assert_eq!(Balances::reserved_balance(1), 1); + assert_eq!(Balances::free_balance(1), 9); + run_to_block(9); + + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 2), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 3), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 4), LeaseData { leaser: 1, amount: 1 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); + }); +} + +#[test] +fn can_win_auction_with_late_randomness() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 1)); + assert_eq!(Balances::reserved_balance(1), 1); + assert_eq!(Balances::free_balance(1), 9); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + run_to_block(8); + // Auction has not yet ended. + assert_eq!(leases(), vec![]); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(2, 0) + ); + // This will prevent the auction's winner from being decided in the next block, since + // the random seed was known before the final bids were made. + set_last_random(H256::zero(), 8); + // Auction definitely ended now, but we don't know exactly when in the last 3 blocks yet + // since no randomness available yet. + run_to_block(9); + // Auction has now ended... But auction winner still not yet decided, so no leases yet. + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::VrfDelay(0) + ); + assert_eq!(leases(), vec![]); + + // Random seed now updated to a value known at block 9, when the auction ended. This + // means that the winner can now be chosen. + set_last_random(H256::zero(), 9); + run_to_block(10); + // Auction ended and winner selected + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 2), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 3), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 4), LeaseData { leaser: 1, amount: 1 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); + }); +} + +#[test] +fn can_win_incomplete_auction() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 4, 4, 5)); + run_to_block(9); + + assert_eq!(leases(), vec![((0.into(), 4), LeaseData { leaser: 1, amount: 5 }),]); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); + }); +} + +#[test] +fn should_choose_best_combination() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 0.into(), 1, 2, 3, 4)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), 0.into(), 1, 4, 4, 2)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 1.into(), 1, 1, 4, 2)); + run_to_block(9); + + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 2), LeaseData { leaser: 2, amount: 4 }), + ((0.into(), 3), LeaseData { leaser: 2, amount: 4 }), + ((0.into(), 4), LeaseData { leaser: 3, amount: 2 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); + assert_eq!(TestLeaser::deposit_held(1.into(), &1), 0); + assert_eq!(TestLeaser::deposit_held(0.into(), &2), 4); + assert_eq!(TestLeaser::deposit_held(0.into(), &3), 2); + }); +} + +#[test] +fn gap_bid_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + + // User 1 will make a bid for period 1 and 4 for the same Para 0 + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 4, 4, 4)); + + // User 2 and 3 will make a bid for para 1 on period 2 and 3 respectively + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), 1.into(), 1, 2, 2, 2)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), 1.into(), 1, 3, 3, 3)); + + // Total reserved should be the max of the two + assert_eq!(Balances::reserved_balance(1), 4); + + // Other people are reserved correctly too + assert_eq!(Balances::reserved_balance(2), 2); + assert_eq!(Balances::reserved_balance(3), 3); + + // End the auction. + run_to_block(9); + + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 4), LeaseData { leaser: 1, amount: 4 }), + ((1.into(), 2), LeaseData { leaser: 2, amount: 2 }), + ((1.into(), 3), LeaseData { leaser: 3, amount: 3 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 4); + assert_eq!(TestLeaser::deposit_held(1.into(), &2), 2); + assert_eq!(TestLeaser::deposit_held(1.into(), &3), 3); + }); +} + +#[test] +fn deposit_credit_should_work() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 5)); + assert_eq!(Balances::reserved_balance(1), 5); + run_to_block(10); + + assert_eq!(leases(), vec![((0.into(), 1), LeaseData { leaser: 1, amount: 5 }),]); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); + + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 2)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 2, 2, 6)); + // Only 1 reserved since we have a deposit credit of 5. + assert_eq!(Balances::reserved_balance(1), 1); + run_to_block(20); + + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 1, amount: 5 }), + ((0.into(), 2), LeaseData { leaser: 1, amount: 6 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 6); + }); +} + +#[test] +fn deposit_credit_on_alt_para_should_not_count() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 1, 5)); + assert_eq!(Balances::reserved_balance(1), 5); + run_to_block(10); + + assert_eq!(leases(), vec![((0.into(), 1), LeaseData { leaser: 1, amount: 5 }),]); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); + + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 2)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 1.into(), 2, 2, 2, 6)); + // 6 reserved since we are bidding on a new para; only works because we don't + assert_eq!(Balances::reserved_balance(1), 6); + run_to_block(20); + + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 1, amount: 5 }), + ((1.into(), 2), LeaseData { leaser: 1, amount: 6 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 5); + assert_eq!(TestLeaser::deposit_held(1.into(), &1), 6); + }); +} + +#[test] +fn multiple_bids_work_pre_ending() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + + for i in 1..6u64 { + run_to_block(i as _); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(i), 0.into(), 1, 1, 4, i)); + for j in 1..6 { + assert_eq!(Balances::reserved_balance(j), if j == i { j } else { 0 }); + assert_eq!(Balances::free_balance(j), if j == i { j * 9 } else { j * 10 }); + } + } + + run_to_block(9); + assert_eq!( + leases(), + vec![ + ((0.into(), 1), LeaseData { leaser: 5, amount: 5 }), + ((0.into(), 2), LeaseData { leaser: 5, amount: 5 }), + ((0.into(), 3), LeaseData { leaser: 5, amount: 5 }), + ((0.into(), 4), LeaseData { leaser: 5, amount: 5 }), + ] + ); + }); +} + +#[test] +fn multiple_bids_work_post_ending() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 0, 1)); + + for i in 1..6u64 { + run_to_block(((i - 1) / 2 + 1) as _); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(i), 0.into(), 1, 1, 4, i)); + for j in 1..6 { + assert_eq!(Balances::reserved_balance(j), if j <= i { j } else { 0 }); + assert_eq!(Balances::free_balance(j), if j <= i { j * 9 } else { j * 10 }); + } + } + for i in 1..6u64 { + assert_eq!(ReservedAmounts::::get((i, ParaId::from(0))).unwrap(), i); + } + + run_to_block(5); + assert_eq!( + leases(), + (1..=4) + .map(|i| ((0.into(), i), LeaseData { leaser: 2, amount: 2 })) + .collect::>() + ); + }); +} + +#[test] +fn incomplete_calculate_winners_works() { + let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; + winning[SlotRange::ThreeThree as u8 as usize] = Some((1, 0.into(), 1)); + + let winners = vec![(1, 0.into(), 1, SlotRange::ThreeThree)]; + + assert_eq!(Auctions::calculate_winners(winning), winners); +} + +#[test] +fn first_incomplete_calculate_winners_works() { + let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; + winning[0] = Some((1, 0.into(), 1)); + + let winners = vec![(1, 0.into(), 1, SlotRange::ZeroZero)]; + + assert_eq!(Auctions::calculate_winners(winning), winners); +} + +#[test] +fn calculate_winners_works() { + let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; + winning[SlotRange::ZeroZero as u8 as usize] = Some((2, 0.into(), 2)); + winning[SlotRange::ZeroThree as u8 as usize] = Some((1, 100.into(), 1)); + winning[SlotRange::OneOne as u8 as usize] = Some((3, 1.into(), 1)); + winning[SlotRange::TwoTwo as u8 as usize] = Some((1, 2.into(), 53)); + winning[SlotRange::ThreeThree as u8 as usize] = Some((5, 3.into(), 1)); + + let winners = vec![ + (2, 0.into(), 2, SlotRange::ZeroZero), + (3, 1.into(), 1, SlotRange::OneOne), + (1, 2.into(), 53, SlotRange::TwoTwo), + (5, 3.into(), 1, SlotRange::ThreeThree), + ]; + assert_eq!(Auctions::calculate_winners(winning), winners); + + winning[SlotRange::ZeroOne as u8 as usize] = Some((4, 10.into(), 3)); + let winners = vec![ + (4, 10.into(), 3, SlotRange::ZeroOne), + (1, 2.into(), 53, SlotRange::TwoTwo), + (5, 3.into(), 1, SlotRange::ThreeThree), + ]; + assert_eq!(Auctions::calculate_winners(winning), winners); + + winning[SlotRange::ZeroThree as u8 as usize] = Some((1, 100.into(), 100)); + let winners = vec![(1, 100.into(), 100, SlotRange::ZeroThree)]; + assert_eq!(Auctions::calculate_winners(winning), winners); +} + +#[test] +fn lower_bids_are_correctly_refunded() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 1, 1)); + let para_1 = ParaId::from(1_u32); + let para_2 = ParaId::from(2_u32); + + // Make a bid and reserve a balance + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), para_1, 1, 1, 4, 9)); + assert_eq!(Balances::reserved_balance(1), 9); + assert_eq!(ReservedAmounts::::get((1, para_1)), Some(9)); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(ReservedAmounts::::get((2, para_2)), None); + + // Bigger bid, reserves new balance and returns funds + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), para_2, 1, 1, 4, 19)); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(ReservedAmounts::::get((1, para_1)), None); + assert_eq!(Balances::reserved_balance(2), 19); + assert_eq!(ReservedAmounts::::get((2, para_2)), Some(19)); + }); +} + +#[test] +fn initialize_winners_in_ending_period_works() { + new_test_ext().execute_with(|| { + let ed: u64 = ::ExistentialDeposit::get(); + assert_eq!(ed, 1); + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 9, 1)); + let para_1 = ParaId::from(1_u32); + let para_2 = ParaId::from(2_u32); + let para_3 = ParaId::from(3_u32); + + // Make bids + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), para_1, 1, 1, 4, 9)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), para_2, 1, 3, 4, 19)); + + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; + winning[SlotRange::ZeroThree as u8 as usize] = Some((1, para_1, 9)); + winning[SlotRange::TwoThree as u8 as usize] = Some((2, para_2, 19)); + assert_eq!(Winning::::get(0), Some(winning)); + + run_to_block(9); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(10); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(0, 0) + ); + assert_eq!(Winning::::get(0), Some(winning)); + + run_to_block(11); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(1, 0) + ); + assert_eq!(Winning::::get(1), Some(winning)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), para_3, 1, 3, 4, 29)); + + run_to_block(12); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(2, 0) + ); + winning[SlotRange::TwoThree as u8 as usize] = Some((3, para_3, 29)); + assert_eq!(Winning::::get(2), Some(winning)); + }); +} + +#[test] +fn handle_bid_requires_registered_para() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_noop!( + Auctions::bid(RuntimeOrigin::signed(1), 1337.into(), 1, 1, 4, 1), + Error::::ParaNotRegistered + ); + assert_ok!(TestRegistrar::::register( + 1, + 1337.into(), + dummy_head_data(), + dummy_validation_code() + )); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 1337.into(), 1, 1, 4, 1)); + }); +} + +#[test] +fn handle_bid_checks_existing_lease_periods() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 2, 3, 1)); + assert_eq!(Balances::reserved_balance(1), 1); + assert_eq!(Balances::free_balance(1), 9); + run_to_block(9); + + assert_eq!( + leases(), + vec![ + ((0.into(), 2), LeaseData { leaser: 1, amount: 1 }), + ((0.into(), 3), LeaseData { leaser: 1, amount: 1 }), + ] + ); + assert_eq!(TestLeaser::deposit_held(0.into(), &1), 1); + + // Para 1 just won an auction above and won some lease periods. + // No bids can work which overlap these periods. + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_noop!( + Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 1, 4, 1), + Error::::AlreadyLeasedOut, + ); + assert_noop!( + Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 1, 2, 1), + Error::::AlreadyLeasedOut, + ); + assert_noop!( + Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 3, 4, 1), + Error::::AlreadyLeasedOut, + ); + // This is okay, not an overlapping bid. + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 2, 1, 1, 1)); + }); +} + +// Here we will test that taking only 10 samples during the ending period works as expected. +#[test] +fn less_winning_samples_work() { + new_test_ext().execute_with(|| { + let ed: u64 = ::ExistentialDeposit::get(); + assert_eq!(ed, 1); + EndingPeriod::set(30); + SampleLength::set(10); + + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 9, 11)); + let para_1 = ParaId::from(1_u32); + let para_2 = ParaId::from(2_u32); + let para_3 = ParaId::from(3_u32); + + // Make bids + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), para_1, 1, 11, 14, 9)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(2), para_2, 1, 13, 14, 19)); + + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + let mut winning = [None; SlotRange::SLOT_RANGE_COUNT]; + winning[SlotRange::ZeroThree as u8 as usize] = Some((1, para_1, 9)); + winning[SlotRange::TwoThree as u8 as usize] = Some((2, para_2, 19)); + assert_eq!(Winning::::get(0), Some(winning)); + + run_to_block(9); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(10); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(0, 0) + ); + assert_eq!(Winning::::get(0), Some(winning)); + + // New bids update the current winning + assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), para_3, 1, 14, 14, 29)); + winning[SlotRange::ThreeThree as u8 as usize] = Some((3, para_3, 29)); + assert_eq!(Winning::::get(0), Some(winning)); + + run_to_block(20); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(1, 0) + ); + assert_eq!(Winning::::get(1), Some(winning)); + run_to_block(25); + // Overbid mid sample + assert_ok!(Auctions::bid(RuntimeOrigin::signed(3), para_3, 1, 13, 14, 29)); + winning[SlotRange::TwoThree as u8 as usize] = Some((3, para_3, 29)); + assert_eq!(Winning::::get(1), Some(winning)); + + run_to_block(30); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(2, 0) + ); + assert_eq!(Winning::::get(2), Some(winning)); + + set_last_random(H256::from([254; 32]), 40); + run_to_block(40); + // Auction ended and winner selected + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + assert_eq!( + leases(), + vec![ + ((3.into(), 13), LeaseData { leaser: 3, amount: 29 }), + ((3.into(), 14), LeaseData { leaser: 3, amount: 29 }), + ] + ); + }); +} + +#[test] +fn auction_status_works() { + new_test_ext().execute_with(|| { + EndingPeriod::set(30); + SampleLength::set(10); + set_last_random(dummy_hash(), 0); + + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 9, 11)); + + run_to_block(9); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::StartingPeriod + ); + + run_to_block(10); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(0, 0) + ); + + run_to_block(11); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(0, 1) + ); + + run_to_block(19); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(0, 9) + ); + + run_to_block(20); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(1, 0) + ); + + run_to_block(25); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(1, 5) + ); + + run_to_block(30); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(2, 0) + ); + + run_to_block(39); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::EndingPeriod(2, 9) + ); + + run_to_block(40); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::VrfDelay(0) + ); + + run_to_block(44); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::VrfDelay(4) + ); + + set_last_random(dummy_hash(), 45); + run_to_block(45); + assert_eq!( + Auctions::auction_status(System::block_number()), + AuctionStatus::::NotStarted + ); + }); +} + +#[test] +fn can_cancel_auction() { + new_test_ext().execute_with(|| { + run_to_block(1); + assert_ok!(Auctions::new_auction(RuntimeOrigin::signed(6), 5, 1)); + assert_ok!(Auctions::bid(RuntimeOrigin::signed(1), 0.into(), 1, 1, 4, 1)); + assert_eq!(Balances::reserved_balance(1), 1); + assert_eq!(Balances::free_balance(1), 9); + + assert_noop!(Auctions::cancel_auction(RuntimeOrigin::signed(6)), BadOrigin); + assert_ok!(Auctions::cancel_auction(RuntimeOrigin::root())); + + assert!(AuctionInfo::::get().is_none()); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(ReservedAmounts::::iter().count(), 0); + assert_eq!(Winning::::iter().count(), 0); + }); +} diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs deleted file mode 100644 index b77cbfeff77c..000000000000 --- a/polkadot/runtime/common/src/claims.rs +++ /dev/null @@ -1,1755 +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 . - -//! Pallet to process claims from Ethereum addresses. - -#[cfg(not(feature = "std"))] -use alloc::{format, string::String}; -use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode, MaxEncodedLen}; -use core::fmt::Debug; -use frame_support::{ - ensure, - traits::{Currency, Get, IsSubType, VestingSchedule}, - weights::Weight, - DefaultNoBound, -}; -pub use pallet::*; -use polkadot_primitives::ValidityError; -use scale_info::TypeInfo; -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; -use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; -use sp_runtime::{ - impl_tx_ext_default, - traits::{ - AsSystemOriginSigner, AsTransactionAuthorizedOrigin, CheckedSub, DispatchInfoOf, - Dispatchable, TransactionExtension, Zero, - }, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, - }, - RuntimeDebug, -}; - -type CurrencyOf = <::VestingSchedule as VestingSchedule< - ::AccountId, ->>::Currency; -type BalanceOf = as Currency<::AccountId>>::Balance; - -pub trait WeightInfo { - fn claim() -> Weight; - fn mint_claim() -> Weight; - fn claim_attest() -> Weight; - fn attest() -> Weight; - fn move_claim() -> Weight; - fn prevalidate_attests() -> Weight; -} - -pub struct TestWeightInfo; -impl WeightInfo for TestWeightInfo { - fn claim() -> Weight { - Weight::zero() - } - fn mint_claim() -> Weight { - Weight::zero() - } - fn claim_attest() -> Weight { - Weight::zero() - } - fn attest() -> Weight { - Weight::zero() - } - fn move_claim() -> Weight { - Weight::zero() - } - fn prevalidate_attests() -> Weight { - Weight::zero() - } -} - -/// The kind of statement an account needs to make for a claim to be valid. -#[derive( - Encode, - Decode, - Clone, - Copy, - Eq, - PartialEq, - RuntimeDebug, - TypeInfo, - Serialize, - Deserialize, - MaxEncodedLen, -)] -pub enum StatementKind { - /// Statement required to be made by non-SAFT holders. - Regular, - /// Statement required to be made by SAFT holders. - Saft, -} - -impl StatementKind { - /// Convert this to the (English) statement it represents. - fn to_text(self) -> &'static [u8] { - match self { - StatementKind::Regular => - &b"I hereby agree to the terms of the statement whose SHA-256 multihash is \ - Qmc1XYqT6S39WNp2UeiRUrZichUWUPpGEThDE6dAb3f6Ny. (This may be found at the URL: \ - https://statement.polkadot.network/regular.html)"[..], - StatementKind::Saft => - &b"I hereby agree to the terms of the statement whose SHA-256 multihash is \ - QmXEkMahfhHJPzT3RjkXiZVFi77ZeVeuxtAjhojGRNYckz. (This may be found at the URL: \ - https://statement.polkadot.network/saft.html)"[..], - } - } -} - -impl Default for StatementKind { - fn default() -> Self { - StatementKind::Regular - } -} - -/// An Ethereum address (i.e. 20 bytes, used to represent an Ethereum account). -/// -/// This gets serialized to the 0x-prefixed hex representation. -#[derive( - Clone, Copy, PartialEq, Eq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, -)] -pub struct EthereumAddress([u8; 20]); - -impl Serialize for EthereumAddress { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let hex: String = rustc_hex::ToHex::to_hex(&self.0[..]); - serializer.serialize_str(&format!("0x{}", hex)) - } -} - -impl<'de> Deserialize<'de> for EthereumAddress { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let base_string = String::deserialize(deserializer)?; - let offset = if base_string.starts_with("0x") { 2 } else { 0 }; - let s = &base_string[offset..]; - if s.len() != 40 { - Err(serde::de::Error::custom( - "Bad length of Ethereum address (should be 42 including '0x')", - ))?; - } - let raw: Vec = rustc_hex::FromHex::from_hex(s) - .map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?; - let mut r = Self::default(); - r.0.copy_from_slice(&raw); - Ok(r) - } -} - -#[derive(Encode, Decode, Clone, TypeInfo, MaxEncodedLen)] -pub struct EcdsaSignature(pub [u8; 65]); - -impl PartialEq for EcdsaSignature { - fn eq(&self, other: &Self) -> bool { - &self.0[..] == &other.0[..] - } -} - -impl core::fmt::Debug for EcdsaSignature { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "EcdsaSignature({:?})", &self.0[..]) - } -} - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - pub struct Pallet(_); - - /// Configuration trait. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type VestingSchedule: VestingSchedule>; - #[pallet::constant] - type Prefix: Get<&'static [u8]>; - type MoveClaimOrigin: EnsureOrigin; - type WeightInfo: WeightInfo; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// Someone claimed some DOTs. - Claimed { who: T::AccountId, ethereum_address: EthereumAddress, amount: BalanceOf }, - } - - #[pallet::error] - pub enum Error { - /// Invalid Ethereum signature. - InvalidEthereumSignature, - /// Ethereum address has no claim. - SignerHasNoClaim, - /// Account ID sending transaction has no claim. - SenderHasNoClaim, - /// There's not enough in the pot to pay out some unvested amount. Generally implies a - /// logic error. - PotUnderflow, - /// A needed statement was not included. - InvalidStatement, - /// The account already has a vested balance. - VestedBalanceExists, - } - - #[pallet::storage] - pub type Claims = StorageMap<_, Identity, EthereumAddress, BalanceOf>; - - #[pallet::storage] - pub type Total = StorageValue<_, BalanceOf, ValueQuery>; - - /// Vesting schedule for a claim. - /// First balance is the total amount that should be held for vesting. - /// Second balance is how much should be unlocked per block. - /// The block number is when the vesting should start. - #[pallet::storage] - pub type Vesting = - StorageMap<_, Identity, EthereumAddress, (BalanceOf, BalanceOf, BlockNumberFor)>; - - /// The statement kind that must be signed, if any. - #[pallet::storage] - pub(super) type Signing = StorageMap<_, Identity, EthereumAddress, StatementKind>; - - /// Pre-claimed Ethereum accounts, by the Account ID that they are claimed to. - #[pallet::storage] - pub(super) type Preclaims = StorageMap<_, Identity, T::AccountId, EthereumAddress>; - - #[pallet::genesis_config] - #[derive(DefaultNoBound)] - pub struct GenesisConfig { - pub claims: - Vec<(EthereumAddress, BalanceOf, Option, Option)>, - pub vesting: Vec<(EthereumAddress, (BalanceOf, BalanceOf, BlockNumberFor))>, - } - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - // build `Claims` - self.claims.iter().map(|(a, b, _, _)| (*a, *b)).for_each(|(a, b)| { - Claims::::insert(a, b); - }); - // build `Total` - Total::::put( - self.claims - .iter() - .fold(Zero::zero(), |acc: BalanceOf, &(_, b, _, _)| acc + b), - ); - // build `Vesting` - self.vesting.iter().for_each(|(k, v)| { - Vesting::::insert(k, v); - }); - // build `Signing` - self.claims - .iter() - .filter_map(|(a, _, _, s)| Some((*a, (*s)?))) - .for_each(|(a, s)| { - Signing::::insert(a, s); - }); - // build `Preclaims` - self.claims.iter().filter_map(|(a, _, i, _)| Some((i.clone()?, *a))).for_each( - |(i, a)| { - Preclaims::::insert(i, a); - }, - ); - } - } - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet { - /// Make a claim to collect your DOTs. - /// - /// The dispatch origin for this call must be _None_. - /// - /// Unsigned Validation: - /// A call to claim is deemed valid if the signature provided matches - /// the expected signed message of: - /// - /// > Ethereum Signed Message: - /// > (configured prefix string)(address) - /// - /// and `address` matches the `dest` account. - /// - /// Parameters: - /// - `dest`: The destination account to payout the claim. - /// - `ethereum_signature`: The signature of an ethereum signed message matching the format - /// described above. - /// - /// - /// The weight of this call is invariant over the input parameters. - /// Weight includes logic to validate unsigned `claim` call. - /// - /// Total Complexity: O(1) - /// - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::claim())] - pub fn claim( - origin: OriginFor, - dest: T::AccountId, - ethereum_signature: EcdsaSignature, - ) -> DispatchResult { - ensure_none(origin)?; - - let data = dest.using_encoded(to_ascii_hex); - let signer = Self::eth_recover(ðereum_signature, &data, &[][..]) - .ok_or(Error::::InvalidEthereumSignature)?; - ensure!(Signing::::get(&signer).is_none(), Error::::InvalidStatement); - - Self::process_claim(signer, dest)?; - Ok(()) - } - - /// Mint a new claim to collect DOTs. - /// - /// The dispatch origin for this call must be _Root_. - /// - /// Parameters: - /// - `who`: The Ethereum address allowed to collect this claim. - /// - `value`: The number of DOTs that will be claimed. - /// - `vesting_schedule`: An optional vesting schedule for these DOTs. - /// - /// - /// The weight of this call is invariant over the input parameters. - /// We assume worst case that both vesting and statement is being inserted. - /// - /// Total Complexity: O(1) - /// - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::mint_claim())] - pub fn mint_claim( - origin: OriginFor, - who: EthereumAddress, - value: BalanceOf, - vesting_schedule: Option<(BalanceOf, BalanceOf, BlockNumberFor)>, - statement: Option, - ) -> DispatchResult { - ensure_root(origin)?; - - Total::::mutate(|t| *t += value); - Claims::::insert(who, value); - if let Some(vs) = vesting_schedule { - Vesting::::insert(who, vs); - } - if let Some(s) = statement { - Signing::::insert(who, s); - } - Ok(()) - } - - /// Make a claim to collect your DOTs by signing a statement. - /// - /// The dispatch origin for this call must be _None_. - /// - /// Unsigned Validation: - /// A call to `claim_attest` is deemed valid if the signature provided matches - /// the expected signed message of: - /// - /// > Ethereum Signed Message: - /// > (configured prefix string)(address)(statement) - /// - /// and `address` matches the `dest` account; the `statement` must match that which is - /// expected according to your purchase arrangement. - /// - /// Parameters: - /// - `dest`: The destination account to payout the claim. - /// - `ethereum_signature`: The signature of an ethereum signed message matching the format - /// described above. - /// - `statement`: The identity of the statement which is being attested to in the - /// signature. - /// - /// - /// The weight of this call is invariant over the input parameters. - /// Weight includes logic to validate unsigned `claim_attest` call. - /// - /// Total Complexity: O(1) - /// - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::claim_attest())] - pub fn claim_attest( - origin: OriginFor, - dest: T::AccountId, - ethereum_signature: EcdsaSignature, - statement: Vec, - ) -> DispatchResult { - ensure_none(origin)?; - - let data = dest.using_encoded(to_ascii_hex); - let signer = Self::eth_recover(ðereum_signature, &data, &statement) - .ok_or(Error::::InvalidEthereumSignature)?; - if let Some(s) = Signing::::get(signer) { - ensure!(s.to_text() == &statement[..], Error::::InvalidStatement); - } - Self::process_claim(signer, dest)?; - Ok(()) - } - - /// Attest to a statement, needed to finalize the claims process. - /// - /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a - /// `TransactionExtension`. - /// - /// Unsigned Validation: - /// A call to attest is deemed valid if the sender has a `Preclaim` registered - /// and provides a `statement` which is expected for the account. - /// - /// Parameters: - /// - `statement`: The identity of the statement which is being attested to in the - /// signature. - /// - /// - /// The weight of this call is invariant over the input parameters. - /// Weight includes logic to do pre-validation on `attest` call. - /// - /// Total Complexity: O(1) - /// - #[pallet::call_index(3)] - #[pallet::weight(( - T::WeightInfo::attest(), - DispatchClass::Normal, - Pays::No - ))] - pub fn attest(origin: OriginFor, statement: Vec) -> DispatchResult { - let who = ensure_signed(origin)?; - let signer = Preclaims::::get(&who).ok_or(Error::::SenderHasNoClaim)?; - if let Some(s) = Signing::::get(signer) { - ensure!(s.to_text() == &statement[..], Error::::InvalidStatement); - } - Self::process_claim(signer, who.clone())?; - Preclaims::::remove(&who); - Ok(()) - } - - #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::move_claim())] - pub fn move_claim( - origin: OriginFor, - old: EthereumAddress, - new: EthereumAddress, - maybe_preclaim: Option, - ) -> DispatchResultWithPostInfo { - T::MoveClaimOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?; - - Claims::::take(&old).map(|c| Claims::::insert(&new, c)); - Vesting::::take(&old).map(|c| Vesting::::insert(&new, c)); - Signing::::take(&old).map(|c| Signing::::insert(&new, c)); - maybe_preclaim.map(|preclaim| { - Preclaims::::mutate(&preclaim, |maybe_o| { - if maybe_o.as_ref().map_or(false, |o| o == &old) { - *maybe_o = Some(new) - } - }) - }); - Ok(Pays::No.into()) - } - } - - #[pallet::validate_unsigned] - impl ValidateUnsigned for Pallet { - type Call = Call; - - fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - const PRIORITY: u64 = 100; - - let (maybe_signer, maybe_statement) = match call { - // - // The weight of this logic is included in the `claim` dispatchable. - // - Call::claim { dest: account, ethereum_signature } => { - let data = account.using_encoded(to_ascii_hex); - (Self::eth_recover(ðereum_signature, &data, &[][..]), None) - }, - // - // The weight of this logic is included in the `claim_attest` dispatchable. - // - Call::claim_attest { dest: account, ethereum_signature, statement } => { - let data = account.using_encoded(to_ascii_hex); - ( - Self::eth_recover(ðereum_signature, &data, &statement), - Some(statement.as_slice()), - ) - }, - _ => return Err(InvalidTransaction::Call.into()), - }; - - let signer = maybe_signer.ok_or(InvalidTransaction::Custom( - ValidityError::InvalidEthereumSignature.into(), - ))?; - - let e = InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()); - ensure!(Claims::::contains_key(&signer), e); - - let e = InvalidTransaction::Custom(ValidityError::InvalidStatement.into()); - match Signing::::get(signer) { - None => ensure!(maybe_statement.is_none(), e), - Some(s) => ensure!(Some(s.to_text()) == maybe_statement, e), - } - - Ok(ValidTransaction { - priority: PRIORITY, - requires: vec![], - provides: vec![("claims", signer).encode()], - longevity: TransactionLongevity::max_value(), - propagate: true, - }) - } - } -} - -/// Converts the given binary data into ASCII-encoded hex. It will be twice the length. -fn to_ascii_hex(data: &[u8]) -> Vec { - let mut r = Vec::with_capacity(data.len() * 2); - let mut push_nibble = |n| r.push(if n < 10 { b'0' + n } else { b'a' - 10 + n }); - for &b in data.iter() { - push_nibble(b / 16); - push_nibble(b % 16); - } - r -} - -impl Pallet { - // Constructs the message that Ethereum RPC's `personal_sign` and `eth_sign` would sign. - fn ethereum_signable_message(what: &[u8], extra: &[u8]) -> Vec { - let prefix = T::Prefix::get(); - let mut l = prefix.len() + what.len() + extra.len(); - let mut rev = Vec::new(); - while l > 0 { - rev.push(b'0' + (l % 10) as u8); - l /= 10; - } - let mut v = b"\x19Ethereum Signed Message:\n".to_vec(); - v.extend(rev.into_iter().rev()); - v.extend_from_slice(prefix); - v.extend_from_slice(what); - v.extend_from_slice(extra); - v - } - - // Attempts to recover the Ethereum address from a message signature signed by using - // the Ethereum RPC's `personal_sign` and `eth_sign`. - fn eth_recover(s: &EcdsaSignature, what: &[u8], extra: &[u8]) -> Option { - let msg = keccak_256(&Self::ethereum_signable_message(what, extra)); - let mut res = EthereumAddress::default(); - res.0 - .copy_from_slice(&keccak_256(&secp256k1_ecdsa_recover(&s.0, &msg).ok()?[..])[12..]); - Some(res) - } - - fn process_claim(signer: EthereumAddress, dest: T::AccountId) -> sp_runtime::DispatchResult { - let balance_due = Claims::::get(&signer).ok_or(Error::::SignerHasNoClaim)?; - - let new_total = - Total::::get().checked_sub(&balance_due).ok_or(Error::::PotUnderflow)?; - - let vesting = Vesting::::get(&signer); - if vesting.is_some() && T::VestingSchedule::vesting_balance(&dest).is_some() { - return Err(Error::::VestedBalanceExists.into()) - } - - // We first need to deposit the balance to ensure that the account exists. - let _ = CurrencyOf::::deposit_creating(&dest, balance_due); - - // Check if this claim should have a vesting schedule. - if let Some(vs) = vesting { - // This can only fail if the account already has a vesting schedule, - // but this is checked above. - T::VestingSchedule::add_vesting_schedule(&dest, vs.0, vs.1, vs.2) - .expect("No other vesting schedule exists, as checked above; qed"); - } - - Total::::put(new_total); - Claims::::remove(&signer); - Vesting::::remove(&signer); - Signing::::remove(&signer); - - // Let's deposit an event to let the outside world know this happened. - Self::deposit_event(Event::::Claimed { - who: dest, - ethereum_address: signer, - amount: balance_due, - }); - - Ok(()) - } -} - -/// Validate `attest` calls prior to execution. Needed to avoid a DoS attack since they are -/// otherwise free to place on chain. -#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct PrevalidateAttests(core::marker::PhantomData); - -impl Debug for PrevalidateAttests -where - ::RuntimeCall: IsSubType>, -{ - #[cfg(feature = "std")] - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "PrevalidateAttests") - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result { - Ok(()) - } -} - -impl PrevalidateAttests -where - ::RuntimeCall: IsSubType>, -{ - /// Create new `TransactionExtension` to check runtime version. - pub fn new() -> Self { - Self(core::marker::PhantomData) - } -} - -impl TransactionExtension for PrevalidateAttests -where - ::RuntimeCall: IsSubType>, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: - AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, -{ - const IDENTIFIER: &'static str = "PrevalidateAttests"; - type Implicit = (); - type Pre = (); - type Val = (); - - fn weight(&self, call: &T::RuntimeCall) -> Weight { - if let Some(Call::attest { .. }) = call.is_sub_type() { - T::WeightInfo::prevalidate_attests() - } else { - Weight::zero() - } - } - - fn validate( - &self, - origin: ::RuntimeOrigin, - call: &T::RuntimeCall, - _info: &DispatchInfoOf, - _len: usize, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { - if let Some(Call::attest { statement: attested_statement }) = call.is_sub_type() { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - let signer = Preclaims::::get(who) - .ok_or(InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()))?; - if let Some(s) = Signing::::get(signer) { - let e = InvalidTransaction::Custom(ValidityError::InvalidStatement.into()); - ensure!(&attested_statement[..] == s.to_text(), e); - } - } - Ok((ValidTransaction::default(), (), origin)) - } - - impl_tx_ext_default!(T::RuntimeCall; prepare); -} - -#[cfg(any(test, feature = "runtime-benchmarks"))] -mod secp_utils { - use super::*; - - pub fn public(secret: &libsecp256k1::SecretKey) -> libsecp256k1::PublicKey { - libsecp256k1::PublicKey::from_secret_key(secret) - } - pub fn eth(secret: &libsecp256k1::SecretKey) -> EthereumAddress { - let mut res = EthereumAddress::default(); - res.0.copy_from_slice(&keccak_256(&public(secret).serialize()[1..65])[12..]); - res - } - pub fn sig( - secret: &libsecp256k1::SecretKey, - what: &[u8], - extra: &[u8], - ) -> EcdsaSignature { - let msg = keccak_256(&super::Pallet::::ethereum_signable_message( - &to_ascii_hex(what)[..], - extra, - )); - let (sig, recovery_id) = libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), secret); - let mut r = [0u8; 65]; - r[0..64].copy_from_slice(&sig.serialize()[..]); - r[64] = recovery_id.serialize(); - EcdsaSignature(r) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use hex_literal::hex; - use secp_utils::*; - - use codec::Encode; - // The testing primitives are very useful for avoiding having to work with signatures - // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. - use crate::claims; - use claims::Call as ClaimsCall; - use frame_support::{ - assert_err, assert_noop, assert_ok, derive_impl, - dispatch::{GetDispatchInfo, Pays}, - ord_parameter_types, parameter_types, - traits::{ExistenceRequirement, WithdrawReasons}, - }; - use pallet_balances; - use sp_runtime::{ - traits::{DispatchTransaction, Identity}, - transaction_validity::TransactionLongevity, - BuildStorage, - DispatchError::BadOrigin, - TokenError, - }; - - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Vesting: pallet_vesting, - Claims: claims, - } - ); - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] - impl frame_system::Config for Test { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type AccountData = pallet_balances::AccountData; - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] - impl pallet_balances::Config for Test { - type AccountStore = System; - } - - parameter_types! { - pub const MinVestedTransfer: u64 = 1; - pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); - } - - impl pallet_vesting::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BlockNumberToBalance = Identity; - type MinVestedTransfer = MinVestedTransfer; - type WeightInfo = (); - type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; - type BlockNumberProvider = System; - const MAX_VESTING_SCHEDULES: u32 = 28; - } - - parameter_types! { - pub Prefix: &'static [u8] = b"Pay RUSTs to the TEST account:"; - } - ord_parameter_types! { - pub const Six: u64 = 6; - } - - impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type VestingSchedule = Vesting; - type Prefix = Prefix; - type MoveClaimOrigin = frame_system::EnsureSignedBy; - type WeightInfo = TestWeightInfo; - } - - fn alice() -> libsecp256k1::SecretKey { - libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap() - } - fn bob() -> libsecp256k1::SecretKey { - libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() - } - fn dave() -> libsecp256k1::SecretKey { - libsecp256k1::SecretKey::parse(&keccak_256(b"Dave")).unwrap() - } - fn eve() -> libsecp256k1::SecretKey { - libsecp256k1::SecretKey::parse(&keccak_256(b"Eve")).unwrap() - } - fn frank() -> libsecp256k1::SecretKey { - libsecp256k1::SecretKey::parse(&keccak_256(b"Frank")).unwrap() - } - - // This function basically just builds a genesis storage key/value store according to - // our desired mockup. - pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - // We use default for brevity, but you can configure as desired if needed. - pallet_balances::GenesisConfig::::default() - .assimilate_storage(&mut t) - .unwrap(); - claims::GenesisConfig:: { - claims: vec![ - (eth(&alice()), 100, None, None), - (eth(&dave()), 200, None, Some(StatementKind::Regular)), - (eth(&eve()), 300, Some(42), Some(StatementKind::Saft)), - (eth(&frank()), 400, Some(43), None), - ], - vesting: vec![(eth(&alice()), (50, 10, 1))], - } - .assimilate_storage(&mut t) - .unwrap(); - t.into() - } - - fn total_claims() -> u64 { - 100 + 200 + 300 + 400 - } - - #[test] - fn basic_setup_works() { - new_test_ext().execute_with(|| { - assert_eq!(claims::Total::::get(), total_claims()); - assert_eq!(claims::Claims::::get(ð(&alice())), Some(100)); - assert_eq!(claims::Claims::::get(ð(&dave())), Some(200)); - assert_eq!(claims::Claims::::get(ð(&eve())), Some(300)); - assert_eq!(claims::Claims::::get(ð(&frank())), Some(400)); - assert_eq!(claims::Claims::::get(&EthereumAddress::default()), None); - assert_eq!(claims::Vesting::::get(ð(&alice())), Some((50, 10, 1))); - }); - } - - #[test] - fn serde_works() { - let x = EthereumAddress(hex!["0123456789abcdef0123456789abcdef01234567"]); - let y = serde_json::to_string(&x).unwrap(); - assert_eq!(y, "\"0x0123456789abcdef0123456789abcdef01234567\""); - let z: EthereumAddress = serde_json::from_str(&y).unwrap(); - assert_eq!(x, z); - } - - #[test] - fn claiming_works() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - )); - assert_eq!(Balances::free_balance(&42), 100); - assert_eq!(Vesting::vesting_balance(&42), Some(50)); - assert_eq!(claims::Total::::get(), total_claims() - 100); - }); - } - - #[test] - fn basic_claim_moving_works() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_noop!( - Claims::move_claim(RuntimeOrigin::signed(1), eth(&alice()), eth(&bob()), None), - BadOrigin - ); - assert_ok!(Claims::move_claim( - RuntimeOrigin::signed(6), - eth(&alice()), - eth(&bob()), - None - )); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - ), - Error::::SignerHasNoClaim - ); - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&bob(), &42u64.encode(), &[][..]) - )); - assert_eq!(Balances::free_balance(&42), 100); - assert_eq!(Vesting::vesting_balance(&42), Some(50)); - assert_eq!(claims::Total::::get(), total_claims() - 100); - }); - } - - #[test] - fn claim_attest_moving_works() { - new_test_ext().execute_with(|| { - assert_ok!(Claims::move_claim( - RuntimeOrigin::signed(6), - eth(&dave()), - eth(&bob()), - None - )); - let s = sig::(&bob(), &42u64.encode(), StatementKind::Regular.to_text()); - assert_ok!(Claims::claim_attest( - RuntimeOrigin::none(), - 42, - s, - StatementKind::Regular.to_text().to_vec() - )); - assert_eq!(Balances::free_balance(&42), 200); - }); - } - - #[test] - fn attest_moving_works() { - new_test_ext().execute_with(|| { - assert_ok!(Claims::move_claim( - RuntimeOrigin::signed(6), - eth(&eve()), - eth(&bob()), - Some(42) - )); - assert_ok!(Claims::attest( - RuntimeOrigin::signed(42), - StatementKind::Saft.to_text().to_vec() - )); - assert_eq!(Balances::free_balance(&42), 300); - }); - } - - #[test] - fn claiming_does_not_bypass_signing() { - new_test_ext().execute_with(|| { - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - )); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&dave(), &42u64.encode(), &[][..]) - ), - Error::::InvalidStatement, - ); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&eve(), &42u64.encode(), &[][..]) - ), - Error::::InvalidStatement, - ); - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&frank(), &42u64.encode(), &[][..]) - )); - }); - } - - #[test] - fn attest_claiming_works() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - let s = sig::(&dave(), &42u64.encode(), StatementKind::Saft.to_text()); - let r = Claims::claim_attest( - RuntimeOrigin::none(), - 42, - s.clone(), - StatementKind::Saft.to_text().to_vec(), - ); - assert_noop!(r, Error::::InvalidStatement); - - let r = Claims::claim_attest( - RuntimeOrigin::none(), - 42, - s, - StatementKind::Regular.to_text().to_vec(), - ); - assert_noop!(r, Error::::SignerHasNoClaim); - // ^^^ we use ecdsa_recover, so an invalid signature just results in a random signer id - // being recovered, which realistically will never have a claim. - - let s = sig::(&dave(), &42u64.encode(), StatementKind::Regular.to_text()); - assert_ok!(Claims::claim_attest( - RuntimeOrigin::none(), - 42, - s, - StatementKind::Regular.to_text().to_vec() - )); - assert_eq!(Balances::free_balance(&42), 200); - assert_eq!(claims::Total::::get(), total_claims() - 200); - - let s = sig::(&dave(), &42u64.encode(), StatementKind::Regular.to_text()); - let r = Claims::claim_attest( - RuntimeOrigin::none(), - 42, - s, - StatementKind::Regular.to_text().to_vec(), - ); - assert_noop!(r, Error::::SignerHasNoClaim); - }); - } - - #[test] - fn attesting_works() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_noop!( - Claims::attest(RuntimeOrigin::signed(69), StatementKind::Saft.to_text().to_vec()), - Error::::SenderHasNoClaim - ); - assert_noop!( - Claims::attest( - RuntimeOrigin::signed(42), - StatementKind::Regular.to_text().to_vec() - ), - Error::::InvalidStatement - ); - assert_ok!(Claims::attest( - RuntimeOrigin::signed(42), - StatementKind::Saft.to_text().to_vec() - )); - assert_eq!(Balances::free_balance(&42), 300); - assert_eq!(claims::Total::::get(), total_claims() - 300); - }); - } - - #[test] - fn claim_cannot_clobber_preclaim() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - // Alice's claim is 100 - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - )); - assert_eq!(Balances::free_balance(&42), 100); - // Eve's claim is 300 through Account 42 - assert_ok!(Claims::attest( - RuntimeOrigin::signed(42), - StatementKind::Saft.to_text().to_vec() - )); - assert_eq!(Balances::free_balance(&42), 100 + 300); - assert_eq!(claims::Total::::get(), total_claims() - 400); - }); - } - - #[test] - fn valid_attest_transactions_are_free() { - new_test_ext().execute_with(|| { - let p = PrevalidateAttests::::new(); - let c = RuntimeCall::Claims(ClaimsCall::attest { - statement: StatementKind::Saft.to_text().to_vec(), - }); - let di = c.get_dispatch_info(); - assert_eq!(di.pays_fee, Pays::No); - let r = p.validate_only(Some(42).into(), &c, &di, 20); - assert_eq!(r.unwrap().0, ValidTransaction::default()); - }); - } - - #[test] - fn invalid_attest_transactions_are_recognized() { - new_test_ext().execute_with(|| { - let p = PrevalidateAttests::::new(); - let c = RuntimeCall::Claims(ClaimsCall::attest { - statement: StatementKind::Regular.to_text().to_vec(), - }); - let di = c.get_dispatch_info(); - let r = p.validate_only(Some(42).into(), &c, &di, 20); - assert!(r.is_err()); - let c = RuntimeCall::Claims(ClaimsCall::attest { - statement: StatementKind::Saft.to_text().to_vec(), - }); - let di = c.get_dispatch_info(); - let r = p.validate_only(Some(69).into(), &c, &di, 20); - assert!(r.is_err()); - }); - } - - #[test] - fn cannot_bypass_attest_claiming() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - let s = sig::(&dave(), &42u64.encode(), &[]); - let r = Claims::claim(RuntimeOrigin::none(), 42, s.clone()); - assert_noop!(r, Error::::InvalidStatement); - }); - } - - #[test] - fn add_claim_works() { - new_test_ext().execute_with(|| { - assert_noop!( - Claims::mint_claim(RuntimeOrigin::signed(42), eth(&bob()), 200, None, None), - sp_runtime::traits::BadOrigin, - ); - assert_eq!(Balances::free_balance(42), 0); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 69, - sig::(&bob(), &69u64.encode(), &[][..]) - ), - Error::::SignerHasNoClaim, - ); - assert_ok!(Claims::mint_claim(RuntimeOrigin::root(), eth(&bob()), 200, None, None)); - assert_eq!(claims::Total::::get(), total_claims() + 200); - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 69, - sig::(&bob(), &69u64.encode(), &[][..]) - )); - assert_eq!(Balances::free_balance(&69), 200); - assert_eq!(Vesting::vesting_balance(&69), None); - assert_eq!(claims::Total::::get(), total_claims()); - }); - } - - #[test] - fn add_claim_with_vesting_works() { - new_test_ext().execute_with(|| { - assert_noop!( - Claims::mint_claim( - RuntimeOrigin::signed(42), - eth(&bob()), - 200, - Some((50, 10, 1)), - None - ), - sp_runtime::traits::BadOrigin, - ); - assert_eq!(Balances::free_balance(42), 0); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 69, - sig::(&bob(), &69u64.encode(), &[][..]) - ), - Error::::SignerHasNoClaim, - ); - assert_ok!(Claims::mint_claim( - RuntimeOrigin::root(), - eth(&bob()), - 200, - Some((50, 10, 1)), - None - )); - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 69, - sig::(&bob(), &69u64.encode(), &[][..]) - )); - assert_eq!(Balances::free_balance(&69), 200); - assert_eq!(Vesting::vesting_balance(&69), Some(50)); - - // Make sure we can not transfer the vested balance. - assert_err!( - >::transfer( - &69, - &80, - 180, - ExistenceRequirement::AllowDeath - ), - TokenError::Frozen, - ); - }); - } - - #[test] - fn add_claim_with_statement_works() { - new_test_ext().execute_with(|| { - assert_noop!( - Claims::mint_claim( - RuntimeOrigin::signed(42), - eth(&bob()), - 200, - None, - Some(StatementKind::Regular) - ), - sp_runtime::traits::BadOrigin, - ); - assert_eq!(Balances::free_balance(42), 0); - let signature = sig::(&bob(), &69u64.encode(), StatementKind::Regular.to_text()); - assert_noop!( - Claims::claim_attest( - RuntimeOrigin::none(), - 69, - signature.clone(), - StatementKind::Regular.to_text().to_vec() - ), - Error::::SignerHasNoClaim - ); - assert_ok!(Claims::mint_claim( - RuntimeOrigin::root(), - eth(&bob()), - 200, - None, - Some(StatementKind::Regular) - )); - assert_noop!( - Claims::claim_attest(RuntimeOrigin::none(), 69, signature.clone(), vec![],), - Error::::SignerHasNoClaim - ); - assert_ok!(Claims::claim_attest( - RuntimeOrigin::none(), - 69, - signature.clone(), - StatementKind::Regular.to_text().to_vec() - )); - assert_eq!(Balances::free_balance(&69), 200); - }); - } - - #[test] - fn origin_signed_claiming_fail() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_err!( - Claims::claim( - RuntimeOrigin::signed(42), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - ), - sp_runtime::traits::BadOrigin, - ); - }); - } - - #[test] - fn double_claiming_doesnt_work() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_ok!(Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - )); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &42u64.encode(), &[][..]) - ), - Error::::SignerHasNoClaim - ); - }); - } - - #[test] - fn claiming_while_vested_doesnt_work() { - new_test_ext().execute_with(|| { - CurrencyOf::::make_free_balance_be(&69, total_claims()); - assert_eq!(Balances::free_balance(69), total_claims()); - // A user is already vested - assert_ok!(::VestingSchedule::add_vesting_schedule( - &69, - total_claims(), - 100, - 10 - )); - assert_ok!(Claims::mint_claim( - RuntimeOrigin::root(), - eth(&bob()), - 200, - Some((50, 10, 1)), - None - )); - // New total - assert_eq!(claims::Total::::get(), total_claims() + 200); - - // They should not be able to claim - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 69, - sig::(&bob(), &69u64.encode(), &[][..]) - ), - Error::::VestedBalanceExists, - ); - }); - } - - #[test] - fn non_sender_sig_doesnt_work() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&alice(), &69u64.encode(), &[][..]) - ), - Error::::SignerHasNoClaim - ); - }); - } - - #[test] - fn non_claimant_doesnt_work() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(42), 0); - assert_noop!( - Claims::claim( - RuntimeOrigin::none(), - 42, - sig::(&bob(), &69u64.encode(), &[][..]) - ), - Error::::SignerHasNoClaim - ); - }); - } - - #[test] - fn real_eth_sig_works() { - new_test_ext().execute_with(|| { - // "Pay RUSTs to the TEST account:2a00000000000000" - let sig = hex!["444023e89b67e67c0562ed0305d252a5dd12b2af5ac51d6d3cb69a0b486bc4b3191401802dc29d26d586221f7256cd3329fe82174bdf659baea149a40e1c495d1c"]; - let sig = EcdsaSignature(sig); - let who = 42u64.using_encoded(to_ascii_hex); - let signer = Claims::eth_recover(&sig, &who, &[][..]).unwrap(); - assert_eq!(signer.0, hex!["6d31165d5d932d571f3b44695653b46dcc327e84"]); - }); - } - - #[test] - fn validate_unsigned_works() { - use sp_runtime::traits::ValidateUnsigned; - let source = sp_runtime::transaction_validity::TransactionSource::External; - - new_test_ext().execute_with(|| { - assert_eq!( - Pallet::::validate_unsigned( - source, - &ClaimsCall::claim { - dest: 1, - ethereum_signature: sig::(&alice(), &1u64.encode(), &[][..]) - } - ), - Ok(ValidTransaction { - priority: 100, - requires: vec![], - provides: vec![("claims", eth(&alice())).encode()], - longevity: TransactionLongevity::max_value(), - propagate: true, - }) - ); - assert_eq!( - Pallet::::validate_unsigned( - source, - &ClaimsCall::claim { dest: 0, ethereum_signature: EcdsaSignature([0; 65]) } - ), - InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()).into(), - ); - assert_eq!( - Pallet::::validate_unsigned( - source, - &ClaimsCall::claim { - dest: 1, - ethereum_signature: sig::(&bob(), &1u64.encode(), &[][..]) - } - ), - InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(), - ); - let s = sig::(&dave(), &1u64.encode(), StatementKind::Regular.to_text()); - let call = ClaimsCall::claim_attest { - dest: 1, - ethereum_signature: s, - statement: StatementKind::Regular.to_text().to_vec(), - }; - assert_eq!( - Pallet::::validate_unsigned(source, &call), - Ok(ValidTransaction { - priority: 100, - requires: vec![], - provides: vec![("claims", eth(&dave())).encode()], - longevity: TransactionLongevity::max_value(), - propagate: true, - }) - ); - assert_eq!( - Pallet::::validate_unsigned( - source, - &ClaimsCall::claim_attest { - dest: 1, - ethereum_signature: EcdsaSignature([0; 65]), - statement: StatementKind::Regular.to_text().to_vec() - } - ), - InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()).into(), - ); - - let s = sig::(&bob(), &1u64.encode(), StatementKind::Regular.to_text()); - let call = ClaimsCall::claim_attest { - dest: 1, - ethereum_signature: s, - statement: StatementKind::Regular.to_text().to_vec(), - }; - assert_eq!( - Pallet::::validate_unsigned(source, &call), - InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(), - ); - - let s = sig::(&dave(), &1u64.encode(), StatementKind::Saft.to_text()); - let call = ClaimsCall::claim_attest { - dest: 1, - ethereum_signature: s, - statement: StatementKind::Regular.to_text().to_vec(), - }; - assert_eq!( - Pallet::::validate_unsigned(source, &call), - InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(), - ); - - let s = sig::(&dave(), &1u64.encode(), StatementKind::Saft.to_text()); - let call = ClaimsCall::claim_attest { - dest: 1, - ethereum_signature: s, - statement: StatementKind::Saft.to_text().to_vec(), - }; - assert_eq!( - Pallet::::validate_unsigned(source, &call), - InvalidTransaction::Custom(ValidityError::InvalidStatement.into()).into(), - ); - }); - } -} - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking { - use super::*; - use crate::claims::Call; - use frame_benchmarking::v2::*; - use frame_support::{ - dispatch::{DispatchInfo, GetDispatchInfo}, - traits::UnfilteredDispatchable, - }; - use frame_system::RawOrigin; - use secp_utils::*; - use sp_runtime::{ - traits::{DispatchTransaction, ValidateUnsigned}, - DispatchResult, - }; - - const SEED: u32 = 0; - - const MAX_CLAIMS: u32 = 10_000; - const VALUE: u32 = 1_000_000; - - fn create_claim(input: u32) -> DispatchResult { - let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap(); - let eth_address = eth(&secret_key); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - super::Pallet::::mint_claim( - RawOrigin::Root.into(), - eth_address, - VALUE.into(), - vesting, - None, - )?; - Ok(()) - } - - fn create_claim_attest(input: u32) -> DispatchResult { - let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap(); - let eth_address = eth(&secret_key); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - super::Pallet::::mint_claim( - RawOrigin::Root.into(), - eth_address, - VALUE.into(), - vesting, - Some(Default::default()), - )?; - Ok(()) - } - - #[benchmarks( - where - ::RuntimeCall: IsSubType> + From>, - ::RuntimeCall: Dispatchable + GetDispatchInfo, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, - <::RuntimeCall as Dispatchable>::PostInfo: Default, - )] - mod benchmarks { - use super::*; - - // Benchmark `claim` including `validate_unsigned` logic. - #[benchmark] - fn claim() -> Result<(), BenchmarkError> { - let c = MAX_CLAIMS; - for _ in 0..c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&c.encode())).unwrap(); - let eth_address = eth(&secret_key); - let account: T::AccountId = account("user", c, SEED); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - let signature = sig::(&secret_key, &account.encode(), &[][..]); - super::Pallet::::mint_claim( - RawOrigin::Root.into(), - eth_address, - VALUE.into(), - vesting, - None, - )?; - assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - let source = sp_runtime::transaction_validity::TransactionSource::External; - let call_enc = - Call::::claim { dest: account.clone(), ethereum_signature: signature.clone() } - .encode(); - - #[block] - { - let call = as Decode>::decode(&mut &*call_enc) - .expect("call is encoded above, encoding must be correct"); - super::Pallet::::validate_unsigned(source, &call) - .map_err(|e| -> &'static str { e.into() })?; - call.dispatch_bypass_filter(RawOrigin::None.into())?; - } - - assert_eq!(Claims::::get(eth_address), None); - Ok(()) - } - - // Benchmark `mint_claim` when there already exists `c` claims in storage. - #[benchmark] - fn mint_claim() -> Result<(), BenchmarkError> { - let c = MAX_CLAIMS; - for _ in 0..c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - let eth_address = account("eth_address", 0, SEED); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - let statement = StatementKind::Regular; - - #[extrinsic_call] - _(RawOrigin::Root, eth_address, VALUE.into(), vesting, Some(statement)); - - assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - Ok(()) - } - - // Benchmark `claim_attest` including `validate_unsigned` logic. - #[benchmark] - fn claim_attest() -> Result<(), BenchmarkError> { - let c = MAX_CLAIMS; - for _ in 0..c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - // Crate signature - let attest_c = u32::MAX - c; - let secret_key = - libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); - let eth_address = eth(&secret_key); - let account: T::AccountId = account("user", c, SEED); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - let statement = StatementKind::Regular; - let signature = sig::(&secret_key, &account.encode(), statement.to_text()); - super::Pallet::::mint_claim( - RawOrigin::Root.into(), - eth_address, - VALUE.into(), - vesting, - Some(statement), - )?; - assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - let call_enc = Call::::claim_attest { - dest: account.clone(), - ethereum_signature: signature.clone(), - statement: StatementKind::Regular.to_text().to_vec(), - } - .encode(); - let source = sp_runtime::transaction_validity::TransactionSource::External; - - #[block] - { - let call = as Decode>::decode(&mut &*call_enc) - .expect("call is encoded above, encoding must be correct"); - super::Pallet::::validate_unsigned(source, &call) - .map_err(|e| -> &'static str { e.into() })?; - call.dispatch_bypass_filter(RawOrigin::None.into())?; - } - - assert_eq!(Claims::::get(eth_address), None); - Ok(()) - } - - // Benchmark `attest` including prevalidate logic. - #[benchmark] - fn attest() -> Result<(), BenchmarkError> { - let c = MAX_CLAIMS; - for _ in 0..c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - let attest_c = u32::MAX - c; - let secret_key = - libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); - let eth_address = eth(&secret_key); - let account: T::AccountId = account("user", c, SEED); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - let statement = StatementKind::Regular; - super::Pallet::::mint_claim( - RawOrigin::Root.into(), - eth_address, - VALUE.into(), - vesting, - Some(statement), - )?; - Preclaims::::insert(&account, eth_address); - assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - - let stmt = StatementKind::Regular.to_text().to_vec(); - - #[extrinsic_call] - _(RawOrigin::Signed(account), stmt); - - assert_eq!(Claims::::get(eth_address), None); - Ok(()) - } - - #[benchmark] - fn move_claim() -> Result<(), BenchmarkError> { - let c = MAX_CLAIMS; - for _ in 0..c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - let attest_c = u32::MAX - c; - let secret_key = - libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); - let eth_address = eth(&secret_key); - - let new_secret_key = - libsecp256k1::SecretKey::parse(&keccak_256(&(u32::MAX / 2).encode())).unwrap(); - let new_eth_address = eth(&new_secret_key); - - let account: T::AccountId = account("user", c, SEED); - Preclaims::::insert(&account, eth_address); - - assert!(Claims::::contains_key(eth_address)); - assert!(!Claims::::contains_key(new_eth_address)); - - #[extrinsic_call] - _(RawOrigin::Root, eth_address, new_eth_address, Some(account)); - - assert!(!Claims::::contains_key(eth_address)); - assert!(Claims::::contains_key(new_eth_address)); - Ok(()) - } - - // Benchmark the time it takes to do `repeat` number of keccak256 hashes - #[benchmark(extra)] - fn keccak256(i: Linear<0, 10_000>) { - let bytes = (i).encode(); - - #[block] - { - for _ in 0..i { - let _hash = keccak_256(&bytes); - } - } - } - - // Benchmark the time it takes to do `repeat` number of `eth_recover` - #[benchmark(extra)] - fn eth_recover(i: Linear<0, 1_000>) { - // Crate signature - let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&i.encode())).unwrap(); - let account: T::AccountId = account("user", i, SEED); - let signature = sig::(&secret_key, &account.encode(), &[][..]); - let data = account.using_encoded(to_ascii_hex); - let extra = StatementKind::default().to_text(); - - #[block] - { - for _ in 0..i { - assert!(super::Pallet::::eth_recover(&signature, &data, extra).is_some()); - } - } - } - - #[benchmark] - fn prevalidate_attests() -> Result<(), BenchmarkError> { - let c = MAX_CLAIMS; - for _ in 0..c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - let ext = PrevalidateAttests::::new(); - let call = super::Call::attest { statement: StatementKind::Regular.to_text().to_vec() }; - let call: ::RuntimeCall = call.into(); - let info = call.get_dispatch_info(); - let attest_c = u32::MAX - c; - let secret_key = - libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); - let eth_address = eth(&secret_key); - let account: T::AccountId = account("user", c, SEED); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - let statement = StatementKind::Regular; - super::Pallet::::mint_claim( - RawOrigin::Root.into(), - eth_address, - VALUE.into(), - vesting, - Some(statement), - )?; - Preclaims::::insert(&account, eth_address); - assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(account).into(), &call, &info, 0, |_| { - Ok(Default::default()) - }) - .unwrap() - .is_ok()); - } - - Ok(()) - } - - impl_benchmark_test_suite!( - Pallet, - crate::claims::tests::new_test_ext(), - crate::claims::tests::Test, - ); - } -} diff --git a/polkadot/runtime/common/src/claims/benchmarking.rs b/polkadot/runtime/common/src/claims/benchmarking.rs new file mode 100644 index 000000000000..f9150f7980e5 --- /dev/null +++ b/polkadot/runtime/common/src/claims/benchmarking.rs @@ -0,0 +1,318 @@ +// 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 . + +//! Benchmarking for claims pallet + +#[cfg(feature = "runtime-benchmarks")] +use super::*; +use crate::claims::Call; +use frame_benchmarking::v2::*; +use frame_support::{ + dispatch::{DispatchInfo, GetDispatchInfo}, + traits::UnfilteredDispatchable, +}; +use frame_system::RawOrigin; +use secp_utils::*; +use sp_runtime::{ + traits::{DispatchTransaction, ValidateUnsigned}, + DispatchResult, +}; + +const SEED: u32 = 0; + +const MAX_CLAIMS: u32 = 10_000; +const VALUE: u32 = 1_000_000; + +fn create_claim(input: u32) -> DispatchResult { + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap(); + let eth_address = eth(&secret_key); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + super::Pallet::::mint_claim( + RawOrigin::Root.into(), + eth_address, + VALUE.into(), + vesting, + None, + )?; + Ok(()) +} + +fn create_claim_attest(input: u32) -> DispatchResult { + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap(); + let eth_address = eth(&secret_key); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + super::Pallet::::mint_claim( + RawOrigin::Root.into(), + eth_address, + VALUE.into(), + vesting, + Some(Default::default()), + )?; + Ok(()) +} + +#[benchmarks( + where + ::RuntimeCall: IsSubType> + From>, + ::RuntimeCall: Dispatchable + GetDispatchInfo, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, + <::RuntimeCall as Dispatchable>::PostInfo: Default, + )] +mod benchmarks { + use super::*; + + // Benchmark `claim` including `validate_unsigned` logic. + #[benchmark] + fn claim() -> Result<(), BenchmarkError> { + let c = MAX_CLAIMS; + for _ in 0..c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&c.encode())).unwrap(); + let eth_address = eth(&secret_key); + let account: T::AccountId = account("user", c, SEED); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + let signature = sig::(&secret_key, &account.encode(), &[][..]); + super::Pallet::::mint_claim( + RawOrigin::Root.into(), + eth_address, + VALUE.into(), + vesting, + None, + )?; + assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); + let source = sp_runtime::transaction_validity::TransactionSource::External; + let call_enc = + Call::::claim { dest: account.clone(), ethereum_signature: signature.clone() } + .encode(); + + #[block] + { + let call = as Decode>::decode(&mut &*call_enc) + .expect("call is encoded above, encoding must be correct"); + super::Pallet::::validate_unsigned(source, &call) + .map_err(|e| -> &'static str { e.into() })?; + call.dispatch_bypass_filter(RawOrigin::None.into())?; + } + + assert_eq!(Claims::::get(eth_address), None); + Ok(()) + } + + // Benchmark `mint_claim` when there already exists `c` claims in storage. + #[benchmark] + fn mint_claim() -> Result<(), BenchmarkError> { + let c = MAX_CLAIMS; + for _ in 0..c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + let eth_address = account("eth_address", 0, SEED); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + let statement = StatementKind::Regular; + + #[extrinsic_call] + _(RawOrigin::Root, eth_address, VALUE.into(), vesting, Some(statement)); + + assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); + Ok(()) + } + + // Benchmark `claim_attest` including `validate_unsigned` logic. + #[benchmark] + fn claim_attest() -> Result<(), BenchmarkError> { + let c = MAX_CLAIMS; + for _ in 0..c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + // Crate signature + let attest_c = u32::MAX - c; + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); + let eth_address = eth(&secret_key); + let account: T::AccountId = account("user", c, SEED); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + let statement = StatementKind::Regular; + let signature = sig::(&secret_key, &account.encode(), statement.to_text()); + super::Pallet::::mint_claim( + RawOrigin::Root.into(), + eth_address, + VALUE.into(), + vesting, + Some(statement), + )?; + assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); + let call_enc = Call::::claim_attest { + dest: account.clone(), + ethereum_signature: signature.clone(), + statement: StatementKind::Regular.to_text().to_vec(), + } + .encode(); + let source = sp_runtime::transaction_validity::TransactionSource::External; + + #[block] + { + let call = as Decode>::decode(&mut &*call_enc) + .expect("call is encoded above, encoding must be correct"); + super::Pallet::::validate_unsigned(source, &call) + .map_err(|e| -> &'static str { e.into() })?; + call.dispatch_bypass_filter(RawOrigin::None.into())?; + } + + assert_eq!(Claims::::get(eth_address), None); + Ok(()) + } + + // Benchmark `attest` including prevalidate logic. + #[benchmark] + fn attest() -> Result<(), BenchmarkError> { + let c = MAX_CLAIMS; + for _ in 0..c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + let attest_c = u32::MAX - c; + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); + let eth_address = eth(&secret_key); + let account: T::AccountId = account("user", c, SEED); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + let statement = StatementKind::Regular; + super::Pallet::::mint_claim( + RawOrigin::Root.into(), + eth_address, + VALUE.into(), + vesting, + Some(statement), + )?; + Preclaims::::insert(&account, eth_address); + assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); + + let stmt = StatementKind::Regular.to_text().to_vec(); + + #[extrinsic_call] + _(RawOrigin::Signed(account), stmt); + + assert_eq!(Claims::::get(eth_address), None); + Ok(()) + } + + #[benchmark] + fn move_claim() -> Result<(), BenchmarkError> { + let c = MAX_CLAIMS; + for _ in 0..c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + let attest_c = u32::MAX - c; + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); + let eth_address = eth(&secret_key); + + let new_secret_key = + libsecp256k1::SecretKey::parse(&keccak_256(&(u32::MAX / 2).encode())).unwrap(); + let new_eth_address = eth(&new_secret_key); + + let account: T::AccountId = account("user", c, SEED); + Preclaims::::insert(&account, eth_address); + + assert!(Claims::::contains_key(eth_address)); + assert!(!Claims::::contains_key(new_eth_address)); + + #[extrinsic_call] + _(RawOrigin::Root, eth_address, new_eth_address, Some(account)); + + assert!(!Claims::::contains_key(eth_address)); + assert!(Claims::::contains_key(new_eth_address)); + Ok(()) + } + + // Benchmark the time it takes to do `repeat` number of keccak256 hashes + #[benchmark(extra)] + fn keccak256(i: Linear<0, 10_000>) { + let bytes = (i).encode(); + + #[block] + { + for _ in 0..i { + let _hash = keccak_256(&bytes); + } + } + } + + // Benchmark the time it takes to do `repeat` number of `eth_recover` + #[benchmark(extra)] + fn eth_recover(i: Linear<0, 1_000>) { + // Crate signature + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&i.encode())).unwrap(); + let account: T::AccountId = account("user", i, SEED); + let signature = sig::(&secret_key, &account.encode(), &[][..]); + let data = account.using_encoded(to_ascii_hex); + let extra = StatementKind::default().to_text(); + + #[block] + { + for _ in 0..i { + assert!(super::Pallet::::eth_recover(&signature, &data, extra).is_some()); + } + } + } + + #[benchmark] + fn prevalidate_attests() -> Result<(), BenchmarkError> { + let c = MAX_CLAIMS; + for _ in 0..c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + let ext = PrevalidateAttests::::new(); + let call = super::Call::attest { statement: StatementKind::Regular.to_text().to_vec() }; + let call: ::RuntimeCall = call.into(); + let info = call.get_dispatch_info(); + let attest_c = u32::MAX - c; + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); + let eth_address = eth(&secret_key); + let account: T::AccountId = account("user", c, SEED); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + let statement = StatementKind::Regular; + super::Pallet::::mint_claim( + RawOrigin::Root.into(), + eth_address, + VALUE.into(), + vesting, + Some(statement), + )?; + Preclaims::::insert(&account, eth_address); + assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(account).into(), &call, &info, 0, 0, |_| { + Ok(Default::default()) + }) + .unwrap() + .is_ok()); + } + + Ok(()) + } + + impl_benchmark_test_suite!( + Pallet, + crate::claims::mock::new_test_ext(), + crate::claims::mock::Test, + ); +} diff --git a/polkadot/runtime/common/src/claims/mock.rs b/polkadot/runtime/common/src/claims/mock.rs new file mode 100644 index 000000000000..640df6ec6a8a --- /dev/null +++ b/polkadot/runtime/common/src/claims/mock.rs @@ -0,0 +1,129 @@ +// 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 . + +//! Mocking utilities for testing in claims pallet. + +#[cfg(test)] +use super::*; +use secp_utils::*; + +// The testing primitives are very useful for avoiding having to work with signatures +// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. +use crate::claims; +use frame_support::{derive_impl, ord_parameter_types, parameter_types, traits::WithdrawReasons}; +use pallet_balances; +use sp_runtime::{traits::Identity, BuildStorage}; + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Vesting: pallet_vesting, + Claims: claims, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type AccountData = pallet_balances::AccountData; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type AccountStore = System; +} + +parameter_types! { + pub const MinVestedTransfer: u64 = 1; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); +} + +impl pallet_vesting::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type BlockNumberToBalance = Identity; + type MinVestedTransfer = MinVestedTransfer; + type WeightInfo = (); + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; + const MAX_VESTING_SCHEDULES: u32 = 28; +} + +parameter_types! { + pub Prefix: &'static [u8] = b"Pay RUSTs to the TEST account:"; +} +ord_parameter_types! { + pub const Six: u64 = 6; +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type VestingSchedule = Vesting; + type Prefix = Prefix; + type MoveClaimOrigin = frame_system::EnsureSignedBy; + type WeightInfo = TestWeightInfo; +} + +pub fn alice() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap() +} +pub fn bob() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() +} +pub fn dave() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Dave")).unwrap() +} +pub fn eve() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Eve")).unwrap() +} +pub fn frank() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Frank")).unwrap() +} + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + // We use default for brevity, but you can configure as desired if needed. + pallet_balances::GenesisConfig::::default() + .assimilate_storage(&mut t) + .unwrap(); + claims::GenesisConfig:: { + claims: vec![ + (eth(&alice()), 100, None, None), + (eth(&dave()), 200, None, Some(StatementKind::Regular)), + (eth(&eve()), 300, Some(42), Some(StatementKind::Saft)), + (eth(&frank()), 400, Some(43), None), + ], + vesting: vec![(eth(&alice()), (50, 10, 1))], + } + .assimilate_storage(&mut t) + .unwrap(); + t.into() +} + +pub fn total_claims() -> u64 { + 100 + 200 + 300 + 400 +} diff --git a/polkadot/runtime/common/src/claims/mod.rs b/polkadot/runtime/common/src/claims/mod.rs new file mode 100644 index 000000000000..f48e40ee1887 --- /dev/null +++ b/polkadot/runtime/common/src/claims/mod.rs @@ -0,0 +1,723 @@ +// 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 . + +//! Pallet to process claims from Ethereum addresses. + +#[cfg(not(feature = "std"))] +use alloc::{format, string::String}; +use alloc::{vec, vec::Vec}; +use codec::{Decode, Encode, MaxEncodedLen}; +use core::fmt::Debug; +use frame_support::{ + ensure, + traits::{Currency, Get, IsSubType, VestingSchedule}, + weights::Weight, + DefaultNoBound, +}; +pub use pallet::*; +use polkadot_primitives::ValidityError; +use scale_info::TypeInfo; +use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; +use sp_runtime::{ + impl_tx_ext_default, + traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, CheckedSub, DispatchInfoOf, + Dispatchable, TransactionExtension, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + ValidTransaction, + }, + RuntimeDebug, +}; + +type CurrencyOf = <::VestingSchedule as VestingSchedule< + ::AccountId, +>>::Currency; +type BalanceOf = as Currency<::AccountId>>::Balance; + +pub trait WeightInfo { + fn claim() -> Weight; + fn mint_claim() -> Weight; + fn claim_attest() -> Weight; + fn attest() -> Weight; + fn move_claim() -> Weight; + fn prevalidate_attests() -> Weight; +} + +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn claim() -> Weight { + Weight::zero() + } + fn mint_claim() -> Weight { + Weight::zero() + } + fn claim_attest() -> Weight { + Weight::zero() + } + fn attest() -> Weight { + Weight::zero() + } + fn move_claim() -> Weight { + Weight::zero() + } + fn prevalidate_attests() -> Weight { + Weight::zero() + } +} + +/// The kind of statement an account needs to make for a claim to be valid. +#[derive( + Encode, + Decode, + Clone, + Copy, + Eq, + PartialEq, + RuntimeDebug, + TypeInfo, + Serialize, + Deserialize, + MaxEncodedLen, +)] +pub enum StatementKind { + /// Statement required to be made by non-SAFT holders. + Regular, + /// Statement required to be made by SAFT holders. + Saft, +} + +impl StatementKind { + /// Convert this to the (English) statement it represents. + fn to_text(self) -> &'static [u8] { + match self { + StatementKind::Regular => + &b"I hereby agree to the terms of the statement whose SHA-256 multihash is \ + Qmc1XYqT6S39WNp2UeiRUrZichUWUPpGEThDE6dAb3f6Ny. (This may be found at the URL: \ + https://statement.polkadot.network/regular.html)"[..], + StatementKind::Saft => + &b"I hereby agree to the terms of the statement whose SHA-256 multihash is \ + QmXEkMahfhHJPzT3RjkXiZVFi77ZeVeuxtAjhojGRNYckz. (This may be found at the URL: \ + https://statement.polkadot.network/saft.html)"[..], + } + } +} + +impl Default for StatementKind { + fn default() -> Self { + StatementKind::Regular + } +} + +/// An Ethereum address (i.e. 20 bytes, used to represent an Ethereum account). +/// +/// This gets serialized to the 0x-prefixed hex representation. +#[derive( + Clone, Copy, PartialEq, Eq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] +pub struct EthereumAddress([u8; 20]); + +impl Serialize for EthereumAddress { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let hex: String = rustc_hex::ToHex::to_hex(&self.0[..]); + serializer.serialize_str(&format!("0x{}", hex)) + } +} + +impl<'de> Deserialize<'de> for EthereumAddress { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let base_string = String::deserialize(deserializer)?; + let offset = if base_string.starts_with("0x") { 2 } else { 0 }; + let s = &base_string[offset..]; + if s.len() != 40 { + Err(serde::de::Error::custom( + "Bad length of Ethereum address (should be 42 including '0x')", + ))?; + } + let raw: Vec = rustc_hex::FromHex::from_hex(s) + .map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?; + let mut r = Self::default(); + r.0.copy_from_slice(&raw); + Ok(r) + } +} + +#[derive(Encode, Decode, Clone, TypeInfo, MaxEncodedLen)] +pub struct EcdsaSignature(pub [u8; 65]); + +impl PartialEq for EcdsaSignature { + fn eq(&self, other: &Self) -> bool { + &self.0[..] == &other.0[..] + } +} + +impl core::fmt::Debug for EcdsaSignature { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "EcdsaSignature({:?})", &self.0[..]) + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + /// Configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type VestingSchedule: VestingSchedule>; + #[pallet::constant] + type Prefix: Get<&'static [u8]>; + type MoveClaimOrigin: EnsureOrigin; + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Someone claimed some DOTs. + Claimed { who: T::AccountId, ethereum_address: EthereumAddress, amount: BalanceOf }, + } + + #[pallet::error] + pub enum Error { + /// Invalid Ethereum signature. + InvalidEthereumSignature, + /// Ethereum address has no claim. + SignerHasNoClaim, + /// Account ID sending transaction has no claim. + SenderHasNoClaim, + /// There's not enough in the pot to pay out some unvested amount. Generally implies a + /// logic error. + PotUnderflow, + /// A needed statement was not included. + InvalidStatement, + /// The account already has a vested balance. + VestedBalanceExists, + } + + #[pallet::storage] + pub type Claims = StorageMap<_, Identity, EthereumAddress, BalanceOf>; + + #[pallet::storage] + pub type Total = StorageValue<_, BalanceOf, ValueQuery>; + + /// Vesting schedule for a claim. + /// First balance is the total amount that should be held for vesting. + /// Second balance is how much should be unlocked per block. + /// The block number is when the vesting should start. + #[pallet::storage] + pub type Vesting = + StorageMap<_, Identity, EthereumAddress, (BalanceOf, BalanceOf, BlockNumberFor)>; + + /// The statement kind that must be signed, if any. + #[pallet::storage] + pub(super) type Signing = StorageMap<_, Identity, EthereumAddress, StatementKind>; + + /// Pre-claimed Ethereum accounts, by the Account ID that they are claimed to. + #[pallet::storage] + pub(super) type Preclaims = StorageMap<_, Identity, T::AccountId, EthereumAddress>; + + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig { + pub claims: + Vec<(EthereumAddress, BalanceOf, Option, Option)>, + pub vesting: Vec<(EthereumAddress, (BalanceOf, BalanceOf, BlockNumberFor))>, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + // build `Claims` + self.claims.iter().map(|(a, b, _, _)| (*a, *b)).for_each(|(a, b)| { + Claims::::insert(a, b); + }); + // build `Total` + Total::::put( + self.claims + .iter() + .fold(Zero::zero(), |acc: BalanceOf, &(_, b, _, _)| acc + b), + ); + // build `Vesting` + self.vesting.iter().for_each(|(k, v)| { + Vesting::::insert(k, v); + }); + // build `Signing` + self.claims + .iter() + .filter_map(|(a, _, _, s)| Some((*a, (*s)?))) + .for_each(|(a, s)| { + Signing::::insert(a, s); + }); + // build `Preclaims` + self.claims.iter().filter_map(|(a, _, i, _)| Some((i.clone()?, *a))).for_each( + |(i, a)| { + Preclaims::::insert(i, a); + }, + ); + } + } + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet { + /// Make a claim to collect your DOTs. + /// + /// The dispatch origin for this call must be _None_. + /// + /// Unsigned Validation: + /// A call to claim is deemed valid if the signature provided matches + /// the expected signed message of: + /// + /// > Ethereum Signed Message: + /// > (configured prefix string)(address) + /// + /// and `address` matches the `dest` account. + /// + /// Parameters: + /// - `dest`: The destination account to payout the claim. + /// - `ethereum_signature`: The signature of an ethereum signed message matching the format + /// described above. + /// + /// + /// The weight of this call is invariant over the input parameters. + /// Weight includes logic to validate unsigned `claim` call. + /// + /// Total Complexity: O(1) + /// + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::claim())] + pub fn claim( + origin: OriginFor, + dest: T::AccountId, + ethereum_signature: EcdsaSignature, + ) -> DispatchResult { + ensure_none(origin)?; + + let data = dest.using_encoded(to_ascii_hex); + let signer = Self::eth_recover(ðereum_signature, &data, &[][..]) + .ok_or(Error::::InvalidEthereumSignature)?; + ensure!(Signing::::get(&signer).is_none(), Error::::InvalidStatement); + + Self::process_claim(signer, dest)?; + Ok(()) + } + + /// Mint a new claim to collect DOTs. + /// + /// The dispatch origin for this call must be _Root_. + /// + /// Parameters: + /// - `who`: The Ethereum address allowed to collect this claim. + /// - `value`: The number of DOTs that will be claimed. + /// - `vesting_schedule`: An optional vesting schedule for these DOTs. + /// + /// + /// The weight of this call is invariant over the input parameters. + /// We assume worst case that both vesting and statement is being inserted. + /// + /// Total Complexity: O(1) + /// + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::mint_claim())] + pub fn mint_claim( + origin: OriginFor, + who: EthereumAddress, + value: BalanceOf, + vesting_schedule: Option<(BalanceOf, BalanceOf, BlockNumberFor)>, + statement: Option, + ) -> DispatchResult { + ensure_root(origin)?; + + Total::::mutate(|t| *t += value); + Claims::::insert(who, value); + if let Some(vs) = vesting_schedule { + Vesting::::insert(who, vs); + } + if let Some(s) = statement { + Signing::::insert(who, s); + } + Ok(()) + } + + /// Make a claim to collect your DOTs by signing a statement. + /// + /// The dispatch origin for this call must be _None_. + /// + /// Unsigned Validation: + /// A call to `claim_attest` is deemed valid if the signature provided matches + /// the expected signed message of: + /// + /// > Ethereum Signed Message: + /// > (configured prefix string)(address)(statement) + /// + /// and `address` matches the `dest` account; the `statement` must match that which is + /// expected according to your purchase arrangement. + /// + /// Parameters: + /// - `dest`: The destination account to payout the claim. + /// - `ethereum_signature`: The signature of an ethereum signed message matching the format + /// described above. + /// - `statement`: The identity of the statement which is being attested to in the + /// signature. + /// + /// + /// The weight of this call is invariant over the input parameters. + /// Weight includes logic to validate unsigned `claim_attest` call. + /// + /// Total Complexity: O(1) + /// + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::claim_attest())] + pub fn claim_attest( + origin: OriginFor, + dest: T::AccountId, + ethereum_signature: EcdsaSignature, + statement: Vec, + ) -> DispatchResult { + ensure_none(origin)?; + + let data = dest.using_encoded(to_ascii_hex); + let signer = Self::eth_recover(ðereum_signature, &data, &statement) + .ok_or(Error::::InvalidEthereumSignature)?; + if let Some(s) = Signing::::get(signer) { + ensure!(s.to_text() == &statement[..], Error::::InvalidStatement); + } + Self::process_claim(signer, dest)?; + Ok(()) + } + + /// Attest to a statement, needed to finalize the claims process. + /// + /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a + /// `TransactionExtension`. + /// + /// Unsigned Validation: + /// A call to attest is deemed valid if the sender has a `Preclaim` registered + /// and provides a `statement` which is expected for the account. + /// + /// Parameters: + /// - `statement`: The identity of the statement which is being attested to in the + /// signature. + /// + /// + /// The weight of this call is invariant over the input parameters. + /// Weight includes logic to do pre-validation on `attest` call. + /// + /// Total Complexity: O(1) + /// + #[pallet::call_index(3)] + #[pallet::weight(( + T::WeightInfo::attest(), + DispatchClass::Normal, + Pays::No + ))] + pub fn attest(origin: OriginFor, statement: Vec) -> DispatchResult { + let who = ensure_signed(origin)?; + let signer = Preclaims::::get(&who).ok_or(Error::::SenderHasNoClaim)?; + if let Some(s) = Signing::::get(signer) { + ensure!(s.to_text() == &statement[..], Error::::InvalidStatement); + } + Self::process_claim(signer, who.clone())?; + Preclaims::::remove(&who); + Ok(()) + } + + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::move_claim())] + pub fn move_claim( + origin: OriginFor, + old: EthereumAddress, + new: EthereumAddress, + maybe_preclaim: Option, + ) -> DispatchResultWithPostInfo { + T::MoveClaimOrigin::try_origin(origin).map(|_| ()).or_else(ensure_root)?; + + Claims::::take(&old).map(|c| Claims::::insert(&new, c)); + Vesting::::take(&old).map(|c| Vesting::::insert(&new, c)); + Signing::::take(&old).map(|c| Signing::::insert(&new, c)); + maybe_preclaim.map(|preclaim| { + Preclaims::::mutate(&preclaim, |maybe_o| { + if maybe_o.as_ref().map_or(false, |o| o == &old) { + *maybe_o = Some(new) + } + }) + }); + Ok(Pays::No.into()) + } + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + const PRIORITY: u64 = 100; + + let (maybe_signer, maybe_statement) = match call { + // + // The weight of this logic is included in the `claim` dispatchable. + // + Call::claim { dest: account, ethereum_signature } => { + let data = account.using_encoded(to_ascii_hex); + (Self::eth_recover(ðereum_signature, &data, &[][..]), None) + }, + // + // The weight of this logic is included in the `claim_attest` dispatchable. + // + Call::claim_attest { dest: account, ethereum_signature, statement } => { + let data = account.using_encoded(to_ascii_hex); + ( + Self::eth_recover(ðereum_signature, &data, &statement), + Some(statement.as_slice()), + ) + }, + _ => return Err(InvalidTransaction::Call.into()), + }; + + let signer = maybe_signer.ok_or(InvalidTransaction::Custom( + ValidityError::InvalidEthereumSignature.into(), + ))?; + + let e = InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()); + ensure!(Claims::::contains_key(&signer), e); + + let e = InvalidTransaction::Custom(ValidityError::InvalidStatement.into()); + match Signing::::get(signer) { + None => ensure!(maybe_statement.is_none(), e), + Some(s) => ensure!(Some(s.to_text()) == maybe_statement, e), + } + + Ok(ValidTransaction { + priority: PRIORITY, + requires: vec![], + provides: vec![("claims", signer).encode()], + longevity: TransactionLongevity::max_value(), + propagate: true, + }) + } + } +} + +/// Converts the given binary data into ASCII-encoded hex. It will be twice the length. +fn to_ascii_hex(data: &[u8]) -> Vec { + let mut r = Vec::with_capacity(data.len() * 2); + let mut push_nibble = |n| r.push(if n < 10 { b'0' + n } else { b'a' - 10 + n }); + for &b in data.iter() { + push_nibble(b / 16); + push_nibble(b % 16); + } + r +} + +impl Pallet { + // Constructs the message that Ethereum RPC's `personal_sign` and `eth_sign` would sign. + fn ethereum_signable_message(what: &[u8], extra: &[u8]) -> Vec { + let prefix = T::Prefix::get(); + let mut l = prefix.len() + what.len() + extra.len(); + let mut rev = Vec::new(); + while l > 0 { + rev.push(b'0' + (l % 10) as u8); + l /= 10; + } + let mut v = b"\x19Ethereum Signed Message:\n".to_vec(); + v.extend(rev.into_iter().rev()); + v.extend_from_slice(prefix); + v.extend_from_slice(what); + v.extend_from_slice(extra); + v + } + + // Attempts to recover the Ethereum address from a message signature signed by using + // the Ethereum RPC's `personal_sign` and `eth_sign`. + fn eth_recover(s: &EcdsaSignature, what: &[u8], extra: &[u8]) -> Option { + let msg = keccak_256(&Self::ethereum_signable_message(what, extra)); + let mut res = EthereumAddress::default(); + res.0 + .copy_from_slice(&keccak_256(&secp256k1_ecdsa_recover(&s.0, &msg).ok()?[..])[12..]); + Some(res) + } + + fn process_claim(signer: EthereumAddress, dest: T::AccountId) -> sp_runtime::DispatchResult { + let balance_due = Claims::::get(&signer).ok_or(Error::::SignerHasNoClaim)?; + + let new_total = + Total::::get().checked_sub(&balance_due).ok_or(Error::::PotUnderflow)?; + + let vesting = Vesting::::get(&signer); + if vesting.is_some() && T::VestingSchedule::vesting_balance(&dest).is_some() { + return Err(Error::::VestedBalanceExists.into()) + } + + // We first need to deposit the balance to ensure that the account exists. + let _ = CurrencyOf::::deposit_creating(&dest, balance_due); + + // Check if this claim should have a vesting schedule. + if let Some(vs) = vesting { + // This can only fail if the account already has a vesting schedule, + // but this is checked above. + T::VestingSchedule::add_vesting_schedule(&dest, vs.0, vs.1, vs.2) + .expect("No other vesting schedule exists, as checked above; qed"); + } + + Total::::put(new_total); + Claims::::remove(&signer); + Vesting::::remove(&signer); + Signing::::remove(&signer); + + // Let's deposit an event to let the outside world know this happened. + Self::deposit_event(Event::::Claimed { + who: dest, + ethereum_address: signer, + amount: balance_due, + }); + + Ok(()) + } +} + +/// Validate `attest` calls prior to execution. Needed to avoid a DoS attack since they are +/// otherwise free to place on chain. +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct PrevalidateAttests(core::marker::PhantomData); + +impl Debug for PrevalidateAttests +where + ::RuntimeCall: IsSubType>, +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "PrevalidateAttests") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result { + Ok(()) + } +} + +impl PrevalidateAttests +where + ::RuntimeCall: IsSubType>, +{ + /// Create new `TransactionExtension` to check runtime version. + pub fn new() -> Self { + Self(core::marker::PhantomData) + } +} + +impl TransactionExtension for PrevalidateAttests +where + ::RuntimeCall: IsSubType>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, +{ + const IDENTIFIER: &'static str = "PrevalidateAttests"; + type Implicit = (); + type Pre = (); + type Val = (); + + fn weight(&self, call: &T::RuntimeCall) -> Weight { + if let Some(Call::attest { .. }) = call.is_sub_type() { + T::WeightInfo::prevalidate_attests() + } else { + Weight::zero() + } + } + + fn validate( + &self, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + if let Some(Call::attest { statement: attested_statement }) = call.is_sub_type() { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + let signer = Preclaims::::get(who) + .ok_or(InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()))?; + if let Some(s) = Signing::::get(signer) { + let e = InvalidTransaction::Custom(ValidityError::InvalidStatement.into()); + ensure!(&attested_statement[..] == s.to_text(), e); + } + } + Ok((ValidTransaction::default(), (), origin)) + } + + impl_tx_ext_default!(T::RuntimeCall; prepare); +} + +#[cfg(any(test, feature = "runtime-benchmarks"))] +mod secp_utils { + use super::*; + + pub fn public(secret: &libsecp256k1::SecretKey) -> libsecp256k1::PublicKey { + libsecp256k1::PublicKey::from_secret_key(secret) + } + pub fn eth(secret: &libsecp256k1::SecretKey) -> EthereumAddress { + let mut res = EthereumAddress::default(); + res.0.copy_from_slice(&keccak_256(&public(secret).serialize()[1..65])[12..]); + res + } + pub fn sig( + secret: &libsecp256k1::SecretKey, + what: &[u8], + extra: &[u8], + ) -> EcdsaSignature { + let msg = keccak_256(&super::Pallet::::ethereum_signable_message( + &to_ascii_hex(what)[..], + extra, + )); + let (sig, recovery_id) = libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), secret); + let mut r = [0u8; 65]; + r[0..64].copy_from_slice(&sig.serialize()[..]); + r[64] = recovery_id.serialize(); + EcdsaSignature(r) + } +} + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; diff --git a/polkadot/runtime/common/src/claims/tests.rs b/polkadot/runtime/common/src/claims/tests.rs new file mode 100644 index 000000000000..dff2623cb934 --- /dev/null +++ b/polkadot/runtime/common/src/claims/tests.rs @@ -0,0 +1,666 @@ +// 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 . + +//! Tests for the claims pallet. + +#[cfg(test)] +use super::*; +use crate::{claims, claims::mock::*}; +use claims::Call as ClaimsCall; +use hex_literal::hex; +use secp_utils::*; +use sp_runtime::transaction_validity::TransactionSource::External; + +use codec::Encode; +// The testing primitives are very useful for avoiding having to work with signatures +// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. +use frame_support::{ + assert_err, assert_noop, assert_ok, + dispatch::{GetDispatchInfo, Pays}, + traits::ExistenceRequirement, +}; +use sp_runtime::{ + traits::DispatchTransaction, transaction_validity::TransactionLongevity, + DispatchError::BadOrigin, TokenError, +}; + +#[test] +fn basic_setup_works() { + new_test_ext().execute_with(|| { + assert_eq!(claims::Total::::get(), total_claims()); + assert_eq!(claims::Claims::::get(ð(&alice())), Some(100)); + assert_eq!(claims::Claims::::get(ð(&dave())), Some(200)); + assert_eq!(claims::Claims::::get(ð(&eve())), Some(300)); + assert_eq!(claims::Claims::::get(ð(&frank())), Some(400)); + assert_eq!(claims::Claims::::get(&EthereumAddress::default()), None); + assert_eq!(claims::Vesting::::get(ð(&alice())), Some((50, 10, 1))); + }); +} + +#[test] +fn serde_works() { + let x = EthereumAddress(hex!["0123456789abcdef0123456789abcdef01234567"]); + let y = serde_json::to_string(&x).unwrap(); + assert_eq!(y, "\"0x0123456789abcdef0123456789abcdef01234567\""); + let z: EthereumAddress = serde_json::from_str(&y).unwrap(); + assert_eq!(x, z); +} + +#[test] +fn claiming_works() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + )); + assert_eq!(Balances::free_balance(&42), 100); + assert_eq!(claims::mock::Vesting::vesting_balance(&42), Some(50)); + assert_eq!(claims::Total::::get(), total_claims() - 100); + }); +} + +#[test] +fn basic_claim_moving_works() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_noop!( + claims::mock::Claims::move_claim( + RuntimeOrigin::signed(1), + eth(&alice()), + eth(&bob()), + None + ), + BadOrigin + ); + assert_ok!(claims::mock::Claims::move_claim( + RuntimeOrigin::signed(6), + eth(&alice()), + eth(&bob()), + None + )); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + ), + Error::::SignerHasNoClaim + ); + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&bob(), &42u64.encode(), &[][..]) + )); + assert_eq!(Balances::free_balance(&42), 100); + assert_eq!(claims::mock::Vesting::vesting_balance(&42), Some(50)); + assert_eq!(claims::Total::::get(), total_claims() - 100); + }); +} + +#[test] +fn claim_attest_moving_works() { + new_test_ext().execute_with(|| { + assert_ok!(claims::mock::Claims::move_claim( + RuntimeOrigin::signed(6), + eth(&dave()), + eth(&bob()), + None + )); + let s = sig::(&bob(), &42u64.encode(), StatementKind::Regular.to_text()); + assert_ok!(claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 42, + s, + StatementKind::Regular.to_text().to_vec() + )); + assert_eq!(Balances::free_balance(&42), 200); + }); +} + +#[test] +fn attest_moving_works() { + new_test_ext().execute_with(|| { + assert_ok!(claims::mock::Claims::move_claim( + RuntimeOrigin::signed(6), + eth(&eve()), + eth(&bob()), + Some(42) + )); + assert_ok!(claims::mock::Claims::attest( + RuntimeOrigin::signed(42), + StatementKind::Saft.to_text().to_vec() + )); + assert_eq!(Balances::free_balance(&42), 300); + }); +} + +#[test] +fn claiming_does_not_bypass_signing() { + new_test_ext().execute_with(|| { + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + )); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&dave(), &42u64.encode(), &[][..]) + ), + Error::::InvalidStatement, + ); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&eve(), &42u64.encode(), &[][..]) + ), + Error::::InvalidStatement, + ); + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&frank(), &42u64.encode(), &[][..]) + )); + }); +} + +#[test] +fn attest_claiming_works() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + let s = sig::(&dave(), &42u64.encode(), StatementKind::Saft.to_text()); + let r = claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 42, + s.clone(), + StatementKind::Saft.to_text().to_vec(), + ); + assert_noop!(r, Error::::InvalidStatement); + + let r = claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 42, + s, + StatementKind::Regular.to_text().to_vec(), + ); + assert_noop!(r, Error::::SignerHasNoClaim); + // ^^^ we use ecdsa_recover, so an invalid signature just results in a random signer id + // being recovered, which realistically will never have a claim. + + let s = sig::(&dave(), &42u64.encode(), StatementKind::Regular.to_text()); + assert_ok!(claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 42, + s, + StatementKind::Regular.to_text().to_vec() + )); + assert_eq!(Balances::free_balance(&42), 200); + assert_eq!(claims::Total::::get(), total_claims() - 200); + + let s = sig::(&dave(), &42u64.encode(), StatementKind::Regular.to_text()); + let r = claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 42, + s, + StatementKind::Regular.to_text().to_vec(), + ); + assert_noop!(r, Error::::SignerHasNoClaim); + }); +} + +#[test] +fn attesting_works() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_noop!( + claims::mock::Claims::attest( + RuntimeOrigin::signed(69), + StatementKind::Saft.to_text().to_vec() + ), + Error::::SenderHasNoClaim + ); + assert_noop!( + claims::mock::Claims::attest( + RuntimeOrigin::signed(42), + StatementKind::Regular.to_text().to_vec() + ), + Error::::InvalidStatement + ); + assert_ok!(claims::mock::Claims::attest( + RuntimeOrigin::signed(42), + StatementKind::Saft.to_text().to_vec() + )); + assert_eq!(Balances::free_balance(&42), 300); + assert_eq!(claims::Total::::get(), total_claims() - 300); + }); +} + +#[test] +fn claim_cannot_clobber_preclaim() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + // Alice's claim is 100 + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + )); + assert_eq!(Balances::free_balance(&42), 100); + // Eve's claim is 300 through Account 42 + assert_ok!(claims::mock::Claims::attest( + RuntimeOrigin::signed(42), + StatementKind::Saft.to_text().to_vec() + )); + assert_eq!(Balances::free_balance(&42), 100 + 300); + assert_eq!(claims::Total::::get(), total_claims() - 400); + }); +} + +#[test] +fn valid_attest_transactions_are_free() { + new_test_ext().execute_with(|| { + let p = PrevalidateAttests::::new(); + let c = claims::mock::RuntimeCall::Claims(ClaimsCall::attest { + statement: StatementKind::Saft.to_text().to_vec(), + }); + let di = c.get_dispatch_info(); + assert_eq!(di.pays_fee, Pays::No); + let r = p.validate_only(Some(42).into(), &c, &di, 20, External, 0); + assert_eq!(r.unwrap().0, ValidTransaction::default()); + }); +} + +#[test] +fn invalid_attest_transactions_are_recognized() { + new_test_ext().execute_with(|| { + let p = PrevalidateAttests::::new(); + let c = claims::mock::RuntimeCall::Claims(ClaimsCall::attest { + statement: StatementKind::Regular.to_text().to_vec(), + }); + let di = c.get_dispatch_info(); + let r = p.validate_only(Some(42).into(), &c, &di, 20, External, 0); + assert!(r.is_err()); + let c = claims::mock::RuntimeCall::Claims(ClaimsCall::attest { + statement: StatementKind::Saft.to_text().to_vec(), + }); + let di = c.get_dispatch_info(); + let r = p.validate_only(Some(69).into(), &c, &di, 20, External, 0); + assert!(r.is_err()); + }); +} + +#[test] +fn cannot_bypass_attest_claiming() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + let s = sig::(&dave(), &42u64.encode(), &[]); + let r = claims::mock::Claims::claim(RuntimeOrigin::none(), 42, s.clone()); + assert_noop!(r, Error::::InvalidStatement); + }); +} + +#[test] +fn add_claim_works() { + new_test_ext().execute_with(|| { + assert_noop!( + claims::mock::Claims::mint_claim( + RuntimeOrigin::signed(42), + eth(&bob()), + 200, + None, + None + ), + sp_runtime::traits::BadOrigin, + ); + assert_eq!(Balances::free_balance(42), 0); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 69, + sig::(&bob(), &69u64.encode(), &[][..]) + ), + Error::::SignerHasNoClaim, + ); + assert_ok!(claims::mock::Claims::mint_claim( + RuntimeOrigin::root(), + eth(&bob()), + 200, + None, + None + )); + assert_eq!(claims::Total::::get(), total_claims() + 200); + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 69, + sig::(&bob(), &69u64.encode(), &[][..]) + )); + assert_eq!(Balances::free_balance(&69), 200); + assert_eq!(claims::mock::Vesting::vesting_balance(&69), None); + assert_eq!(claims::Total::::get(), total_claims()); + }); +} + +#[test] +fn add_claim_with_vesting_works() { + new_test_ext().execute_with(|| { + assert_noop!( + claims::mock::Claims::mint_claim( + RuntimeOrigin::signed(42), + eth(&bob()), + 200, + Some((50, 10, 1)), + None + ), + sp_runtime::traits::BadOrigin, + ); + assert_eq!(Balances::free_balance(42), 0); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 69, + sig::(&bob(), &69u64.encode(), &[][..]) + ), + Error::::SignerHasNoClaim, + ); + assert_ok!(claims::mock::Claims::mint_claim( + RuntimeOrigin::root(), + eth(&bob()), + 200, + Some((50, 10, 1)), + None + )); + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 69, + sig::(&bob(), &69u64.encode(), &[][..]) + )); + assert_eq!(Balances::free_balance(&69), 200); + assert_eq!(claims::mock::Vesting::vesting_balance(&69), Some(50)); + + // Make sure we can not transfer the vested balance. + assert_err!( + >::transfer(&69, &80, 180, ExistenceRequirement::AllowDeath), + TokenError::Frozen, + ); + }); +} + +#[test] +fn add_claim_with_statement_works() { + new_test_ext().execute_with(|| { + assert_noop!( + claims::mock::Claims::mint_claim( + RuntimeOrigin::signed(42), + eth(&bob()), + 200, + None, + Some(StatementKind::Regular) + ), + sp_runtime::traits::BadOrigin, + ); + assert_eq!(Balances::free_balance(42), 0); + let signature = sig::(&bob(), &69u64.encode(), StatementKind::Regular.to_text()); + assert_noop!( + claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 69, + signature.clone(), + StatementKind::Regular.to_text().to_vec() + ), + Error::::SignerHasNoClaim + ); + assert_ok!(claims::mock::Claims::mint_claim( + RuntimeOrigin::root(), + eth(&bob()), + 200, + None, + Some(StatementKind::Regular) + )); + assert_noop!( + claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 69, + signature.clone(), + vec![], + ), + Error::::SignerHasNoClaim + ); + assert_ok!(claims::mock::Claims::claim_attest( + RuntimeOrigin::none(), + 69, + signature.clone(), + StatementKind::Regular.to_text().to_vec() + )); + assert_eq!(Balances::free_balance(&69), 200); + }); +} + +#[test] +fn origin_signed_claiming_fail() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_err!( + claims::mock::Claims::claim( + RuntimeOrigin::signed(42), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + ), + sp_runtime::traits::BadOrigin, + ); + }); +} + +#[test] +fn double_claiming_doesnt_work() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_ok!(claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + )); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &42u64.encode(), &[][..]) + ), + Error::::SignerHasNoClaim + ); + }); +} + +#[test] +fn claiming_while_vested_doesnt_work() { + new_test_ext().execute_with(|| { + CurrencyOf::::make_free_balance_be(&69, total_claims()); + assert_eq!(Balances::free_balance(69), total_claims()); + // A user is already vested + assert_ok!(::VestingSchedule::add_vesting_schedule( + &69, + total_claims(), + 100, + 10 + )); + assert_ok!(claims::mock::Claims::mint_claim( + RuntimeOrigin::root(), + eth(&bob()), + 200, + Some((50, 10, 1)), + None + )); + // New total + assert_eq!(claims::Total::::get(), total_claims() + 200); + + // They should not be able to claim + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 69, + sig::(&bob(), &69u64.encode(), &[][..]) + ), + Error::::VestedBalanceExists, + ); + }); +} + +#[test] +fn non_sender_sig_doesnt_work() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&alice(), &69u64.encode(), &[][..]) + ), + Error::::SignerHasNoClaim + ); + }); +} + +#[test] +fn non_claimant_doesnt_work() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::free_balance(42), 0); + assert_noop!( + claims::mock::Claims::claim( + RuntimeOrigin::none(), + 42, + sig::(&bob(), &69u64.encode(), &[][..]) + ), + Error::::SignerHasNoClaim + ); + }); +} + +#[test] +fn real_eth_sig_works() { + new_test_ext().execute_with(|| { + // "Pay RUSTs to the TEST account:2a00000000000000" + let sig = hex!["444023e89b67e67c0562ed0305d252a5dd12b2af5ac51d6d3cb69a0b486bc4b3191401802dc29d26d586221f7256cd3329fe82174bdf659baea149a40e1c495d1c"]; + let sig = EcdsaSignature(sig); + let who = 42u64.using_encoded(to_ascii_hex); + let signer = claims::mock::Claims::eth_recover(&sig, &who, &[][..]).unwrap(); + assert_eq!(signer.0, hex!["6d31165d5d932d571f3b44695653b46dcc327e84"]); + }); +} + +#[test] +fn validate_unsigned_works() { + use sp_runtime::traits::ValidateUnsigned; + let source = sp_runtime::transaction_validity::TransactionSource::External; + + new_test_ext().execute_with(|| { + assert_eq!( + Pallet::::validate_unsigned( + source, + &ClaimsCall::claim { + dest: 1, + ethereum_signature: sig::(&alice(), &1u64.encode(), &[][..]) + } + ), + Ok(ValidTransaction { + priority: 100, + requires: vec![], + provides: vec![("claims", eth(&alice())).encode()], + longevity: TransactionLongevity::max_value(), + propagate: true, + }) + ); + assert_eq!( + Pallet::::validate_unsigned( + source, + &ClaimsCall::claim { dest: 0, ethereum_signature: EcdsaSignature([0; 65]) } + ), + InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()).into(), + ); + assert_eq!( + Pallet::::validate_unsigned( + source, + &ClaimsCall::claim { + dest: 1, + ethereum_signature: sig::(&bob(), &1u64.encode(), &[][..]) + } + ), + InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(), + ); + let s = sig::(&dave(), &1u64.encode(), StatementKind::Regular.to_text()); + let call = ClaimsCall::claim_attest { + dest: 1, + ethereum_signature: s, + statement: StatementKind::Regular.to_text().to_vec(), + }; + assert_eq!( + Pallet::::validate_unsigned(source, &call), + Ok(ValidTransaction { + priority: 100, + requires: vec![], + provides: vec![("claims", eth(&dave())).encode()], + longevity: TransactionLongevity::max_value(), + propagate: true, + }) + ); + assert_eq!( + Pallet::::validate_unsigned( + source, + &ClaimsCall::claim_attest { + dest: 1, + ethereum_signature: EcdsaSignature([0; 65]), + statement: StatementKind::Regular.to_text().to_vec() + } + ), + InvalidTransaction::Custom(ValidityError::InvalidEthereumSignature.into()).into(), + ); + + let s = sig::(&bob(), &1u64.encode(), StatementKind::Regular.to_text()); + let call = ClaimsCall::claim_attest { + dest: 1, + ethereum_signature: s, + statement: StatementKind::Regular.to_text().to_vec(), + }; + assert_eq!( + Pallet::::validate_unsigned(source, &call), + InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(), + ); + + let s = sig::(&dave(), &1u64.encode(), StatementKind::Saft.to_text()); + let call = ClaimsCall::claim_attest { + dest: 1, + ethereum_signature: s, + statement: StatementKind::Regular.to_text().to_vec(), + }; + assert_eq!( + Pallet::::validate_unsigned(source, &call), + InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()).into(), + ); + + let s = sig::(&dave(), &1u64.encode(), StatementKind::Saft.to_text()); + let call = ClaimsCall::claim_attest { + dest: 1, + ethereum_signature: s, + statement: StatementKind::Saft.to_text().to_vec(), + }; + assert_eq!( + Pallet::::validate_unsigned(source, &call), + InvalidTransaction::Custom(ValidityError::InvalidStatement.into()).into(), + ); + }); +} diff --git a/polkadot/runtime/common/src/identity_migrator.rs b/polkadot/runtime/common/src/identity_migrator.rs index 126c886280e6..e3835b692526 100644 --- a/polkadot/runtime/common/src/identity_migrator.rs +++ b/polkadot/runtime/common/src/identity_migrator.rs @@ -160,12 +160,22 @@ pub trait OnReapIdentity { /// - `bytes`: The byte size of `IdentityInfo`. /// - `subs`: The number of sub-accounts they had. fn on_reap_identity(who: &AccountId, bytes: u32, subs: u32) -> DispatchResult; + + /// Ensure that identity reaping will be succesful in benchmarking. + /// + /// Should setup the state in a way that the same call ot `[Self::on_reap_identity]` will be + /// successful. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_identity_reaping(who: &AccountId, bytes: u32, subs: u32); } impl OnReapIdentity for () { fn on_reap_identity(_who: &AccountId, _bytes: u32, _subs: u32) -> DispatchResult { Ok(()) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_identity_reaping(_: &AccountId, _: u32, _: u32) {} } #[cfg(feature = "runtime-benchmarks")] @@ -219,6 +229,12 @@ mod benchmarks { } Identity::::set_subs(target_origin.clone(), subs.clone())?; + T::ReapIdentityHandler::ensure_successful_identity_reaping( + &target, + info.encoded_size() as u32, + subs.len() as u32, + ); + // add registrars and provide judgements let registrar_origin = T::RegistrarOrigin::try_successful_origin() .expect("RegistrarOrigin has no successful origin required for the benchmark"); diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 2f79d223d3c0..9a290f08609a 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -138,6 +138,15 @@ pub enum VersionedLocatableAsset { V3 { location: xcm::v3::Location, asset_id: xcm::v3::AssetId }, #[codec(index = 4)] V4 { location: xcm::v4::Location, asset_id: xcm::v4::AssetId }, + #[codec(index = 5)] + V5 { location: xcm::v5::Location, asset_id: xcm::v5::AssetId }, +} + +/// A conversion from latest xcm to `VersionedLocatableAsset`. +impl From<(xcm::latest::Location, xcm::latest::AssetId)> for VersionedLocatableAsset { + fn from(value: (xcm::latest::Location, xcm::latest::AssetId)) -> Self { + VersionedLocatableAsset::V5 { location: value.0, asset_id: value.1 } + } } /// Converts the [`VersionedLocatableAsset`] to the [`xcm_builder::LocatableAssetId`]. @@ -149,12 +158,22 @@ impl TryConvert asset: VersionedLocatableAsset, ) -> Result { match asset { - VersionedLocatableAsset::V3 { location, asset_id } => + VersionedLocatableAsset::V3 { location, asset_id } => { + let v4_location: xcm::v4::Location = + location.try_into().map_err(|_| asset.clone())?; + let v4_asset_id: xcm::v4::AssetId = + asset_id.try_into().map_err(|_| asset.clone())?; + Ok(xcm_builder::LocatableAssetId { + location: v4_location.try_into().map_err(|_| asset.clone())?, + asset_id: v4_asset_id.try_into().map_err(|_| asset.clone())?, + }) + }, + VersionedLocatableAsset::V4 { ref location, ref asset_id } => Ok(xcm_builder::LocatableAssetId { - location: location.try_into().map_err(|_| asset.clone())?, - asset_id: asset_id.try_into().map_err(|_| asset.clone())?, + location: location.clone().try_into().map_err(|_| asset.clone())?, + asset_id: asset_id.clone().try_into().map_err(|_| asset.clone())?, }), - VersionedLocatableAsset::V4 { location, asset_id } => + VersionedLocatableAsset::V5 { location, asset_id } => Ok(xcm_builder::LocatableAssetId { location, asset_id }), } } @@ -167,12 +186,12 @@ impl TryConvert<&VersionedLocation, xcm::latest::Location> for VersionedLocation location: &VersionedLocation, ) -> Result { let latest = match location.clone() { - VersionedLocation::V2(l) => { - let v3: xcm::v3::Location = l.try_into().map_err(|_| location)?; - v3.try_into().map_err(|_| location)? + VersionedLocation::V3(l) => { + let v4_location: xcm::v4::Location = l.try_into().map_err(|_| location)?; + v4_location.try_into().map_err(|_| location)? }, - VersionedLocation::V3(l) => l.try_into().map_err(|_| location)?, - VersionedLocation::V4(l) => l, + VersionedLocation::V4(l) => l.try_into().map_err(|_| location)?, + VersionedLocation::V5(l) => l, }; Ok(latest) } @@ -188,11 +207,25 @@ where fn contains(asset: &VersionedLocatableAsset) -> bool { use VersionedLocatableAsset::*; let (location, asset_id) = match asset.clone() { - V3 { location, asset_id } => match (location.try_into(), asset_id.try_into()) { + V3 { location, asset_id } => { + let v4_location: xcm::v4::Location = match location.try_into() { + Ok(l) => l, + Err(_) => return false, + }; + let v4_asset_id: xcm::v4::AssetId = match asset_id.try_into() { + Ok(a) => a, + Err(_) => return false, + }; + match (v4_location.try_into(), v4_asset_id.try_into()) { + (Ok(l), Ok(a)) => (l, a), + _ => return false, + } + }, + V4 { location, asset_id } => match (location.try_into(), asset_id.try_into()) { (Ok(l), Ok(a)) => (l, a), _ => return false, }, - V4 { location, asset_id } => (location, asset_id), + V5 { location, asset_id } => (location, asset_id), }; C::contains(&location, &asset_id.0) } @@ -213,17 +246,14 @@ pub mod benchmarks { pub struct AssetRateArguments; impl AssetKindFactory for AssetRateArguments { fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { - VersionedLocatableAsset::V4 { - location: xcm::v4::Location::new(0, [xcm::v4::Junction::Parachain(seed)]), - asset_id: xcm::v4::Location::new( + ( + Location::new(0, [Parachain(seed)]), + AssetId(Location::new( 0, - [ - xcm::v4::Junction::PalletInstance(seed.try_into().unwrap()), - xcm::v4::Junction::GeneralIndex(seed.into()), - ], - ) - .into(), - } + [PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())], + )), + ) + .into() } } @@ -238,26 +268,17 @@ pub mod benchmarks { for TreasuryArguments { fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { - VersionedLocatableAsset::V3 { - location: xcm::v3::Location::new( - Parents::get(), - [xcm::v3::Junction::Parachain(ParaId::get())], - ), - asset_id: xcm::v3::Location::new( + ( + Location::new(Parents::get(), [Junction::Parachain(ParaId::get())]), + AssetId(Location::new( 0, - [ - xcm::v3::Junction::PalletInstance(seed.try_into().unwrap()), - xcm::v3::Junction::GeneralIndex(seed.into()), - ], - ) - .into(), - } + [PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())], + )), + ) + .into() } fn create_beneficiary(seed: [u8; 32]) -> VersionedLocation { - VersionedLocation::V4(xcm::v4::Location::new( - 0, - [xcm::v4::Junction::AccountId32 { network: None, id: seed }], - )) + VersionedLocation::from(Location::new(0, [AccountId32 { network: None, id: seed }])) } } } diff --git a/polkadot/runtime/common/src/paras_registrar/benchmarking.rs b/polkadot/runtime/common/src/paras_registrar/benchmarking.rs new file mode 100644 index 000000000000..95df8a969576 --- /dev/null +++ b/polkadot/runtime/common/src/paras_registrar/benchmarking.rs @@ -0,0 +1,171 @@ +// 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 . + +//! Benchmarking for paras_registrar pallet + +#[cfg(feature = "runtime-benchmarks")] +use super::{Pallet as Registrar, *}; +use crate::traits::Registrar as RegistrarT; +use frame_support::assert_ok; +use frame_system::RawOrigin; +use polkadot_primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MIN_CODE_SIZE}; +use polkadot_runtime_parachains::{paras, shared, Origin as ParaOrigin}; +use sp_runtime::traits::Bounded; + +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +fn register_para(id: u32) -> ParaId { + let para = ParaId::from(id); + let genesis_head = Registrar::::worst_head_data(); + let validation_code = Registrar::::worst_validation_code(); + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + assert_ok!(Registrar::::reserve(RawOrigin::Signed(caller.clone()).into())); + assert_ok!(Registrar::::register( + RawOrigin::Signed(caller).into(), + para, + genesis_head, + validation_code.clone() + )); + assert_ok!(polkadot_runtime_parachains::paras::Pallet::::add_trusted_validation_code( + frame_system::Origin::::Root.into(), + validation_code, + )); + return para +} + +fn para_origin(id: u32) -> ParaOrigin { + ParaOrigin::Parachain(id.into()) +} + +// This function moves forward to the next scheduled session for parachain lifecycle upgrades. +fn next_scheduled_session() { + shared::Pallet::::set_session_index(shared::Pallet::::scheduled_session()); + paras::Pallet::::test_on_new_session(); +} + +benchmarks! { + where_clause { where ParaOrigin: Into<::RuntimeOrigin> } + + reserve { + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + }: _(RawOrigin::Signed(caller.clone())) + verify { + assert_last_event::(Event::::Reserved { para_id: LOWEST_PUBLIC_ID, who: caller }.into()); + assert!(Paras::::get(LOWEST_PUBLIC_ID).is_some()); + assert_eq!(paras::Pallet::::lifecycle(LOWEST_PUBLIC_ID), None); + } + + register { + let para = LOWEST_PUBLIC_ID; + let genesis_head = Registrar::::worst_head_data(); + let validation_code = Registrar::::worst_validation_code(); + let caller: T::AccountId = whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + assert_ok!(Registrar::::reserve(RawOrigin::Signed(caller.clone()).into())); + }: _(RawOrigin::Signed(caller.clone()), para, genesis_head, validation_code.clone()) + verify { + assert_last_event::(Event::::Registered{ para_id: para, manager: caller }.into()); + assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Onboarding)); + assert_ok!(polkadot_runtime_parachains::paras::Pallet::::add_trusted_validation_code( + frame_system::Origin::::Root.into(), + validation_code, + )); + next_scheduled_session::(); + assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Parathread)); + } + + force_register { + let manager: T::AccountId = account("manager", 0, 0); + let deposit = 0u32.into(); + let para = ParaId::from(69); + let genesis_head = Registrar::::worst_head_data(); + let validation_code = Registrar::::worst_validation_code(); + }: _(RawOrigin::Root, manager.clone(), deposit, para, genesis_head, validation_code.clone()) + verify { + assert_last_event::(Event::::Registered { para_id: para, manager }.into()); + assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Onboarding)); + assert_ok!(polkadot_runtime_parachains::paras::Pallet::::add_trusted_validation_code( + frame_system::Origin::::Root.into(), + validation_code, + )); + next_scheduled_session::(); + assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Parathread)); + } + + deregister { + let para = register_para::(LOWEST_PUBLIC_ID.into()); + next_scheduled_session::(); + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), para) + verify { + assert_last_event::(Event::::Deregistered { para_id: para }.into()); + } + + swap { + // On demand parachain + let parathread = register_para::(LOWEST_PUBLIC_ID.into()); + let parachain = register_para::((LOWEST_PUBLIC_ID + 1).into()); + + let parachain_origin = para_origin(parachain.into()); + + // Actually finish registration process + next_scheduled_session::(); + + // Upgrade the parachain + Registrar::::make_parachain(parachain)?; + next_scheduled_session::(); + + assert_eq!(paras::Pallet::::lifecycle(parachain), Some(ParaLifecycle::Parachain)); + assert_eq!(paras::Pallet::::lifecycle(parathread), Some(ParaLifecycle::Parathread)); + + let caller: T::AccountId = whitelisted_caller(); + Registrar::::swap(parachain_origin.into(), parachain, parathread)?; + }: _(RawOrigin::Signed(caller.clone()), parathread, parachain) + verify { + next_scheduled_session::(); + // Swapped! + assert_eq!(paras::Pallet::::lifecycle(parachain), Some(ParaLifecycle::Parathread)); + assert_eq!(paras::Pallet::::lifecycle(parathread), Some(ParaLifecycle::Parachain)); + } + + schedule_code_upgrade { + let b in MIN_CODE_SIZE .. MAX_CODE_SIZE; + let new_code = ValidationCode(vec![0; b as usize]); + let para_id = ParaId::from(1000); + }: _(RawOrigin::Root, para_id, new_code) + + set_current_head { + let b in 1 .. MAX_HEAD_DATA_SIZE; + let new_head = HeadData(vec![0; b as usize]); + let para_id = ParaId::from(1000); + }: _(RawOrigin::Root, para_id, new_head) + + impl_benchmark_test_suite!( + Registrar, + crate::integration_tests::new_test_ext(), + crate::integration_tests::Test, + ); +} diff --git a/polkadot/runtime/common/src/paras_registrar/mock.rs b/polkadot/runtime/common/src/paras_registrar/mock.rs new file mode 100644 index 000000000000..1627fd70365d --- /dev/null +++ b/polkadot/runtime/common/src/paras_registrar/mock.rs @@ -0,0 +1,254 @@ +// 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 . + +//! Mocking utilities for testing in paras_registrar pallet. + +#[cfg(test)] +use super::*; +use crate::paras_registrar; +use alloc::collections::btree_map::BTreeMap; +use frame_support::{ + derive_impl, parameter_types, + traits::{OnFinalize, OnInitialize}, +}; +use frame_system::limits; +use polkadot_primitives::{Balance, BlockNumber, MAX_CODE_SIZE}; +use polkadot_runtime_parachains::{configuration, origin, shared}; +use sp_core::H256; +use sp_io::TestExternalities; +use sp_keyring::Sr25519Keyring; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + transaction_validity::TransactionPriority, + BuildStorage, Perbill, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Configuration: configuration, + Parachains: paras, + ParasShared: shared, + Registrar: paras_registrar, + ParachainsOrigin: origin, + } +); + +impl frame_system::offchain::CreateTransactionBase for Test +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type RuntimeCall = RuntimeCall; +} + +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } +} + +const NORMAL_RATIO: Perbill = Perbill::from_percent(75); +parameter_types! { + pub BlockWeights: limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); + pub BlockLength: limits::BlockLength = + limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO); +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type DbWeight = (); + type BlockWeights = BlockWeights; + type BlockLength = BlockLength; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type Balance = Balance; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; +} + +impl shared::Config for Test { + type DisabledValidators = (); +} + +impl origin::Config for Test {} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +impl paras::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type QueueFootprinter = (); + type NextSessionRotation = crate::mock::TestNextSessionRotation; + type OnNewHead = (); + type AssignCoretime = (); +} + +impl configuration::Config for Test { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub const ParaDeposit: Balance = 10; + pub const DataDepositPerByte: Balance = 1; + pub const MaxRetries: u32 = 3; +} + +impl Config for Test { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type OnSwap = MockSwap; + type ParaDeposit = ParaDeposit; + type DataDepositPerByte = DataDepositPerByte; + type WeightInfo = TestWeightInfo; +} + +pub fn new_test_ext() -> TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + configuration::GenesisConfig:: { + config: configuration::HostConfiguration { + max_code_size: MAX_CODE_SIZE, + max_head_data_size: 1 * 1024 * 1024, // 1 MB + ..Default::default() + }, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(1, 10_000_000), (2, 10_000_000), (3, 10_000_000)], + } + .assimilate_storage(&mut t) + .unwrap(); + + t.into() +} + +parameter_types! { + pub static SwapData: BTreeMap = BTreeMap::new(); +} + +pub struct MockSwap; +impl OnSwap for MockSwap { + fn on_swap(one: ParaId, other: ParaId) { + let mut swap_data = SwapData::get(); + let one_data = swap_data.remove(&one).unwrap_or_default(); + let other_data = swap_data.remove(&other).unwrap_or_default(); + swap_data.insert(one, other_data); + swap_data.insert(other, one_data); + SwapData::set(swap_data); + } +} + +pub const BLOCKS_PER_SESSION: u32 = 3; + +pub const VALIDATORS: &[Sr25519Keyring] = &[ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Ferdie, +]; + +pub fn run_to_block(n: BlockNumber) { + // NOTE that this function only simulates modules of interest. Depending on new pallet may + // require adding it here. + assert!(System::block_number() < n); + while System::block_number() < n { + let b = System::block_number(); + + if System::block_number() > 1 { + System::on_finalize(System::block_number()); + } + // Session change every 3 blocks. + if (b + 1) % BLOCKS_PER_SESSION == 0 { + let session_index = shared::CurrentSessionIndex::::get() + 1; + let validators_pub_keys = VALIDATORS.iter().map(|v| v.public().into()).collect(); + + shared::Pallet::::set_session_index(session_index); + shared::Pallet::::set_active_validators_ascending(validators_pub_keys); + + Parachains::test_on_new_session(); + } + System::set_block_number(b + 1); + System::on_initialize(System::block_number()); + } +} + +pub fn run_to_session(n: BlockNumber) { + let block_number = n * BLOCKS_PER_SESSION; + run_to_block(block_number); +} + +pub fn test_genesis_head(size: usize) -> HeadData { + HeadData(vec![0u8; size]) +} + +pub fn test_validation_code(size: usize) -> ValidationCode { + let validation_code = vec![0u8; size as usize]; + ValidationCode(validation_code) +} + +pub fn para_origin(id: ParaId) -> RuntimeOrigin { + polkadot_runtime_parachains::Origin::Parachain(id).into() +} + +pub fn max_code_size() -> u32 { + configuration::ActiveConfig::::get().max_code_size +} + +pub fn max_head_size() -> u32 { + configuration::ActiveConfig::::get().max_head_data_size +} diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 2ead621dedf0..aed0729c9d51 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -561,15 +561,16 @@ impl Pallet { origin: ::RuntimeOrigin, id: ParaId, ) -> DispatchResult { - ensure_signed(origin.clone()) - .map_err(|e| e.into()) - .and_then(|who| -> DispatchResult { - let para_info = Paras::::get(id).ok_or(Error::::NotRegistered)?; + if let Ok(who) = ensure_signed(origin.clone()) { + let para_info = Paras::::get(id).ok_or(Error::::NotRegistered)?; + + if para_info.manager == who { ensure!(!para_info.is_locked(), Error::::ParaLocked); - ensure!(para_info.manager == who, Error::::NotOwner); - Ok(()) - }) - .or_else(|_| -> DispatchResult { Self::ensure_root_or_para(origin, id) }) + return Ok(()) + } + } + + Self::ensure_root_or_para(origin, id) } /// Ensure the origin is one of Root or the `para` itself. @@ -577,14 +578,14 @@ impl Pallet { origin: ::RuntimeOrigin, id: ParaId, ) -> DispatchResult { - if let Ok(caller_id) = ensure_parachain(::RuntimeOrigin::from(origin.clone())) - { - // Check if matching para id... - ensure!(caller_id == id, Error::::NotOwner); - } else { - // Check if root... - ensure_root(origin.clone())?; + if ensure_root(origin.clone()).is_ok() { + return Ok(()) } + + let caller_id = ensure_parachain(::RuntimeOrigin::from(origin))?; + // Check if matching para id... + ensure!(caller_id == id, Error::::NotOwner); + Ok(()) } @@ -713,967 +714,10 @@ impl OnNewHead for Pallet { } #[cfg(test)] -mod tests { - use super::*; - use crate::{ - mock::conclude_pvf_checking, paras_registrar, traits::Registrar as RegistrarTrait, - }; - use alloc::collections::btree_map::BTreeMap; - use frame_support::{ - assert_noop, assert_ok, derive_impl, parameter_types, - traits::{OnFinalize, OnInitialize}, - }; - use frame_system::limits; - use pallet_balances::Error as BalancesError; - use polkadot_primitives::{Balance, BlockNumber, SessionIndex, MAX_CODE_SIZE}; - use polkadot_runtime_parachains::{configuration, origin, shared}; - use sp_core::H256; - use sp_io::TestExternalities; - use sp_keyring::Sr25519Keyring; - use sp_runtime::{ - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, - transaction_validity::TransactionPriority, - BuildStorage, Perbill, - }; - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlockU32; - - frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Configuration: configuration, - Parachains: paras, - ParasShared: shared, - Registrar: paras_registrar, - ParachainsOrigin: origin, - } - ); - - impl frame_system::offchain::CreateTransactionBase for Test - where - RuntimeCall: From, - { - type Extrinsic = UncheckedExtrinsic; - type RuntimeCall = RuntimeCall; - } - - impl frame_system::offchain::CreateInherent for Test - where - RuntimeCall: From, - { - fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { - UncheckedExtrinsic::new_bare(call) - } - } - - const NORMAL_RATIO: Perbill = Perbill::from_percent(75); - parameter_types! { - pub BlockWeights: limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); - pub BlockLength: limits::BlockLength = - limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO); - } - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type DbWeight = (); - type BlockWeights = BlockWeights; - type BlockLength = BlockLength; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - parameter_types! { - pub const ExistentialDeposit: Balance = 1; - } - - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] - impl pallet_balances::Config for Test { - type Balance = Balance; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - } - - impl shared::Config for Test { - type DisabledValidators = (); - } - - impl origin::Config for Test {} - - parameter_types! { - pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); - } - - impl paras::Config for Test { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = paras::TestWeightInfo; - type UnsignedPriority = ParasUnsignedPriority; - type QueueFootprinter = (); - type NextSessionRotation = crate::mock::TestNextSessionRotation; - type OnNewHead = (); - type AssignCoretime = (); - } - - impl configuration::Config for Test { - type WeightInfo = configuration::TestWeightInfo; - } - - parameter_types! { - pub const ParaDeposit: Balance = 10; - pub const DataDepositPerByte: Balance = 1; - pub const MaxRetries: u32 = 3; - } - - impl Config for Test { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type OnSwap = MockSwap; - type ParaDeposit = ParaDeposit; - type DataDepositPerByte = DataDepositPerByte; - type WeightInfo = TestWeightInfo; - } - - pub fn new_test_ext() -> TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - configuration::GenesisConfig:: { - config: configuration::HostConfiguration { - max_code_size: MAX_CODE_SIZE, - max_head_data_size: 1 * 1024 * 1024, // 1 MB - ..Default::default() - }, - } - .assimilate_storage(&mut t) - .unwrap(); - - pallet_balances::GenesisConfig:: { - balances: vec![(1, 10_000_000), (2, 10_000_000), (3, 10_000_000)], - } - .assimilate_storage(&mut t) - .unwrap(); - - t.into() - } - - parameter_types! { - pub static SwapData: BTreeMap = BTreeMap::new(); - } - - pub struct MockSwap; - impl OnSwap for MockSwap { - fn on_swap(one: ParaId, other: ParaId) { - let mut swap_data = SwapData::get(); - let one_data = swap_data.remove(&one).unwrap_or_default(); - let other_data = swap_data.remove(&other).unwrap_or_default(); - swap_data.insert(one, other_data); - swap_data.insert(other, one_data); - SwapData::set(swap_data); - } - } - - const BLOCKS_PER_SESSION: u32 = 3; - - const VALIDATORS: &[Sr25519Keyring] = &[ - Sr25519Keyring::Alice, - Sr25519Keyring::Bob, - Sr25519Keyring::Charlie, - Sr25519Keyring::Dave, - Sr25519Keyring::Ferdie, - ]; - - fn run_to_block(n: BlockNumber) { - // NOTE that this function only simulates modules of interest. Depending on new pallet may - // require adding it here. - assert!(System::block_number() < n); - while System::block_number() < n { - let b = System::block_number(); - - if System::block_number() > 1 { - System::on_finalize(System::block_number()); - } - // Session change every 3 blocks. - if (b + 1) % BLOCKS_PER_SESSION == 0 { - let session_index = shared::CurrentSessionIndex::::get() + 1; - let validators_pub_keys = VALIDATORS.iter().map(|v| v.public().into()).collect(); - - shared::Pallet::::set_session_index(session_index); - shared::Pallet::::set_active_validators_ascending(validators_pub_keys); - - Parachains::test_on_new_session(); - } - System::set_block_number(b + 1); - System::on_initialize(System::block_number()); - } - } - - fn run_to_session(n: BlockNumber) { - let block_number = n * BLOCKS_PER_SESSION; - run_to_block(block_number); - } - - fn test_genesis_head(size: usize) -> HeadData { - HeadData(vec![0u8; size]) - } +mod mock; - fn test_validation_code(size: usize) -> ValidationCode { - let validation_code = vec![0u8; size as usize]; - ValidationCode(validation_code) - } - - fn para_origin(id: ParaId) -> RuntimeOrigin { - polkadot_runtime_parachains::Origin::Parachain(id).into() - } - - fn max_code_size() -> u32 { - configuration::ActiveConfig::::get().max_code_size - } - - fn max_head_size() -> u32 { - configuration::ActiveConfig::::get().max_head_data_size - } - - #[test] - fn basic_setup_works() { - new_test_ext().execute_with(|| { - assert_eq!(PendingSwap::::get(&ParaId::from(0u32)), None); - assert_eq!(Paras::::get(&ParaId::from(0u32)), None); - }); - } - - #[test] - fn end_to_end_scenario_works() { - new_test_ext().execute_with(|| { - let para_id = LOWEST_PUBLIC_ID; - - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - // first para is not yet registered - assert!(!Parachains::is_parathread(para_id)); - // We register the Para ID - let validation_code = test_validation_code(32); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(32), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - run_to_session(START_SESSION_INDEX + 2); - // It is now a parathread (on-demand parachain). - assert!(Parachains::is_parathread(para_id)); - assert!(!Parachains::is_parachain(para_id)); - // Some other external process will elevate on-demand to lease holding parachain - assert_ok!(Registrar::make_parachain(para_id)); - run_to_session(START_SESSION_INDEX + 4); - // It is now a lease holding parachain. - assert!(!Parachains::is_parathread(para_id)); - assert!(Parachains::is_parachain(para_id)); - // Turn it back into a parathread (on-demand parachain) - assert_ok!(Registrar::make_parathread(para_id)); - run_to_session(START_SESSION_INDEX + 6); - assert!(Parachains::is_parathread(para_id)); - assert!(!Parachains::is_parachain(para_id)); - // Deregister it - assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,)); - run_to_session(START_SESSION_INDEX + 8); - // It is nothing - assert!(!Parachains::is_parathread(para_id)); - assert!(!Parachains::is_parachain(para_id)); - }); - } - - #[test] - fn register_works() { - new_test_ext().execute_with(|| { - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - let para_id = LOWEST_PUBLIC_ID; - assert!(!Parachains::is_parathread(para_id)); - - let validation_code = test_validation_code(32); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_eq!(Balances::reserved_balance(&1), ::ParaDeposit::get()); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(32), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - run_to_session(START_SESSION_INDEX + 2); - assert!(Parachains::is_parathread(para_id)); - // Even though the registered validation code has a smaller size than the maximum the - // para manager's deposit is reserved as though they registered the maximum-sized code. - // Consequently, they can upgrade their code to the maximum size at any point without - // additional cost. - let validation_code_deposit = - max_code_size() as BalanceOf * ::DataDepositPerByte::get(); - let head_deposit = 32 * ::DataDepositPerByte::get(); - assert_eq!( - Balances::reserved_balance(&1), - ::ParaDeposit::get() + head_deposit + validation_code_deposit - ); - }); - } - - #[test] - fn schedule_code_upgrade_validates_code() { - new_test_ext().execute_with(|| { - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - let para_id = LOWEST_PUBLIC_ID; - assert!(!Parachains::is_parathread(para_id)); - - let validation_code = test_validation_code(32); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_eq!(Balances::reserved_balance(&1), ::ParaDeposit::get()); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(32), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - run_to_session(START_SESSION_INDEX + 2); - assert!(Parachains::is_parathread(para_id)); - - let new_code = test_validation_code(0); - assert_noop!( - Registrar::schedule_code_upgrade( - RuntimeOrigin::signed(1), - para_id, - new_code.clone(), - ), - paras::Error::::InvalidCode - ); - - let new_code = test_validation_code(max_code_size() as usize + 1); - assert_noop!( - Registrar::schedule_code_upgrade( - RuntimeOrigin::signed(1), - para_id, - new_code.clone(), - ), - paras::Error::::InvalidCode - ); - }); - } - - #[test] - fn register_handles_basic_errors() { - new_test_ext().execute_with(|| { - let para_id = LOWEST_PUBLIC_ID; - - assert_noop!( - Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(max_head_size() as usize), - test_validation_code(max_code_size() as usize), - ), - Error::::NotReserved - ); - - // Successfully register para - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - - assert_noop!( - Registrar::register( - RuntimeOrigin::signed(2), - para_id, - test_genesis_head(max_head_size() as usize), - test_validation_code(max_code_size() as usize), - ), - Error::::NotOwner - ); - - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(max_head_size() as usize), - test_validation_code(max_code_size() as usize), - )); - // Can skip pre-check and deregister para which's still onboarding. - run_to_session(2); - - assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id)); - - // Can't do it again - assert_noop!( - Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(max_head_size() as usize), - test_validation_code(max_code_size() as usize), - ), - Error::::NotReserved - ); - - // Head Size Check - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2))); - assert_noop!( - Registrar::register( - RuntimeOrigin::signed(2), - para_id + 1, - test_genesis_head((max_head_size() + 1) as usize), - test_validation_code(max_code_size() as usize), - ), - Error::::HeadDataTooLarge - ); - - // Code Size Check - assert_noop!( - Registrar::register( - RuntimeOrigin::signed(2), - para_id + 1, - test_genesis_head(max_head_size() as usize), - test_validation_code((max_code_size() + 1) as usize), - ), - Error::::CodeTooLarge - ); - - // Needs enough funds for deposit - assert_noop!( - Registrar::reserve(RuntimeOrigin::signed(1337)), - BalancesError::::InsufficientBalance - ); - }); - } - - #[test] - fn deregister_works() { - new_test_ext().execute_with(|| { - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - let para_id = LOWEST_PUBLIC_ID; - assert!(!Parachains::is_parathread(para_id)); - - let validation_code = test_validation_code(32); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(32), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - run_to_session(START_SESSION_INDEX + 2); - assert!(Parachains::is_parathread(para_id)); - assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,)); - run_to_session(START_SESSION_INDEX + 4); - assert!(paras::Pallet::::lifecycle(para_id).is_none()); - assert_eq!(Balances::reserved_balance(&1), 0); - }); - } - - #[test] - fn deregister_handles_basic_errors() { - new_test_ext().execute_with(|| { - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - let para_id = LOWEST_PUBLIC_ID; - assert!(!Parachains::is_parathread(para_id)); - - let validation_code = test_validation_code(32); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - test_genesis_head(32), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - run_to_session(START_SESSION_INDEX + 2); - assert!(Parachains::is_parathread(para_id)); - // Owner check - assert_noop!(Registrar::deregister(RuntimeOrigin::signed(2), para_id,), BadOrigin); - assert_ok!(Registrar::make_parachain(para_id)); - run_to_session(START_SESSION_INDEX + 4); - // Cant directly deregister parachain - assert_noop!( - Registrar::deregister(RuntimeOrigin::root(), para_id,), - Error::::NotParathread - ); - }); - } - - #[test] - fn swap_works() { - new_test_ext().execute_with(|| { - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - // Successfully register first two parachains - let para_1 = LOWEST_PUBLIC_ID; - let para_2 = LOWEST_PUBLIC_ID + 1; - - let validation_code = test_validation_code(max_code_size() as usize); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_1, - test_genesis_head(max_head_size() as usize), - validation_code.clone(), - )); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(2), - para_2, - test_genesis_head(max_head_size() as usize), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - run_to_session(START_SESSION_INDEX + 2); - - // Upgrade para 1 into a parachain - assert_ok!(Registrar::make_parachain(para_1)); - - // Set some mock swap data. - let mut swap_data = SwapData::get(); - swap_data.insert(para_1, 69); - swap_data.insert(para_2, 1337); - SwapData::set(swap_data); - - run_to_session(START_SESSION_INDEX + 4); - - // Roles are as we expect - assert!(Parachains::is_parachain(para_1)); - assert!(!Parachains::is_parathread(para_1)); - assert!(!Parachains::is_parachain(para_2)); - assert!(Parachains::is_parathread(para_2)); - - // Both paras initiate a swap - // Swap between parachain and parathread - assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,)); - assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,)); - System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped { - para_id: para_2, - other_id: para_1, - })); - - run_to_session(START_SESSION_INDEX + 6); - - // Roles are swapped - assert!(!Parachains::is_parachain(para_1)); - assert!(Parachains::is_parathread(para_1)); - assert!(Parachains::is_parachain(para_2)); - assert!(!Parachains::is_parathread(para_2)); - - // Data is swapped - assert_eq!(SwapData::get().get(¶_1).unwrap(), &1337); - assert_eq!(SwapData::get().get(¶_2).unwrap(), &69); - - // Both paras initiate a swap - // Swap between parathread and parachain - assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,)); - assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,)); - System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped { - para_id: para_2, - other_id: para_1, - })); - - // Data is swapped - assert_eq!(SwapData::get().get(¶_1).unwrap(), &69); - assert_eq!(SwapData::get().get(¶_2).unwrap(), &1337); - - // Parachain to parachain swap - let para_3 = LOWEST_PUBLIC_ID + 2; - let validation_code = test_validation_code(max_code_size() as usize); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(3))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(3), - para_3, - test_genesis_head(max_head_size() as usize), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX + 6); - - run_to_session(START_SESSION_INDEX + 8); - - // Upgrade para 3 into a parachain - assert_ok!(Registrar::make_parachain(para_3)); - - // Set some mock swap data. - let mut swap_data = SwapData::get(); - swap_data.insert(para_3, 777); - SwapData::set(swap_data); - - run_to_session(START_SESSION_INDEX + 10); - - // Both are parachains - assert!(Parachains::is_parachain(para_3)); - assert!(!Parachains::is_parathread(para_3)); - assert!(Parachains::is_parachain(para_1)); - assert!(!Parachains::is_parathread(para_1)); - - // Both paras initiate a swap - // Swap between parachain and parachain - assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_3,)); - assert_ok!(Registrar::swap(para_origin(para_3), para_3, para_1,)); - System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped { - para_id: para_3, - other_id: para_1, - })); - - // Data is swapped - assert_eq!(SwapData::get().get(¶_3).unwrap(), &69); - assert_eq!(SwapData::get().get(¶_1).unwrap(), &777); - }); - } - - #[test] - fn para_lock_works() { - new_test_ext().execute_with(|| { - run_to_block(1); - - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - let para_id = LOWEST_PUBLIC_ID; - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_id, - vec![1; 3].into(), - test_validation_code(32) - )); - - assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin); - - // Once they produces new block, we lock them in. - Registrar::on_new_head(para_id, &Default::default()); - - // Owner cannot pass origin check when checking lock - assert_noop!( - Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id), - BadOrigin - ); - // Owner cannot remove lock. - assert_noop!(Registrar::remove_lock(RuntimeOrigin::signed(1), para_id), BadOrigin); - // Para can. - assert_ok!(Registrar::remove_lock(para_origin(para_id), para_id)); - // Owner can pass origin check again - assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id)); - - // Won't lock again after it is unlocked - Registrar::on_new_head(para_id, &Default::default()); - - assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id)); - }); - } - - #[test] - fn swap_handles_bad_states() { - new_test_ext().execute_with(|| { - const START_SESSION_INDEX: SessionIndex = 1; - run_to_session(START_SESSION_INDEX); - - let para_1 = LOWEST_PUBLIC_ID; - let para_2 = LOWEST_PUBLIC_ID + 1; - - // paras are not yet registered - assert!(!Parachains::is_parathread(para_1)); - assert!(!Parachains::is_parathread(para_2)); - - // Cannot even start a swap - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_1, para_2), - Error::::NotRegistered - ); - - // We register Paras 1 and 2 - let validation_code = test_validation_code(32); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1))); - assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2))); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(1), - para_1, - test_genesis_head(32), - validation_code.clone(), - )); - assert_ok!(Registrar::register( - RuntimeOrigin::signed(2), - para_2, - test_genesis_head(32), - validation_code.clone(), - )); - conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); - - // Cannot swap - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_2, para_1), - Error::::CannotSwap - ); - - run_to_session(START_SESSION_INDEX + 2); - - // They are now parathreads (on-demand parachains). - assert!(Parachains::is_parathread(para_1)); - assert!(Parachains::is_parathread(para_2)); - - // Cannot swap - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_2, para_1), - Error::::CannotSwap - ); - - // Some other external process will elevate one on-demand - // parachain to a lease holding parachain - assert_ok!(Registrar::make_parachain(para_1)); - - // Cannot swap - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_2, para_1), - Error::::CannotSwap - ); - - run_to_session(START_SESSION_INDEX + 3); - - // Cannot swap - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_2, para_1), - Error::::CannotSwap - ); - - run_to_session(START_SESSION_INDEX + 4); - - // It is now a lease holding parachain. - assert!(Parachains::is_parachain(para_1)); - assert!(Parachains::is_parathread(para_2)); - - // Swap works here. - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_2, para_1)); - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. }) - ))); - - run_to_session(START_SESSION_INDEX + 5); - - // Cannot swap - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_2, para_1), - Error::::CannotSwap - ); - - run_to_session(START_SESSION_INDEX + 6); - - // Swap worked! - assert!(Parachains::is_parachain(para_2)); - assert!(Parachains::is_parathread(para_1)); - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. }) - ))); - - // Something starts to downgrade a para - assert_ok!(Registrar::make_parathread(para_2)); - - run_to_session(START_SESSION_INDEX + 7); - - // Cannot swap - assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); - assert_noop!( - Registrar::swap(RuntimeOrigin::root(), para_2, para_1), - Error::::CannotSwap - ); - - run_to_session(START_SESSION_INDEX + 8); - - assert!(Parachains::is_parathread(para_1)); - assert!(Parachains::is_parathread(para_2)); - }); - } -} +#[cfg(test)] +mod tests; #[cfg(feature = "runtime-benchmarks")] -mod benchmarking { - use super::{Pallet as Registrar, *}; - use crate::traits::Registrar as RegistrarT; - use frame_support::assert_ok; - use frame_system::RawOrigin; - use polkadot_primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MIN_CODE_SIZE}; - use polkadot_runtime_parachains::{paras, shared, Origin as ParaOrigin}; - use sp_runtime::traits::Bounded; - - use frame_benchmarking::{account, benchmarks, whitelisted_caller}; - - fn assert_last_event(generic_event: ::RuntimeEvent) { - let events = frame_system::Pallet::::events(); - let system_event: ::RuntimeEvent = generic_event.into(); - // compare to the last event record - let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; - assert_eq!(event, &system_event); - } - - fn register_para(id: u32) -> ParaId { - let para = ParaId::from(id); - let genesis_head = Registrar::::worst_head_data(); - let validation_code = Registrar::::worst_validation_code(); - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - assert_ok!(Registrar::::reserve(RawOrigin::Signed(caller.clone()).into())); - assert_ok!(Registrar::::register( - RawOrigin::Signed(caller).into(), - para, - genesis_head, - validation_code.clone() - )); - assert_ok!(polkadot_runtime_parachains::paras::Pallet::::add_trusted_validation_code( - frame_system::Origin::::Root.into(), - validation_code, - )); - return para - } - - fn para_origin(id: u32) -> ParaOrigin { - ParaOrigin::Parachain(id.into()) - } - - // This function moves forward to the next scheduled session for parachain lifecycle upgrades. - fn next_scheduled_session() { - shared::Pallet::::set_session_index(shared::Pallet::::scheduled_session()); - paras::Pallet::::test_on_new_session(); - } - - benchmarks! { - where_clause { where ParaOrigin: Into<::RuntimeOrigin> } - - reserve { - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - }: _(RawOrigin::Signed(caller.clone())) - verify { - assert_last_event::(Event::::Reserved { para_id: LOWEST_PUBLIC_ID, who: caller }.into()); - assert!(Paras::::get(LOWEST_PUBLIC_ID).is_some()); - assert_eq!(paras::Pallet::::lifecycle(LOWEST_PUBLIC_ID), None); - } - - register { - let para = LOWEST_PUBLIC_ID; - let genesis_head = Registrar::::worst_head_data(); - let validation_code = Registrar::::worst_validation_code(); - let caller: T::AccountId = whitelisted_caller(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - assert_ok!(Registrar::::reserve(RawOrigin::Signed(caller.clone()).into())); - }: _(RawOrigin::Signed(caller.clone()), para, genesis_head, validation_code.clone()) - verify { - assert_last_event::(Event::::Registered{ para_id: para, manager: caller }.into()); - assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Onboarding)); - assert_ok!(polkadot_runtime_parachains::paras::Pallet::::add_trusted_validation_code( - frame_system::Origin::::Root.into(), - validation_code, - )); - next_scheduled_session::(); - assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Parathread)); - } - - force_register { - let manager: T::AccountId = account("manager", 0, 0); - let deposit = 0u32.into(); - let para = ParaId::from(69); - let genesis_head = Registrar::::worst_head_data(); - let validation_code = Registrar::::worst_validation_code(); - }: _(RawOrigin::Root, manager.clone(), deposit, para, genesis_head, validation_code.clone()) - verify { - assert_last_event::(Event::::Registered { para_id: para, manager }.into()); - assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Onboarding)); - assert_ok!(polkadot_runtime_parachains::paras::Pallet::::add_trusted_validation_code( - frame_system::Origin::::Root.into(), - validation_code, - )); - next_scheduled_session::(); - assert_eq!(paras::Pallet::::lifecycle(para), Some(ParaLifecycle::Parathread)); - } - - deregister { - let para = register_para::(LOWEST_PUBLIC_ID.into()); - next_scheduled_session::(); - let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), para) - verify { - assert_last_event::(Event::::Deregistered { para_id: para }.into()); - } - - swap { - // On demand parachain - let parathread = register_para::(LOWEST_PUBLIC_ID.into()); - let parachain = register_para::((LOWEST_PUBLIC_ID + 1).into()); - - let parachain_origin = para_origin(parachain.into()); - - // Actually finish registration process - next_scheduled_session::(); - - // Upgrade the parachain - Registrar::::make_parachain(parachain)?; - next_scheduled_session::(); - - assert_eq!(paras::Pallet::::lifecycle(parachain), Some(ParaLifecycle::Parachain)); - assert_eq!(paras::Pallet::::lifecycle(parathread), Some(ParaLifecycle::Parathread)); - - let caller: T::AccountId = whitelisted_caller(); - Registrar::::swap(parachain_origin.into(), parachain, parathread)?; - }: _(RawOrigin::Signed(caller.clone()), parathread, parachain) - verify { - next_scheduled_session::(); - // Swapped! - assert_eq!(paras::Pallet::::lifecycle(parachain), Some(ParaLifecycle::Parathread)); - assert_eq!(paras::Pallet::::lifecycle(parathread), Some(ParaLifecycle::Parachain)); - } - - schedule_code_upgrade { - let b in MIN_CODE_SIZE .. MAX_CODE_SIZE; - let new_code = ValidationCode(vec![0; b as usize]); - let para_id = ParaId::from(1000); - }: _(RawOrigin::Root, para_id, new_code) - - set_current_head { - let b in 1 .. MAX_HEAD_DATA_SIZE; - let new_head = HeadData(vec![0; b as usize]); - let para_id = ParaId::from(1000); - }: _(RawOrigin::Root, para_id, new_head) - - impl_benchmark_test_suite!( - Registrar, - crate::integration_tests::new_test_ext(), - crate::integration_tests::Test, - ); - } -} +mod benchmarking; diff --git a/polkadot/runtime/common/src/paras_registrar/tests.rs b/polkadot/runtime/common/src/paras_registrar/tests.rs new file mode 100644 index 000000000000..66fef31c9afd --- /dev/null +++ b/polkadot/runtime/common/src/paras_registrar/tests.rs @@ -0,0 +1,588 @@ +// 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 . + +//! Tests for the paras_registrar pallet. + +#[cfg(test)] +use super::*; +use crate::{ + mock::conclude_pvf_checking, paras_registrar, paras_registrar::mock::*, + traits::Registrar as RegistrarTrait, +}; +use frame_support::{assert_noop, assert_ok}; +use pallet_balances::Error as BalancesError; +use polkadot_primitives::SessionIndex; +use sp_runtime::traits::BadOrigin; + +#[test] +fn end_to_end_scenario_works() { + new_test_ext().execute_with(|| { + let para_id = LOWEST_PUBLIC_ID; + + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + // first para is not yet registered + assert!(!Parachains::is_parathread(para_id)); + // We register the Para ID + let validation_code = test_validation_code(32); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + // It is now a parathread (on-demand parachain). + assert!(Parachains::is_parathread(para_id)); + assert!(!Parachains::is_parachain(para_id)); + // Some other external process will elevate on-demand to lease holding parachain + assert_ok!(mock::Registrar::make_parachain(para_id)); + run_to_session(START_SESSION_INDEX + 4); + // It is now a lease holding parachain. + assert!(!Parachains::is_parathread(para_id)); + assert!(Parachains::is_parachain(para_id)); + // Turn it back into a parathread (on-demand parachain) + assert_ok!(mock::Registrar::make_parathread(para_id)); + run_to_session(START_SESSION_INDEX + 6); + assert!(Parachains::is_parathread(para_id)); + assert!(!Parachains::is_parachain(para_id)); + // Deregister it + assert_ok!(mock::Registrar::deregister(RuntimeOrigin::root(), para_id,)); + run_to_session(START_SESSION_INDEX + 8); + // It is nothing + assert!(!Parachains::is_parathread(para_id)); + assert!(!Parachains::is_parachain(para_id)); + }); +} + +#[test] +fn register_works() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + let para_id = LOWEST_PUBLIC_ID; + assert!(!Parachains::is_parathread(para_id)); + + let validation_code = test_validation_code(32); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_eq!(Balances::reserved_balance(&1), ::ParaDeposit::get()); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + assert!(Parachains::is_parathread(para_id)); + // Even though the registered validation code has a smaller size than the maximum the + // para manager's deposit is reserved as though they registered the maximum-sized code. + // Consequently, they can upgrade their code to the maximum size at any point without + // additional cost. + let validation_code_deposit = + max_code_size() as BalanceOf * ::DataDepositPerByte::get(); + let head_deposit = 32 * ::DataDepositPerByte::get(); + assert_eq!( + Balances::reserved_balance(&1), + ::ParaDeposit::get() + head_deposit + validation_code_deposit + ); + }); +} + +#[test] +fn schedule_code_upgrade_validates_code() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + let para_id = LOWEST_PUBLIC_ID; + assert!(!Parachains::is_parathread(para_id)); + + let validation_code = test_validation_code(32); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_eq!(Balances::reserved_balance(&1), ::ParaDeposit::get()); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + assert!(Parachains::is_parathread(para_id)); + + let new_code = test_validation_code(0); + assert_noop!( + mock::Registrar::schedule_code_upgrade( + RuntimeOrigin::signed(1), + para_id, + new_code.clone(), + ), + paras::Error::::InvalidCode + ); + + let new_code = test_validation_code(max_code_size() as usize + 1); + assert_noop!( + mock::Registrar::schedule_code_upgrade( + RuntimeOrigin::signed(1), + para_id, + new_code.clone(), + ), + paras::Error::::InvalidCode + ); + }); +} + +#[test] +fn register_handles_basic_errors() { + new_test_ext().execute_with(|| { + let para_id = LOWEST_PUBLIC_ID; + + assert_noop!( + mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(max_head_size() as usize), + test_validation_code(max_code_size() as usize), + ), + Error::::NotReserved + ); + + // Successfully register para + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + + assert_noop!( + mock::Registrar::register( + RuntimeOrigin::signed(2), + para_id, + test_genesis_head(max_head_size() as usize), + test_validation_code(max_code_size() as usize), + ), + Error::::NotOwner + ); + + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(max_head_size() as usize), + test_validation_code(max_code_size() as usize), + )); + // Can skip pre-check and deregister para which's still onboarding. + run_to_session(2); + + assert_ok!(mock::Registrar::deregister(RuntimeOrigin::root(), para_id)); + + // Can't do it again + assert_noop!( + mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(max_head_size() as usize), + test_validation_code(max_code_size() as usize), + ), + Error::::NotReserved + ); + + // Head Size Check + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(2))); + assert_noop!( + mock::Registrar::register( + RuntimeOrigin::signed(2), + para_id + 1, + test_genesis_head((max_head_size() + 1) as usize), + test_validation_code(max_code_size() as usize), + ), + Error::::HeadDataTooLarge + ); + + // Code Size Check + assert_noop!( + mock::Registrar::register( + RuntimeOrigin::signed(2), + para_id + 1, + test_genesis_head(max_head_size() as usize), + test_validation_code((max_code_size() + 1) as usize), + ), + Error::::CodeTooLarge + ); + + // Needs enough funds for deposit + assert_noop!( + mock::Registrar::reserve(RuntimeOrigin::signed(1337)), + BalancesError::::InsufficientBalance + ); + }); +} + +#[test] +fn deregister_works() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + let para_id = LOWEST_PUBLIC_ID; + assert!(!Parachains::is_parathread(para_id)); + + let validation_code = test_validation_code(32); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + assert!(Parachains::is_parathread(para_id)); + assert_ok!(mock::Registrar::deregister(RuntimeOrigin::root(), para_id,)); + run_to_session(START_SESSION_INDEX + 4); + assert!(paras::Pallet::::lifecycle(para_id).is_none()); + assert_eq!(Balances::reserved_balance(&1), 0); + }); +} + +#[test] +fn deregister_handles_basic_errors() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + let para_id = LOWEST_PUBLIC_ID; + assert!(!Parachains::is_parathread(para_id)); + + let validation_code = test_validation_code(32); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + assert!(Parachains::is_parathread(para_id)); + // Owner check + assert_noop!(mock::Registrar::deregister(RuntimeOrigin::signed(2), para_id,), BadOrigin); + assert_ok!(mock::Registrar::make_parachain(para_id)); + run_to_session(START_SESSION_INDEX + 4); + // Cant directly deregister parachain + assert_noop!( + mock::Registrar::deregister(RuntimeOrigin::root(), para_id,), + Error::::NotParathread + ); + }); +} + +#[test] +fn swap_works() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + // Successfully register first two parachains + let para_1 = LOWEST_PUBLIC_ID; + let para_2 = LOWEST_PUBLIC_ID + 1; + + let validation_code = test_validation_code(max_code_size() as usize); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_1, + test_genesis_head(max_head_size() as usize), + validation_code.clone(), + )); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(2))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(2), + para_2, + test_genesis_head(max_head_size() as usize), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + run_to_session(START_SESSION_INDEX + 2); + + // Upgrade para 1 into a parachain + assert_ok!(mock::Registrar::make_parachain(para_1)); + + // Set some mock swap data. + let mut swap_data = SwapData::get(); + swap_data.insert(para_1, 69); + swap_data.insert(para_2, 1337); + SwapData::set(swap_data); + + run_to_session(START_SESSION_INDEX + 4); + + // Roles are as we expect + assert!(Parachains::is_parachain(para_1)); + assert!(!Parachains::is_parathread(para_1)); + assert!(!Parachains::is_parachain(para_2)); + assert!(Parachains::is_parathread(para_2)); + + // Both paras initiate a swap + // Swap between parachain and parathread + assert_ok!(mock::Registrar::swap(para_origin(para_1), para_1, para_2,)); + assert_ok!(mock::Registrar::swap(para_origin(para_2), para_2, para_1,)); + System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped { + para_id: para_2, + other_id: para_1, + })); + + run_to_session(START_SESSION_INDEX + 6); + + // Roles are swapped + assert!(!Parachains::is_parachain(para_1)); + assert!(Parachains::is_parathread(para_1)); + assert!(Parachains::is_parachain(para_2)); + assert!(!Parachains::is_parathread(para_2)); + + // Data is swapped + assert_eq!(SwapData::get().get(¶_1).unwrap(), &1337); + assert_eq!(SwapData::get().get(¶_2).unwrap(), &69); + + // Both paras initiate a swap + // Swap between parathread and parachain + assert_ok!(mock::Registrar::swap(para_origin(para_1), para_1, para_2,)); + assert_ok!(mock::Registrar::swap(para_origin(para_2), para_2, para_1,)); + System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped { + para_id: para_2, + other_id: para_1, + })); + + // Data is swapped + assert_eq!(SwapData::get().get(¶_1).unwrap(), &69); + assert_eq!(SwapData::get().get(¶_2).unwrap(), &1337); + + // Parachain to parachain swap + let para_3 = LOWEST_PUBLIC_ID + 2; + let validation_code = test_validation_code(max_code_size() as usize); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(3))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(3), + para_3, + test_genesis_head(max_head_size() as usize), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX + 6); + + run_to_session(START_SESSION_INDEX + 8); + + // Upgrade para 3 into a parachain + assert_ok!(mock::Registrar::make_parachain(para_3)); + + // Set some mock swap data. + let mut swap_data = SwapData::get(); + swap_data.insert(para_3, 777); + SwapData::set(swap_data); + + run_to_session(START_SESSION_INDEX + 10); + + // Both are parachains + assert!(Parachains::is_parachain(para_3)); + assert!(!Parachains::is_parathread(para_3)); + assert!(Parachains::is_parachain(para_1)); + assert!(!Parachains::is_parathread(para_1)); + + // Both paras initiate a swap + // Swap between parachain and parachain + assert_ok!(mock::Registrar::swap(para_origin(para_1), para_1, para_3,)); + assert_ok!(mock::Registrar::swap(para_origin(para_3), para_3, para_1,)); + System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped { + para_id: para_3, + other_id: para_1, + })); + + // Data is swapped + assert_eq!(SwapData::get().get(¶_3).unwrap(), &69); + assert_eq!(SwapData::get().get(¶_1).unwrap(), &777); + }); +} + +#[test] +fn para_lock_works() { + new_test_ext().execute_with(|| { + run_to_block(1); + + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + let para_id = LOWEST_PUBLIC_ID; + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_id, + vec![1; 3].into(), + test_validation_code(32) + )); + + assert_noop!(mock::Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin); + + // Once they produces new block, we lock them in. + mock::Registrar::on_new_head(para_id, &Default::default()); + + // Owner cannot pass origin check when checking lock + assert_noop!( + mock::Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id), + Error::::ParaLocked, + ); + // Owner cannot remove lock. + assert_noop!(mock::Registrar::remove_lock(RuntimeOrigin::signed(1), para_id), BadOrigin); + // Para can. + assert_ok!(mock::Registrar::remove_lock(para_origin(para_id), para_id)); + // Owner can pass origin check again + assert_ok!(mock::Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id)); + + // Won't lock again after it is unlocked + mock::Registrar::on_new_head(para_id, &Default::default()); + + assert_ok!(mock::Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id)); + }); +} + +#[test] +fn swap_handles_bad_states() { + new_test_ext().execute_with(|| { + const START_SESSION_INDEX: SessionIndex = 1; + run_to_session(START_SESSION_INDEX); + + let para_1 = LOWEST_PUBLIC_ID; + let para_2 = LOWEST_PUBLIC_ID + 1; + + // paras are not yet registered + assert!(!Parachains::is_parathread(para_1)); + assert!(!Parachains::is_parathread(para_2)); + + // Cannot even start a swap + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2), + Error::::NotRegistered + ); + + // We register Paras 1 and 2 + let validation_code = test_validation_code(32); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(1))); + assert_ok!(mock::Registrar::reserve(RuntimeOrigin::signed(2))); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(1), + para_1, + test_genesis_head(32), + validation_code.clone(), + )); + assert_ok!(mock::Registrar::register( + RuntimeOrigin::signed(2), + para_2, + test_genesis_head(32), + validation_code.clone(), + )); + conclude_pvf_checking::(&validation_code, VALIDATORS, START_SESSION_INDEX); + + // Cannot swap + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(START_SESSION_INDEX + 2); + + // They are now parathreads (on-demand parachains). + assert!(Parachains::is_parathread(para_1)); + assert!(Parachains::is_parathread(para_2)); + + // Cannot swap + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1), + Error::::CannotSwap + ); + + // Some other external process will elevate one on-demand + // parachain to a lease holding parachain + assert_ok!(mock::Registrar::make_parachain(para_1)); + + // Cannot swap + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(START_SESSION_INDEX + 3); + + // Cannot swap + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(START_SESSION_INDEX + 4); + + // It is now a lease holding parachain. + assert!(Parachains::is_parachain(para_1)); + assert!(Parachains::is_parathread(para_2)); + + // Swap works here. + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1)); + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. }) + ))); + + run_to_session(START_SESSION_INDEX + 5); + + // Cannot swap + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(START_SESSION_INDEX + 6); + + // Swap worked! + assert!(Parachains::is_parachain(para_2)); + assert!(Parachains::is_parathread(para_1)); + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. }) + ))); + + // Something starts to downgrade a para + assert_ok!(mock::Registrar::make_parathread(para_2)); + + run_to_session(START_SESSION_INDEX + 7); + + // Cannot swap + assert_ok!(mock::Registrar::swap(RuntimeOrigin::root(), para_1, para_2)); + assert_noop!( + mock::Registrar::swap(RuntimeOrigin::root(), para_2, para_1), + Error::::CannotSwap + ); + + run_to_session(START_SESSION_INDEX + 8); + + assert!(Parachains::is_parathread(para_1)); + assert!(Parachains::is_parathread(para_2)); + }); +} diff --git a/polkadot/runtime/common/src/paras_sudo_wrapper.rs b/polkadot/runtime/common/src/paras_sudo_wrapper.rs index af93c70b4783..bd5984b3b63e 100644 --- a/polkadot/runtime/common/src/paras_sudo_wrapper.rs +++ b/polkadot/runtime/common/src/paras_sudo_wrapper.rs @@ -24,7 +24,7 @@ pub use pallet::*; use polkadot_primitives::Id as ParaId; use polkadot_runtime_parachains::{ configuration, dmp, hrmp, - paras::{self, AssignCoretime, ParaGenesisArgs}, + paras::{self, AssignCoretime, ParaGenesisArgs, ParaKind}, ParaLifecycle, }; @@ -48,6 +48,8 @@ pub mod pallet { /// A DMP message couldn't be sent because it exceeds the maximum size allowed for a /// downward message. ExceedsMaxMessageSize, + /// A DMP message couldn't be sent because the destination is unreachable. + Unroutable, /// Could not schedule para cleanup. CouldntCleanup, /// Not a parathread (on-demand parachain). @@ -80,10 +82,15 @@ pub mod pallet { genesis: ParaGenesisArgs, ) -> DispatchResult { ensure_root(origin)?; + + let assign_coretime = genesis.para_kind == ParaKind::Parachain; + polkadot_runtime_parachains::schedule_para_initialize::(id, genesis) .map_err(|_| Error::::ParaAlreadyExists)?; - T::AssignCoretime::assign_coretime(id)?; + if assign_coretime { + T::AssignCoretime::assign_coretime(id)?; + } Ok(()) } @@ -152,6 +159,7 @@ pub mod pallet { { dmp::QueueDownwardMessageError::ExceedsMaxMessageSize => Error::::ExceedsMaxMessageSize.into(), + dmp::QueueDownwardMessageError::Unroutable => Error::::Unroutable.into(), }) } diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs deleted file mode 100644 index cec92540654c..000000000000 --- a/polkadot/runtime/common/src/purchase.rs +++ /dev/null @@ -1,1178 +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 . - -//! Pallet to process purchase of DOTs. - -use alloc::vec::Vec; -use codec::{Decode, Encode}; -use frame_support::{ - pallet_prelude::*, - traits::{Currency, EnsureOrigin, ExistenceRequirement, Get, VestingSchedule}, -}; -use frame_system::pallet_prelude::*; -pub use pallet::*; -use scale_info::TypeInfo; -use sp_core::sr25519; -use sp_runtime::{ - traits::{CheckedAdd, Saturating, Verify, Zero}, - AnySignature, DispatchError, DispatchResult, Permill, RuntimeDebug, -}; - -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -/// The kind of statement an account needs to make for a claim to be valid. -#[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub enum AccountValidity { - /// Account is not valid. - Invalid, - /// Account has initiated the account creation process. - Initiated, - /// Account is pending validation. - Pending, - /// Account is valid with a low contribution amount. - ValidLow, - /// Account is valid with a high contribution amount. - ValidHigh, - /// Account has completed the purchase process. - Completed, -} - -impl Default for AccountValidity { - fn default() -> Self { - AccountValidity::Invalid - } -} - -impl AccountValidity { - fn is_valid(&self) -> bool { - match self { - Self::Invalid => false, - Self::Initiated => false, - Self::Pending => false, - Self::ValidLow => true, - Self::ValidHigh => true, - Self::Completed => false, - } - } -} - -/// All information about an account regarding the purchase of DOTs. -#[derive(Encode, Decode, Default, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct AccountStatus { - /// The current validity status of the user. Will denote if the user has passed KYC, - /// how much they are able to purchase, and when their purchase process has completed. - validity: AccountValidity, - /// The amount of free DOTs they have purchased. - free_balance: Balance, - /// The amount of locked DOTs they have purchased. - locked_balance: Balance, - /// Their sr25519/ed25519 signature verifying they have signed our required statement. - signature: Vec, - /// The percentage of VAT the purchaser is responsible for. This is already factored into - /// account balance. - vat: Permill, -} - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::pallet] - #[pallet::without_storage_info] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Balances Pallet - type Currency: Currency; - - /// Vesting Pallet - type VestingSchedule: VestingSchedule< - Self::AccountId, - Moment = BlockNumberFor, - Currency = Self::Currency, - >; - - /// The origin allowed to set account status. - type ValidityOrigin: EnsureOrigin; - - /// The origin allowed to make configurations to the pallet. - type ConfigurationOrigin: EnsureOrigin; - - /// The maximum statement length for the statement users to sign when creating an account. - #[pallet::constant] - type MaxStatementLength: Get; - - /// The amount of purchased locked DOTs that we will unlock for basic actions on the chain. - #[pallet::constant] - type UnlockedProportion: Get; - - /// The maximum amount of locked DOTs that we will unlock. - #[pallet::constant] - type MaxUnlocked: Get>; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// A new account was created. - AccountCreated { who: T::AccountId }, - /// Someone's account validity was updated. - ValidityUpdated { who: T::AccountId, validity: AccountValidity }, - /// Someone's purchase balance was updated. - BalanceUpdated { who: T::AccountId, free: BalanceOf, locked: BalanceOf }, - /// A payout was made to a purchaser. - PaymentComplete { who: T::AccountId, free: BalanceOf, locked: BalanceOf }, - /// A new payment account was set. - PaymentAccountSet { who: T::AccountId }, - /// A new statement was set. - StatementUpdated, - /// A new statement was set. `[block_number]` - UnlockBlockUpdated { block_number: BlockNumberFor }, - } - - #[pallet::error] - pub enum Error { - /// Account is not currently valid to use. - InvalidAccount, - /// Account used in the purchase already exists. - ExistingAccount, - /// Provided signature is invalid - InvalidSignature, - /// Account has already completed the purchase process. - AlreadyCompleted, - /// An overflow occurred when doing calculations. - Overflow, - /// The statement is too long to be stored on chain. - InvalidStatement, - /// The unlock block is in the past! - InvalidUnlockBlock, - /// Vesting schedule already exists for this account. - VestingScheduleExists, - } - - // A map of all participants in the DOT purchase process. - #[pallet::storage] - pub(super) type Accounts = - StorageMap<_, Blake2_128Concat, T::AccountId, AccountStatus>, ValueQuery>; - - // The account that will be used to payout participants of the DOT purchase process. - #[pallet::storage] - pub(super) type PaymentAccount = StorageValue<_, T::AccountId, OptionQuery>; - - // The statement purchasers will need to sign to participate. - #[pallet::storage] - pub(super) type Statement = StorageValue<_, Vec, ValueQuery>; - - // The block where all locked dots will unlock. - #[pallet::storage] - pub(super) type UnlockBlock = StorageValue<_, BlockNumberFor, ValueQuery>; - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet { - /// Create a new account. Proof of existence through a valid signed message. - /// - /// We check that the account does not exist at this stage. - /// - /// Origin must match the `ValidityOrigin`. - #[pallet::call_index(0)] - #[pallet::weight(Weight::from_parts(200_000_000, 0) + T::DbWeight::get().reads_writes(4, 1))] - pub fn create_account( - origin: OriginFor, - who: T::AccountId, - signature: Vec, - ) -> DispatchResult { - T::ValidityOrigin::ensure_origin(origin)?; - // Account is already being tracked by the pallet. - ensure!(!Accounts::::contains_key(&who), Error::::ExistingAccount); - // Account should not have a vesting schedule. - ensure!( - T::VestingSchedule::vesting_balance(&who).is_none(), - Error::::VestingScheduleExists - ); - - // Verify the signature provided is valid for the statement. - Self::verify_signature(&who, &signature)?; - - // Create a new pending account. - let status = AccountStatus { - validity: AccountValidity::Initiated, - signature, - free_balance: Zero::zero(), - locked_balance: Zero::zero(), - vat: Permill::zero(), - }; - Accounts::::insert(&who, status); - Self::deposit_event(Event::::AccountCreated { who }); - Ok(()) - } - - /// Update the validity status of an existing account. If set to completed, the account - /// will no longer be able to continue through the crowdfund process. - /// - /// We check that the account exists at this stage, but has not completed the process. - /// - /// Origin must match the `ValidityOrigin`. - #[pallet::call_index(1)] - #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] - pub fn update_validity_status( - origin: OriginFor, - who: T::AccountId, - validity: AccountValidity, - ) -> DispatchResult { - T::ValidityOrigin::ensure_origin(origin)?; - ensure!(Accounts::::contains_key(&who), Error::::InvalidAccount); - Accounts::::try_mutate( - &who, - |status: &mut AccountStatus>| -> DispatchResult { - ensure!( - status.validity != AccountValidity::Completed, - Error::::AlreadyCompleted - ); - status.validity = validity; - Ok(()) - }, - )?; - Self::deposit_event(Event::::ValidityUpdated { who, validity }); - Ok(()) - } - - /// Update the balance of a valid account. - /// - /// We check that the account is valid for a balance transfer at this point. - /// - /// Origin must match the `ValidityOrigin`. - #[pallet::call_index(2)] - #[pallet::weight(T::DbWeight::get().reads_writes(2, 1))] - pub fn update_balance( - origin: OriginFor, - who: T::AccountId, - free_balance: BalanceOf, - locked_balance: BalanceOf, - vat: Permill, - ) -> DispatchResult { - T::ValidityOrigin::ensure_origin(origin)?; - - Accounts::::try_mutate( - &who, - |status: &mut AccountStatus>| -> DispatchResult { - // Account has a valid status (not Invalid, Pending, or Completed)... - ensure!(status.validity.is_valid(), Error::::InvalidAccount); - - free_balance.checked_add(&locked_balance).ok_or(Error::::Overflow)?; - status.free_balance = free_balance; - status.locked_balance = locked_balance; - status.vat = vat; - Ok(()) - }, - )?; - Self::deposit_event(Event::::BalanceUpdated { - who, - free: free_balance, - locked: locked_balance, - }); - Ok(()) - } - - /// Pay the user and complete the purchase process. - /// - /// We reverify all assumptions about the state of an account, and complete the process. - /// - /// Origin must match the configured `PaymentAccount` (if it is not configured then this - /// will always fail with `BadOrigin`). - #[pallet::call_index(3)] - #[pallet::weight(T::DbWeight::get().reads_writes(4, 2))] - pub fn payout(origin: OriginFor, who: T::AccountId) -> DispatchResult { - // Payments must be made directly by the `PaymentAccount`. - let payment_account = ensure_signed(origin)?; - let test_against = PaymentAccount::::get().ok_or(DispatchError::BadOrigin)?; - ensure!(payment_account == test_against, DispatchError::BadOrigin); - - // Account should not have a vesting schedule. - ensure!( - T::VestingSchedule::vesting_balance(&who).is_none(), - Error::::VestingScheduleExists - ); - - Accounts::::try_mutate( - &who, - |status: &mut AccountStatus>| -> DispatchResult { - // Account has a valid status (not Invalid, Pending, or Completed)... - ensure!(status.validity.is_valid(), Error::::InvalidAccount); - - // Transfer funds from the payment account into the purchasing user. - let total_balance = status - .free_balance - .checked_add(&status.locked_balance) - .ok_or(Error::::Overflow)?; - T::Currency::transfer( - &payment_account, - &who, - total_balance, - ExistenceRequirement::AllowDeath, - )?; - - if !status.locked_balance.is_zero() { - let unlock_block = UnlockBlock::::get(); - // We allow some configurable portion of the purchased locked DOTs to be - // unlocked for basic usage. - let unlocked = (T::UnlockedProportion::get() * status.locked_balance) - .min(T::MaxUnlocked::get()); - let locked = status.locked_balance.saturating_sub(unlocked); - // We checked that this account has no existing vesting schedule. So this - // function should never fail, however if it does, not much we can do about - // it at this point. - let _ = T::VestingSchedule::add_vesting_schedule( - // Apply vesting schedule to this user - &who, - // For this much amount - locked, - // Unlocking the full amount after one block - locked, - // When everything unlocks - unlock_block, - ); - } - - // Setting the user account to `Completed` ends the purchase process for this - // user. - status.validity = AccountValidity::Completed; - Self::deposit_event(Event::::PaymentComplete { - who: who.clone(), - free: status.free_balance, - locked: status.locked_balance, - }); - Ok(()) - }, - )?; - Ok(()) - } - - /* Configuration Operations */ - - /// Set the account that will be used to payout users in the DOT purchase process. - /// - /// Origin must match the `ConfigurationOrigin` - #[pallet::call_index(4)] - #[pallet::weight(T::DbWeight::get().writes(1))] - pub fn set_payment_account(origin: OriginFor, who: T::AccountId) -> DispatchResult { - T::ConfigurationOrigin::ensure_origin(origin)?; - // Possibly this is worse than having the caller account be the payment account? - PaymentAccount::::put(who.clone()); - Self::deposit_event(Event::::PaymentAccountSet { who }); - Ok(()) - } - - /// Set the statement that must be signed for a user to participate on the DOT sale. - /// - /// Origin must match the `ConfigurationOrigin` - #[pallet::call_index(5)] - #[pallet::weight(T::DbWeight::get().writes(1))] - pub fn set_statement(origin: OriginFor, statement: Vec) -> DispatchResult { - T::ConfigurationOrigin::ensure_origin(origin)?; - ensure!( - (statement.len() as u32) < T::MaxStatementLength::get(), - Error::::InvalidStatement - ); - // Possibly this is worse than having the caller account be the payment account? - Statement::::set(statement); - Self::deposit_event(Event::::StatementUpdated); - Ok(()) - } - - /// Set the block where locked DOTs will become unlocked. - /// - /// Origin must match the `ConfigurationOrigin` - #[pallet::call_index(6)] - #[pallet::weight(T::DbWeight::get().writes(1))] - pub fn set_unlock_block( - origin: OriginFor, - unlock_block: BlockNumberFor, - ) -> DispatchResult { - T::ConfigurationOrigin::ensure_origin(origin)?; - ensure!( - unlock_block > frame_system::Pallet::::block_number(), - Error::::InvalidUnlockBlock - ); - // Possibly this is worse than having the caller account be the payment account? - UnlockBlock::::set(unlock_block); - Self::deposit_event(Event::::UnlockBlockUpdated { block_number: unlock_block }); - Ok(()) - } - } -} - -impl Pallet { - fn verify_signature(who: &T::AccountId, signature: &[u8]) -> Result<(), DispatchError> { - // sr25519 always expects a 64 byte signature. - let signature: AnySignature = sr25519::Signature::try_from(signature) - .map_err(|_| Error::::InvalidSignature)? - .into(); - - // In Polkadot, the AccountId is always the same as the 32 byte public key. - let account_bytes: [u8; 32] = account_to_bytes(who)?; - let public_key = sr25519::Public::from_raw(account_bytes); - - let message = Statement::::get(); - - // Check if everything is good or not. - match signature.verify(message.as_slice(), &public_key) { - true => Ok(()), - false => Err(Error::::InvalidSignature)?, - } - } -} - -// This function converts a 32 byte AccountId to its byte-array equivalent form. -fn account_to_bytes(account: &AccountId) -> Result<[u8; 32], DispatchError> -where - AccountId: Encode, -{ - let account_vec = account.encode(); - ensure!(account_vec.len() == 32, "AccountId must be 32 bytes."); - let mut bytes = [0u8; 32]; - bytes.copy_from_slice(&account_vec); - Ok(bytes) -} - -/// WARNING: Executing this function will clear all storage used by this pallet. -/// Be sure this is what you want... -pub fn remove_pallet() -> frame_support::weights::Weight -where - T: frame_system::Config, -{ - #[allow(deprecated)] - use frame_support::migration::remove_storage_prefix; - #[allow(deprecated)] - remove_storage_prefix(b"Purchase", b"Accounts", b""); - #[allow(deprecated)] - remove_storage_prefix(b"Purchase", b"PaymentAccount", b""); - #[allow(deprecated)] - remove_storage_prefix(b"Purchase", b"Statement", b""); - #[allow(deprecated)] - remove_storage_prefix(b"Purchase", b"UnlockBlock", b""); - - ::BlockWeights::get().max_block -} - -#[cfg(test)] -mod tests { - use super::*; - - use sp_core::{crypto::AccountId32, H256}; - use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; - // The testing primitives are very useful for avoiding having to work with signatures - // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. - use crate::purchase; - use frame_support::{ - assert_noop, assert_ok, derive_impl, ord_parameter_types, parameter_types, - traits::{Currency, WithdrawReasons}, - }; - use sp_runtime::{ - traits::{BlakeTwo256, Dispatchable, Identity, IdentityLookup}, - ArithmeticError, BuildStorage, - DispatchError::BadOrigin, - }; - - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - Vesting: pallet_vesting, - Purchase: purchase, - } - ); - - type AccountId = AccountId32; - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] - impl pallet_balances::Config for Test { - type AccountStore = System; - } - - parameter_types! { - pub const MinVestedTransfer: u64 = 1; - pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); - } - - impl pallet_vesting::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type BlockNumberToBalance = Identity; - type MinVestedTransfer = MinVestedTransfer; - type WeightInfo = (); - type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; - type BlockNumberProvider = System; - const MAX_VESTING_SCHEDULES: u32 = 28; - } - - parameter_types! { - pub const MaxStatementLength: u32 = 1_000; - pub const UnlockedProportion: Permill = Permill::from_percent(10); - pub const MaxUnlocked: u64 = 10; - } - - ord_parameter_types! { - pub const ValidityOrigin: AccountId = AccountId32::from([0u8; 32]); - pub const PaymentOrigin: AccountId = AccountId32::from([1u8; 32]); - pub const ConfigurationOrigin: AccountId = AccountId32::from([2u8; 32]); - } - - impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type VestingSchedule = Vesting; - type ValidityOrigin = frame_system::EnsureSignedBy; - type ConfigurationOrigin = frame_system::EnsureSignedBy; - type MaxStatementLength = MaxStatementLength; - type UnlockedProportion = UnlockedProportion; - type MaxUnlocked = MaxUnlocked; - } - - // This function basically just builds a genesis storage key/value store according to - // our desired mockup. It also executes our `setup` function which sets up this pallet for use. - pub fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| setup()); - ext - } - - fn setup() { - let statement = b"Hello, World".to_vec(); - let unlock_block = 100; - Purchase::set_statement(RuntimeOrigin::signed(configuration_origin()), statement).unwrap(); - Purchase::set_unlock_block(RuntimeOrigin::signed(configuration_origin()), unlock_block) - .unwrap(); - Purchase::set_payment_account( - RuntimeOrigin::signed(configuration_origin()), - payment_account(), - ) - .unwrap(); - Balances::make_free_balance_be(&payment_account(), 100_000); - } - - fn alice() -> AccountId { - Sr25519Keyring::Alice.to_account_id() - } - - fn alice_ed25519() -> AccountId { - Ed25519Keyring::Alice.to_account_id() - } - - fn bob() -> AccountId { - Sr25519Keyring::Bob.to_account_id() - } - - fn alice_signature() -> [u8; 64] { - // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold - // race lonely fit walk//Alice" - hex_literal::hex!("20e0faffdf4dfe939f2faa560f73b1d01cde8472e2b690b7b40606a374244c3a2e9eb9c8107c10b605138374003af8819bd4387d7c24a66ee9253c2e688ab881") - } - - fn bob_signature() -> [u8; 64] { - // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold - // race lonely fit walk//Bob" - hex_literal::hex!("d6d460187ecf530f3ec2d6e3ac91b9d083c8fbd8f1112d92a82e4d84df552d18d338e6da8944eba6e84afaacf8a9850f54e7b53a84530d649be2e0119c7ce889") - } - - fn alice_signature_ed25519() -> [u8; 64] { - // echo -n "Hello, World" | subkey -e sign "bottom drive obey lake curtain smoke basket hold - // race lonely fit walk//Alice" - hex_literal::hex!("ee3f5a6cbfc12a8f00c18b811dc921b550ddf272354cda4b9a57b1d06213fcd8509f5af18425d39a279d13622f14806c3e978e2163981f2ec1c06e9628460b0e") - } - - fn validity_origin() -> AccountId { - ValidityOrigin::get() - } - - fn configuration_origin() -> AccountId { - ConfigurationOrigin::get() - } - - fn payment_account() -> AccountId { - [42u8; 32].into() - } - - #[test] - fn set_statement_works_and_handles_basic_errors() { - new_test_ext().execute_with(|| { - let statement = b"Test Set Statement".to_vec(); - // Invalid origin - assert_noop!( - Purchase::set_statement(RuntimeOrigin::signed(alice()), statement.clone()), - BadOrigin, - ); - // Too Long - let long_statement = [0u8; 10_000].to_vec(); - assert_noop!( - Purchase::set_statement( - RuntimeOrigin::signed(configuration_origin()), - long_statement - ), - Error::::InvalidStatement, - ); - // Just right... - assert_ok!(Purchase::set_statement( - RuntimeOrigin::signed(configuration_origin()), - statement.clone() - )); - assert_eq!(Statement::::get(), statement); - }); - } - - #[test] - fn set_unlock_block_works_and_handles_basic_errors() { - new_test_ext().execute_with(|| { - let unlock_block = 69; - // Invalid origin - assert_noop!( - Purchase::set_unlock_block(RuntimeOrigin::signed(alice()), unlock_block), - BadOrigin, - ); - // Block Number in Past - let bad_unlock_block = 50; - System::set_block_number(bad_unlock_block); - assert_noop!( - Purchase::set_unlock_block( - RuntimeOrigin::signed(configuration_origin()), - bad_unlock_block - ), - Error::::InvalidUnlockBlock, - ); - // Just right... - assert_ok!(Purchase::set_unlock_block( - RuntimeOrigin::signed(configuration_origin()), - unlock_block - )); - assert_eq!(UnlockBlock::::get(), unlock_block); - }); - } - - #[test] - fn set_payment_account_works_and_handles_basic_errors() { - new_test_ext().execute_with(|| { - let payment_account: AccountId = [69u8; 32].into(); - // Invalid Origin - assert_noop!( - Purchase::set_payment_account( - RuntimeOrigin::signed(alice()), - payment_account.clone() - ), - BadOrigin, - ); - // Just right... - assert_ok!(Purchase::set_payment_account( - RuntimeOrigin::signed(configuration_origin()), - payment_account.clone() - )); - assert_eq!(PaymentAccount::::get(), Some(payment_account)); - }); - } - - #[test] - fn signature_verification_works() { - new_test_ext().execute_with(|| { - assert_ok!(Purchase::verify_signature(&alice(), &alice_signature())); - assert_ok!(Purchase::verify_signature(&alice_ed25519(), &alice_signature_ed25519())); - assert_ok!(Purchase::verify_signature(&bob(), &bob_signature())); - - // Mixing and matching fails - assert_noop!( - Purchase::verify_signature(&alice(), &bob_signature()), - Error::::InvalidSignature - ); - assert_noop!( - Purchase::verify_signature(&bob(), &alice_signature()), - Error::::InvalidSignature - ); - }); - } - - #[test] - fn account_creation_works() { - new_test_ext().execute_with(|| { - assert!(!Accounts::::contains_key(alice())); - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec(), - )); - assert_eq!( - Accounts::::get(alice()), - AccountStatus { - validity: AccountValidity::Initiated, - free_balance: Zero::zero(), - locked_balance: Zero::zero(), - signature: alice_signature().to_vec(), - vat: Permill::zero(), - } - ); - }); - } - - #[test] - fn account_creation_handles_basic_errors() { - new_test_ext().execute_with(|| { - // Wrong Origin - assert_noop!( - Purchase::create_account( - RuntimeOrigin::signed(alice()), - alice(), - alice_signature().to_vec() - ), - BadOrigin, - ); - - // Wrong Account/Signature - assert_noop!( - Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - bob_signature().to_vec() - ), - Error::::InvalidSignature, - ); - - // Account with vesting - Balances::make_free_balance_be(&alice(), 100); - assert_ok!(::VestingSchedule::add_vesting_schedule( - &alice(), - 100, - 1, - 50 - )); - assert_noop!( - Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec() - ), - Error::::VestingScheduleExists, - ); - - // Duplicate Purchasing Account - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - bob(), - bob_signature().to_vec() - )); - assert_noop!( - Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - bob(), - bob_signature().to_vec() - ), - Error::::ExistingAccount, - ); - }); - } - - #[test] - fn update_validity_status_works() { - new_test_ext().execute_with(|| { - // Alice account is created. - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec(), - )); - // She submits KYC, and we update the status to `Pending`. - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::Pending, - )); - // KYC comes back negative, so we mark the account invalid. - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::Invalid, - )); - assert_eq!( - Accounts::::get(alice()), - AccountStatus { - validity: AccountValidity::Invalid, - free_balance: Zero::zero(), - locked_balance: Zero::zero(), - signature: alice_signature().to_vec(), - vat: Permill::zero(), - } - ); - // She fixes it, we mark her account valid. - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::ValidLow, - )); - assert_eq!( - Accounts::::get(alice()), - AccountStatus { - validity: AccountValidity::ValidLow, - free_balance: Zero::zero(), - locked_balance: Zero::zero(), - signature: alice_signature().to_vec(), - vat: Permill::zero(), - } - ); - }); - } - - #[test] - fn update_validity_status_handles_basic_errors() { - new_test_ext().execute_with(|| { - // Wrong Origin - assert_noop!( - Purchase::update_validity_status( - RuntimeOrigin::signed(alice()), - alice(), - AccountValidity::Pending, - ), - BadOrigin - ); - // Inactive Account - assert_noop!( - Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::Pending, - ), - Error::::InvalidAccount - ); - // Already Completed - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec(), - )); - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::Completed, - )); - assert_noop!( - Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::Pending, - ), - Error::::AlreadyCompleted - ); - }); - } - - #[test] - fn update_balance_works() { - new_test_ext().execute_with(|| { - // Alice account is created - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec() - )); - // And approved for basic contribution - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::ValidLow, - )); - // We set a balance on the user based on the payment they made. 50 locked, 50 free. - assert_ok!(Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - alice(), - 50, - 50, - Permill::from_rational(77u32, 1000u32), - )); - assert_eq!( - Accounts::::get(alice()), - AccountStatus { - validity: AccountValidity::ValidLow, - free_balance: 50, - locked_balance: 50, - signature: alice_signature().to_vec(), - vat: Permill::from_parts(77000), - } - ); - // We can update the balance based on new information. - assert_ok!(Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - alice(), - 25, - 50, - Permill::zero(), - )); - assert_eq!( - Accounts::::get(alice()), - AccountStatus { - validity: AccountValidity::ValidLow, - free_balance: 25, - locked_balance: 50, - signature: alice_signature().to_vec(), - vat: Permill::zero(), - } - ); - }); - } - - #[test] - fn update_balance_handles_basic_errors() { - new_test_ext().execute_with(|| { - // Wrong Origin - assert_noop!( - Purchase::update_balance( - RuntimeOrigin::signed(alice()), - alice(), - 50, - 50, - Permill::zero(), - ), - BadOrigin - ); - // Inactive Account - assert_noop!( - Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - alice(), - 50, - 50, - Permill::zero(), - ), - Error::::InvalidAccount - ); - // Overflow - assert_noop!( - Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - alice(), - u64::MAX, - u64::MAX, - Permill::zero(), - ), - Error::::InvalidAccount - ); - }); - } - - #[test] - fn payout_works() { - new_test_ext().execute_with(|| { - // Alice and Bob accounts are created - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec() - )); - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - bob(), - bob_signature().to_vec() - )); - // Alice is approved for basic contribution - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::ValidLow, - )); - // Bob is approved for high contribution - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - bob(), - AccountValidity::ValidHigh, - )); - // We set a balance on the users based on the payment they made. 50 locked, 50 free. - assert_ok!(Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - alice(), - 50, - 50, - Permill::zero(), - )); - assert_ok!(Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - bob(), - 100, - 150, - Permill::zero(), - )); - // Now we call payout for Alice and Bob. - assert_ok!(Purchase::payout(RuntimeOrigin::signed(payment_account()), alice(),)); - assert_ok!(Purchase::payout(RuntimeOrigin::signed(payment_account()), bob(),)); - // Payment is made. - assert_eq!(::Currency::free_balance(&payment_account()), 99_650); - assert_eq!(::Currency::free_balance(&alice()), 100); - // 10% of the 50 units is unlocked automatically for Alice - assert_eq!(::VestingSchedule::vesting_balance(&alice()), Some(45)); - assert_eq!(::Currency::free_balance(&bob()), 250); - // A max of 10 units is unlocked automatically for Bob - assert_eq!(::VestingSchedule::vesting_balance(&bob()), Some(140)); - // Status is completed. - assert_eq!( - Accounts::::get(alice()), - AccountStatus { - validity: AccountValidity::Completed, - free_balance: 50, - locked_balance: 50, - signature: alice_signature().to_vec(), - vat: Permill::zero(), - } - ); - assert_eq!( - Accounts::::get(bob()), - AccountStatus { - validity: AccountValidity::Completed, - free_balance: 100, - locked_balance: 150, - signature: bob_signature().to_vec(), - vat: Permill::zero(), - } - ); - // Vesting lock is removed in whole on block 101 (100 blocks after block 1) - System::set_block_number(100); - let vest_call = RuntimeCall::Vesting(pallet_vesting::Call::::vest {}); - assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(alice()))); - assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(bob()))); - assert_eq!(::VestingSchedule::vesting_balance(&alice()), Some(45)); - assert_eq!(::VestingSchedule::vesting_balance(&bob()), Some(140)); - System::set_block_number(101); - assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(alice()))); - assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(bob()))); - assert_eq!(::VestingSchedule::vesting_balance(&alice()), None); - assert_eq!(::VestingSchedule::vesting_balance(&bob()), None); - }); - } - - #[test] - fn payout_handles_basic_errors() { - new_test_ext().execute_with(|| { - // Wrong Origin - assert_noop!(Purchase::payout(RuntimeOrigin::signed(alice()), alice(),), BadOrigin); - // Account with Existing Vesting Schedule - Balances::make_free_balance_be(&bob(), 100); - assert_ok!( - ::VestingSchedule::add_vesting_schedule(&bob(), 100, 1, 50,) - ); - assert_noop!( - Purchase::payout(RuntimeOrigin::signed(payment_account()), bob(),), - Error::::VestingScheduleExists - ); - // Invalid Account (never created) - assert_noop!( - Purchase::payout(RuntimeOrigin::signed(payment_account()), alice(),), - Error::::InvalidAccount - ); - // Invalid Account (created, but not valid) - assert_ok!(Purchase::create_account( - RuntimeOrigin::signed(validity_origin()), - alice(), - alice_signature().to_vec() - )); - assert_noop!( - Purchase::payout(RuntimeOrigin::signed(payment_account()), alice(),), - Error::::InvalidAccount - ); - // Not enough funds in payment account - assert_ok!(Purchase::update_validity_status( - RuntimeOrigin::signed(validity_origin()), - alice(), - AccountValidity::ValidHigh, - )); - assert_ok!(Purchase::update_balance( - RuntimeOrigin::signed(validity_origin()), - alice(), - 100_000, - 100_000, - Permill::zero(), - )); - assert_noop!( - Purchase::payout(RuntimeOrigin::signed(payment_account()), alice()), - ArithmeticError::Underflow - ); - }); - } - - #[test] - fn remove_pallet_works() { - new_test_ext().execute_with(|| { - let account_status = AccountStatus { - validity: AccountValidity::Completed, - free_balance: 1234, - locked_balance: 4321, - signature: b"my signature".to_vec(), - vat: Permill::from_percent(50), - }; - - // Add some storage. - Accounts::::insert(alice(), account_status.clone()); - Accounts::::insert(bob(), account_status); - PaymentAccount::::put(alice()); - Statement::::put(b"hello, world!".to_vec()); - UnlockBlock::::put(4); - - // Verify storage exists. - assert_eq!(Accounts::::iter().count(), 2); - assert!(PaymentAccount::::exists()); - assert!(Statement::::exists()); - assert!(UnlockBlock::::exists()); - - // Remove storage. - remove_pallet::(); - - // Verify storage is gone. - assert_eq!(Accounts::::iter().count(), 0); - assert!(!PaymentAccount::::exists()); - assert!(!Statement::::exists()); - assert!(!UnlockBlock::::exists()); - }); - } -} diff --git a/polkadot/runtime/common/src/purchase/mock.rs b/polkadot/runtime/common/src/purchase/mock.rs new file mode 100644 index 000000000000..ec8599f3b792 --- /dev/null +++ b/polkadot/runtime/common/src/purchase/mock.rs @@ -0,0 +1,181 @@ +// 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 . + +//! Mocking utilities for testing in purchase pallet. + +#[cfg(test)] +use super::*; + +use sp_core::{crypto::AccountId32, H256}; +use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; +// The testing primitives are very useful for avoiding having to work with signatures +// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. +use crate::purchase; +use frame_support::{ + derive_impl, ord_parameter_types, parameter_types, + traits::{Currency, WithdrawReasons}, +}; +use sp_runtime::{ + traits::{BlakeTwo256, Identity, IdentityLookup}, + BuildStorage, +}; + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Vesting: pallet_vesting, + Purchase: purchase, + } +); + +type AccountId = AccountId32; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type AccountStore = System; +} + +parameter_types! { + pub const MinVestedTransfer: u64 = 1; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); +} + +impl pallet_vesting::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type BlockNumberToBalance = Identity; + type MinVestedTransfer = MinVestedTransfer; + type WeightInfo = (); + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; + const MAX_VESTING_SCHEDULES: u32 = 28; +} + +parameter_types! { + pub const MaxStatementLength: u32 = 1_000; + pub const UnlockedProportion: Permill = Permill::from_percent(10); + pub const MaxUnlocked: u64 = 10; +} + +ord_parameter_types! { + pub const ValidityOrigin: AccountId = AccountId32::from([0u8; 32]); + pub const PaymentOrigin: AccountId = AccountId32::from([1u8; 32]); + pub const ConfigurationOrigin: AccountId = AccountId32::from([2u8; 32]); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VestingSchedule = Vesting; + type ValidityOrigin = frame_system::EnsureSignedBy; + type ConfigurationOrigin = frame_system::EnsureSignedBy; + type MaxStatementLength = MaxStatementLength; + type UnlockedProportion = UnlockedProportion; + type MaxUnlocked = MaxUnlocked; +} + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. It also executes our `setup` function which sets up this pallet for use. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| setup()); + ext +} + +pub fn setup() { + let statement = b"Hello, World".to_vec(); + let unlock_block = 100; + Purchase::set_statement(RuntimeOrigin::signed(configuration_origin()), statement).unwrap(); + Purchase::set_unlock_block(RuntimeOrigin::signed(configuration_origin()), unlock_block) + .unwrap(); + Purchase::set_payment_account(RuntimeOrigin::signed(configuration_origin()), payment_account()) + .unwrap(); + Balances::make_free_balance_be(&payment_account(), 100_000); +} + +pub fn alice() -> AccountId { + Sr25519Keyring::Alice.to_account_id() +} + +pub fn alice_ed25519() -> AccountId { + Ed25519Keyring::Alice.to_account_id() +} + +pub fn bob() -> AccountId { + Sr25519Keyring::Bob.to_account_id() +} + +pub fn alice_signature() -> [u8; 64] { + // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold + // race lonely fit walk//Alice" + hex_literal::hex!("20e0faffdf4dfe939f2faa560f73b1d01cde8472e2b690b7b40606a374244c3a2e9eb9c8107c10b605138374003af8819bd4387d7c24a66ee9253c2e688ab881") +} + +pub fn bob_signature() -> [u8; 64] { + // echo -n "Hello, World" | subkey -s sign "bottom drive obey lake curtain smoke basket hold + // race lonely fit walk//Bob" + hex_literal::hex!("d6d460187ecf530f3ec2d6e3ac91b9d083c8fbd8f1112d92a82e4d84df552d18d338e6da8944eba6e84afaacf8a9850f54e7b53a84530d649be2e0119c7ce889") +} + +pub fn alice_signature_ed25519() -> [u8; 64] { + // echo -n "Hello, World" | subkey -e sign "bottom drive obey lake curtain smoke basket hold + // race lonely fit walk//Alice" + hex_literal::hex!("ee3f5a6cbfc12a8f00c18b811dc921b550ddf272354cda4b9a57b1d06213fcd8509f5af18425d39a279d13622f14806c3e978e2163981f2ec1c06e9628460b0e") +} + +pub fn validity_origin() -> AccountId { + ValidityOrigin::get() +} + +pub fn configuration_origin() -> AccountId { + ConfigurationOrigin::get() +} + +pub fn payment_account() -> AccountId { + [42u8; 32].into() +} diff --git a/polkadot/runtime/common/src/purchase/mod.rs b/polkadot/runtime/common/src/purchase/mod.rs new file mode 100644 index 000000000000..71dc5b579670 --- /dev/null +++ b/polkadot/runtime/common/src/purchase/mod.rs @@ -0,0 +1,482 @@ +// 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 . + +//! Pallet to process purchase of DOTs. + +use alloc::vec::Vec; +use codec::{Decode, Encode}; +use frame_support::{ + pallet_prelude::*, + traits::{Currency, EnsureOrigin, ExistenceRequirement, Get, VestingSchedule}, +}; +use frame_system::pallet_prelude::*; +pub use pallet::*; +use scale_info::TypeInfo; +use sp_core::sr25519; +use sp_runtime::{ + traits::{CheckedAdd, Saturating, Verify, Zero}, + AnySignature, DispatchError, DispatchResult, Permill, RuntimeDebug, +}; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +/// The kind of statement an account needs to make for a claim to be valid. +#[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub enum AccountValidity { + /// Account is not valid. + Invalid, + /// Account has initiated the account creation process. + Initiated, + /// Account is pending validation. + Pending, + /// Account is valid with a low contribution amount. + ValidLow, + /// Account is valid with a high contribution amount. + ValidHigh, + /// Account has completed the purchase process. + Completed, +} + +impl Default for AccountValidity { + fn default() -> Self { + AccountValidity::Invalid + } +} + +impl AccountValidity { + fn is_valid(&self) -> bool { + match self { + Self::Invalid => false, + Self::Initiated => false, + Self::Pending => false, + Self::ValidLow => true, + Self::ValidHigh => true, + Self::Completed => false, + } + } +} + +/// All information about an account regarding the purchase of DOTs. +#[derive(Encode, Decode, Default, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct AccountStatus { + /// The current validity status of the user. Will denote if the user has passed KYC, + /// how much they are able to purchase, and when their purchase process has completed. + validity: AccountValidity, + /// The amount of free DOTs they have purchased. + free_balance: Balance, + /// The amount of locked DOTs they have purchased. + locked_balance: Balance, + /// Their sr25519/ed25519 signature verifying they have signed our required statement. + signature: Vec, + /// The percentage of VAT the purchaser is responsible for. This is already factored into + /// account balance. + vat: Permill, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Balances Pallet + type Currency: Currency; + + /// Vesting Pallet + type VestingSchedule: VestingSchedule< + Self::AccountId, + Moment = BlockNumberFor, + Currency = Self::Currency, + >; + + /// The origin allowed to set account status. + type ValidityOrigin: EnsureOrigin; + + /// The origin allowed to make configurations to the pallet. + type ConfigurationOrigin: EnsureOrigin; + + /// The maximum statement length for the statement users to sign when creating an account. + #[pallet::constant] + type MaxStatementLength: Get; + + /// The amount of purchased locked DOTs that we will unlock for basic actions on the chain. + #[pallet::constant] + type UnlockedProportion: Get; + + /// The maximum amount of locked DOTs that we will unlock. + #[pallet::constant] + type MaxUnlocked: Get>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A new account was created. + AccountCreated { who: T::AccountId }, + /// Someone's account validity was updated. + ValidityUpdated { who: T::AccountId, validity: AccountValidity }, + /// Someone's purchase balance was updated. + BalanceUpdated { who: T::AccountId, free: BalanceOf, locked: BalanceOf }, + /// A payout was made to a purchaser. + PaymentComplete { who: T::AccountId, free: BalanceOf, locked: BalanceOf }, + /// A new payment account was set. + PaymentAccountSet { who: T::AccountId }, + /// A new statement was set. + StatementUpdated, + /// A new statement was set. `[block_number]` + UnlockBlockUpdated { block_number: BlockNumberFor }, + } + + #[pallet::error] + pub enum Error { + /// Account is not currently valid to use. + InvalidAccount, + /// Account used in the purchase already exists. + ExistingAccount, + /// Provided signature is invalid + InvalidSignature, + /// Account has already completed the purchase process. + AlreadyCompleted, + /// An overflow occurred when doing calculations. + Overflow, + /// The statement is too long to be stored on chain. + InvalidStatement, + /// The unlock block is in the past! + InvalidUnlockBlock, + /// Vesting schedule already exists for this account. + VestingScheduleExists, + } + + // A map of all participants in the DOT purchase process. + #[pallet::storage] + pub(super) type Accounts = + StorageMap<_, Blake2_128Concat, T::AccountId, AccountStatus>, ValueQuery>; + + // The account that will be used to payout participants of the DOT purchase process. + #[pallet::storage] + pub(super) type PaymentAccount = StorageValue<_, T::AccountId, OptionQuery>; + + // The statement purchasers will need to sign to participate. + #[pallet::storage] + pub(super) type Statement = StorageValue<_, Vec, ValueQuery>; + + // The block where all locked dots will unlock. + #[pallet::storage] + pub(super) type UnlockBlock = StorageValue<_, BlockNumberFor, ValueQuery>; + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet { + /// Create a new account. Proof of existence through a valid signed message. + /// + /// We check that the account does not exist at this stage. + /// + /// Origin must match the `ValidityOrigin`. + #[pallet::call_index(0)] + #[pallet::weight(Weight::from_parts(200_000_000, 0) + T::DbWeight::get().reads_writes(4, 1))] + pub fn create_account( + origin: OriginFor, + who: T::AccountId, + signature: Vec, + ) -> DispatchResult { + T::ValidityOrigin::ensure_origin(origin)?; + // Account is already being tracked by the pallet. + ensure!(!Accounts::::contains_key(&who), Error::::ExistingAccount); + // Account should not have a vesting schedule. + ensure!( + T::VestingSchedule::vesting_balance(&who).is_none(), + Error::::VestingScheduleExists + ); + + // Verify the signature provided is valid for the statement. + Self::verify_signature(&who, &signature)?; + + // Create a new pending account. + let status = AccountStatus { + validity: AccountValidity::Initiated, + signature, + free_balance: Zero::zero(), + locked_balance: Zero::zero(), + vat: Permill::zero(), + }; + Accounts::::insert(&who, status); + Self::deposit_event(Event::::AccountCreated { who }); + Ok(()) + } + + /// Update the validity status of an existing account. If set to completed, the account + /// will no longer be able to continue through the crowdfund process. + /// + /// We check that the account exists at this stage, but has not completed the process. + /// + /// Origin must match the `ValidityOrigin`. + #[pallet::call_index(1)] + #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] + pub fn update_validity_status( + origin: OriginFor, + who: T::AccountId, + validity: AccountValidity, + ) -> DispatchResult { + T::ValidityOrigin::ensure_origin(origin)?; + ensure!(Accounts::::contains_key(&who), Error::::InvalidAccount); + Accounts::::try_mutate( + &who, + |status: &mut AccountStatus>| -> DispatchResult { + ensure!( + status.validity != AccountValidity::Completed, + Error::::AlreadyCompleted + ); + status.validity = validity; + Ok(()) + }, + )?; + Self::deposit_event(Event::::ValidityUpdated { who, validity }); + Ok(()) + } + + /// Update the balance of a valid account. + /// + /// We check that the account is valid for a balance transfer at this point. + /// + /// Origin must match the `ValidityOrigin`. + #[pallet::call_index(2)] + #[pallet::weight(T::DbWeight::get().reads_writes(2, 1))] + pub fn update_balance( + origin: OriginFor, + who: T::AccountId, + free_balance: BalanceOf, + locked_balance: BalanceOf, + vat: Permill, + ) -> DispatchResult { + T::ValidityOrigin::ensure_origin(origin)?; + + Accounts::::try_mutate( + &who, + |status: &mut AccountStatus>| -> DispatchResult { + // Account has a valid status (not Invalid, Pending, or Completed)... + ensure!(status.validity.is_valid(), Error::::InvalidAccount); + + free_balance.checked_add(&locked_balance).ok_or(Error::::Overflow)?; + status.free_balance = free_balance; + status.locked_balance = locked_balance; + status.vat = vat; + Ok(()) + }, + )?; + Self::deposit_event(Event::::BalanceUpdated { + who, + free: free_balance, + locked: locked_balance, + }); + Ok(()) + } + + /// Pay the user and complete the purchase process. + /// + /// We reverify all assumptions about the state of an account, and complete the process. + /// + /// Origin must match the configured `PaymentAccount` (if it is not configured then this + /// will always fail with `BadOrigin`). + #[pallet::call_index(3)] + #[pallet::weight(T::DbWeight::get().reads_writes(4, 2))] + pub fn payout(origin: OriginFor, who: T::AccountId) -> DispatchResult { + // Payments must be made directly by the `PaymentAccount`. + let payment_account = ensure_signed(origin)?; + let test_against = PaymentAccount::::get().ok_or(DispatchError::BadOrigin)?; + ensure!(payment_account == test_against, DispatchError::BadOrigin); + + // Account should not have a vesting schedule. + ensure!( + T::VestingSchedule::vesting_balance(&who).is_none(), + Error::::VestingScheduleExists + ); + + Accounts::::try_mutate( + &who, + |status: &mut AccountStatus>| -> DispatchResult { + // Account has a valid status (not Invalid, Pending, or Completed)... + ensure!(status.validity.is_valid(), Error::::InvalidAccount); + + // Transfer funds from the payment account into the purchasing user. + let total_balance = status + .free_balance + .checked_add(&status.locked_balance) + .ok_or(Error::::Overflow)?; + T::Currency::transfer( + &payment_account, + &who, + total_balance, + ExistenceRequirement::AllowDeath, + )?; + + if !status.locked_balance.is_zero() { + let unlock_block = UnlockBlock::::get(); + // We allow some configurable portion of the purchased locked DOTs to be + // unlocked for basic usage. + let unlocked = (T::UnlockedProportion::get() * status.locked_balance) + .min(T::MaxUnlocked::get()); + let locked = status.locked_balance.saturating_sub(unlocked); + // We checked that this account has no existing vesting schedule. So this + // function should never fail, however if it does, not much we can do about + // it at this point. + let _ = T::VestingSchedule::add_vesting_schedule( + // Apply vesting schedule to this user + &who, + // For this much amount + locked, + // Unlocking the full amount after one block + locked, + // When everything unlocks + unlock_block, + ); + } + + // Setting the user account to `Completed` ends the purchase process for this + // user. + status.validity = AccountValidity::Completed; + Self::deposit_event(Event::::PaymentComplete { + who: who.clone(), + free: status.free_balance, + locked: status.locked_balance, + }); + Ok(()) + }, + )?; + Ok(()) + } + + /* Configuration Operations */ + + /// Set the account that will be used to payout users in the DOT purchase process. + /// + /// Origin must match the `ConfigurationOrigin` + #[pallet::call_index(4)] + #[pallet::weight(T::DbWeight::get().writes(1))] + pub fn set_payment_account(origin: OriginFor, who: T::AccountId) -> DispatchResult { + T::ConfigurationOrigin::ensure_origin(origin)?; + // Possibly this is worse than having the caller account be the payment account? + PaymentAccount::::put(who.clone()); + Self::deposit_event(Event::::PaymentAccountSet { who }); + Ok(()) + } + + /// Set the statement that must be signed for a user to participate on the DOT sale. + /// + /// Origin must match the `ConfigurationOrigin` + #[pallet::call_index(5)] + #[pallet::weight(T::DbWeight::get().writes(1))] + pub fn set_statement(origin: OriginFor, statement: Vec) -> DispatchResult { + T::ConfigurationOrigin::ensure_origin(origin)?; + ensure!( + (statement.len() as u32) < T::MaxStatementLength::get(), + Error::::InvalidStatement + ); + // Possibly this is worse than having the caller account be the payment account? + Statement::::set(statement); + Self::deposit_event(Event::::StatementUpdated); + Ok(()) + } + + /// Set the block where locked DOTs will become unlocked. + /// + /// Origin must match the `ConfigurationOrigin` + #[pallet::call_index(6)] + #[pallet::weight(T::DbWeight::get().writes(1))] + pub fn set_unlock_block( + origin: OriginFor, + unlock_block: BlockNumberFor, + ) -> DispatchResult { + T::ConfigurationOrigin::ensure_origin(origin)?; + ensure!( + unlock_block > frame_system::Pallet::::block_number(), + Error::::InvalidUnlockBlock + ); + // Possibly this is worse than having the caller account be the payment account? + UnlockBlock::::set(unlock_block); + Self::deposit_event(Event::::UnlockBlockUpdated { block_number: unlock_block }); + Ok(()) + } + } +} + +impl Pallet { + fn verify_signature(who: &T::AccountId, signature: &[u8]) -> Result<(), DispatchError> { + // sr25519 always expects a 64 byte signature. + let signature: AnySignature = sr25519::Signature::try_from(signature) + .map_err(|_| Error::::InvalidSignature)? + .into(); + + // In Polkadot, the AccountId is always the same as the 32 byte public key. + let account_bytes: [u8; 32] = account_to_bytes(who)?; + let public_key = sr25519::Public::from_raw(account_bytes); + + let message = Statement::::get(); + + // Check if everything is good or not. + match signature.verify(message.as_slice(), &public_key) { + true => Ok(()), + false => Err(Error::::InvalidSignature)?, + } + } +} + +// This function converts a 32 byte AccountId to its byte-array equivalent form. +fn account_to_bytes(account: &AccountId) -> Result<[u8; 32], DispatchError> +where + AccountId: Encode, +{ + let account_vec = account.encode(); + ensure!(account_vec.len() == 32, "AccountId must be 32 bytes."); + let mut bytes = [0u8; 32]; + bytes.copy_from_slice(&account_vec); + Ok(bytes) +} + +/// WARNING: Executing this function will clear all storage used by this pallet. +/// Be sure this is what you want... +pub fn remove_pallet() -> frame_support::weights::Weight +where + T: frame_system::Config, +{ + #[allow(deprecated)] + use frame_support::migration::remove_storage_prefix; + #[allow(deprecated)] + remove_storage_prefix(b"Purchase", b"Accounts", b""); + #[allow(deprecated)] + remove_storage_prefix(b"Purchase", b"PaymentAccount", b""); + #[allow(deprecated)] + remove_storage_prefix(b"Purchase", b"Statement", b""); + #[allow(deprecated)] + remove_storage_prefix(b"Purchase", b"UnlockBlock", b""); + + ::BlockWeights::get().max_block +} + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; diff --git a/polkadot/runtime/common/src/purchase/tests.rs b/polkadot/runtime/common/src/purchase/tests.rs new file mode 100644 index 000000000000..8cf2a124d245 --- /dev/null +++ b/polkadot/runtime/common/src/purchase/tests.rs @@ -0,0 +1,547 @@ +// 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 . + +//! Tests for the purchase pallet. + +#[cfg(test)] +use super::*; + +use sp_core::crypto::AccountId32; +// The testing primitives are very useful for avoiding having to work with signatures +// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. +use frame_support::{assert_noop, assert_ok, traits::Currency}; +use sp_runtime::{traits::Dispatchable, ArithmeticError, DispatchError::BadOrigin}; + +use crate::purchase::mock::*; + +#[test] +fn set_statement_works_and_handles_basic_errors() { + new_test_ext().execute_with(|| { + let statement = b"Test Set Statement".to_vec(); + // Invalid origin + assert_noop!( + Purchase::set_statement(RuntimeOrigin::signed(alice()), statement.clone()), + BadOrigin, + ); + // Too Long + let long_statement = [0u8; 10_000].to_vec(); + assert_noop!( + Purchase::set_statement(RuntimeOrigin::signed(configuration_origin()), long_statement), + Error::::InvalidStatement, + ); + // Just right... + assert_ok!(Purchase::set_statement( + RuntimeOrigin::signed(configuration_origin()), + statement.clone() + )); + assert_eq!(Statement::::get(), statement); + }); +} + +#[test] +fn set_unlock_block_works_and_handles_basic_errors() { + new_test_ext().execute_with(|| { + let unlock_block = 69; + // Invalid origin + assert_noop!( + Purchase::set_unlock_block(RuntimeOrigin::signed(alice()), unlock_block), + BadOrigin, + ); + // Block Number in Past + let bad_unlock_block = 50; + System::set_block_number(bad_unlock_block); + assert_noop!( + Purchase::set_unlock_block( + RuntimeOrigin::signed(configuration_origin()), + bad_unlock_block + ), + Error::::InvalidUnlockBlock, + ); + // Just right... + assert_ok!(Purchase::set_unlock_block( + RuntimeOrigin::signed(configuration_origin()), + unlock_block + )); + assert_eq!(UnlockBlock::::get(), unlock_block); + }); +} + +#[test] +fn set_payment_account_works_and_handles_basic_errors() { + new_test_ext().execute_with(|| { + let payment_account: AccountId32 = [69u8; 32].into(); + // Invalid Origin + assert_noop!( + Purchase::set_payment_account(RuntimeOrigin::signed(alice()), payment_account.clone()), + BadOrigin, + ); + // Just right... + assert_ok!(Purchase::set_payment_account( + RuntimeOrigin::signed(configuration_origin()), + payment_account.clone() + )); + assert_eq!(PaymentAccount::::get(), Some(payment_account)); + }); +} + +#[test] +fn signature_verification_works() { + new_test_ext().execute_with(|| { + assert_ok!(Purchase::verify_signature(&alice(), &alice_signature())); + assert_ok!(Purchase::verify_signature(&alice_ed25519(), &alice_signature_ed25519())); + assert_ok!(Purchase::verify_signature(&bob(), &bob_signature())); + + // Mixing and matching fails + assert_noop!( + Purchase::verify_signature(&alice(), &bob_signature()), + Error::::InvalidSignature + ); + assert_noop!( + Purchase::verify_signature(&bob(), &alice_signature()), + Error::::InvalidSignature + ); + }); +} + +#[test] +fn account_creation_works() { + new_test_ext().execute_with(|| { + assert!(!Accounts::::contains_key(alice())); + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec(), + )); + assert_eq!( + Accounts::::get(alice()), + AccountStatus { + validity: AccountValidity::Initiated, + free_balance: Zero::zero(), + locked_balance: Zero::zero(), + signature: alice_signature().to_vec(), + vat: Permill::zero(), + } + ); + }); +} + +#[test] +fn account_creation_handles_basic_errors() { + new_test_ext().execute_with(|| { + // Wrong Origin + assert_noop!( + Purchase::create_account( + RuntimeOrigin::signed(alice()), + alice(), + alice_signature().to_vec() + ), + BadOrigin, + ); + + // Wrong Account/Signature + assert_noop!( + Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + bob_signature().to_vec() + ), + Error::::InvalidSignature, + ); + + // Account with vesting + Balances::make_free_balance_be(&alice(), 100); + assert_ok!(::VestingSchedule::add_vesting_schedule(&alice(), 100, 1, 50)); + assert_noop!( + Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec() + ), + Error::::VestingScheduleExists, + ); + + // Duplicate Purchasing Account + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + bob(), + bob_signature().to_vec() + )); + assert_noop!( + Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + bob(), + bob_signature().to_vec() + ), + Error::::ExistingAccount, + ); + }); +} + +#[test] +fn update_validity_status_works() { + new_test_ext().execute_with(|| { + // Alice account is created. + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec(), + )); + // She submits KYC, and we update the status to `Pending`. + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::Pending, + )); + // KYC comes back negative, so we mark the account invalid. + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::Invalid, + )); + assert_eq!( + Accounts::::get(alice()), + AccountStatus { + validity: AccountValidity::Invalid, + free_balance: Zero::zero(), + locked_balance: Zero::zero(), + signature: alice_signature().to_vec(), + vat: Permill::zero(), + } + ); + // She fixes it, we mark her account valid. + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::ValidLow, + )); + assert_eq!( + Accounts::::get(alice()), + AccountStatus { + validity: AccountValidity::ValidLow, + free_balance: Zero::zero(), + locked_balance: Zero::zero(), + signature: alice_signature().to_vec(), + vat: Permill::zero(), + } + ); + }); +} + +#[test] +fn update_validity_status_handles_basic_errors() { + new_test_ext().execute_with(|| { + // Wrong Origin + assert_noop!( + Purchase::update_validity_status( + RuntimeOrigin::signed(alice()), + alice(), + AccountValidity::Pending, + ), + BadOrigin + ); + // Inactive Account + assert_noop!( + Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::Pending, + ), + Error::::InvalidAccount + ); + // Already Completed + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec(), + )); + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::Completed, + )); + assert_noop!( + Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::Pending, + ), + Error::::AlreadyCompleted + ); + }); +} + +#[test] +fn update_balance_works() { + new_test_ext().execute_with(|| { + // Alice account is created + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec() + )); + // And approved for basic contribution + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::ValidLow, + )); + // We set a balance on the user based on the payment they made. 50 locked, 50 free. + assert_ok!(Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + alice(), + 50, + 50, + Permill::from_rational(77u32, 1000u32), + )); + assert_eq!( + Accounts::::get(alice()), + AccountStatus { + validity: AccountValidity::ValidLow, + free_balance: 50, + locked_balance: 50, + signature: alice_signature().to_vec(), + vat: Permill::from_parts(77000), + } + ); + // We can update the balance based on new information. + assert_ok!(Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + alice(), + 25, + 50, + Permill::zero(), + )); + assert_eq!( + Accounts::::get(alice()), + AccountStatus { + validity: AccountValidity::ValidLow, + free_balance: 25, + locked_balance: 50, + signature: alice_signature().to_vec(), + vat: Permill::zero(), + } + ); + }); +} + +#[test] +fn update_balance_handles_basic_errors() { + new_test_ext().execute_with(|| { + // Wrong Origin + assert_noop!( + Purchase::update_balance( + RuntimeOrigin::signed(alice()), + alice(), + 50, + 50, + Permill::zero(), + ), + BadOrigin + ); + // Inactive Account + assert_noop!( + Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + alice(), + 50, + 50, + Permill::zero(), + ), + Error::::InvalidAccount + ); + // Overflow + assert_noop!( + Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + alice(), + u64::MAX, + u64::MAX, + Permill::zero(), + ), + Error::::InvalidAccount + ); + }); +} + +#[test] +fn payout_works() { + new_test_ext().execute_with(|| { + // Alice and Bob accounts are created + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec() + )); + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + bob(), + bob_signature().to_vec() + )); + // Alice is approved for basic contribution + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::ValidLow, + )); + // Bob is approved for high contribution + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + bob(), + AccountValidity::ValidHigh, + )); + // We set a balance on the users based on the payment they made. 50 locked, 50 free. + assert_ok!(Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + alice(), + 50, + 50, + Permill::zero(), + )); + assert_ok!(Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + bob(), + 100, + 150, + Permill::zero(), + )); + // Now we call payout for Alice and Bob. + assert_ok!(Purchase::payout(RuntimeOrigin::signed(payment_account()), alice(),)); + assert_ok!(Purchase::payout(RuntimeOrigin::signed(payment_account()), bob(),)); + // Payment is made. + assert_eq!(::Currency::free_balance(&payment_account()), 99_650); + assert_eq!(::Currency::free_balance(&alice()), 100); + // 10% of the 50 units is unlocked automatically for Alice + assert_eq!(::VestingSchedule::vesting_balance(&alice()), Some(45)); + assert_eq!(::Currency::free_balance(&bob()), 250); + // A max of 10 units is unlocked automatically for Bob + assert_eq!(::VestingSchedule::vesting_balance(&bob()), Some(140)); + // Status is completed. + assert_eq!( + Accounts::::get(alice()), + AccountStatus { + validity: AccountValidity::Completed, + free_balance: 50, + locked_balance: 50, + signature: alice_signature().to_vec(), + vat: Permill::zero(), + } + ); + assert_eq!( + Accounts::::get(bob()), + AccountStatus { + validity: AccountValidity::Completed, + free_balance: 100, + locked_balance: 150, + signature: bob_signature().to_vec(), + vat: Permill::zero(), + } + ); + // Vesting lock is removed in whole on block 101 (100 blocks after block 1) + System::set_block_number(100); + let vest_call = RuntimeCall::Vesting(pallet_vesting::Call::::vest {}); + assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(alice()))); + assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(bob()))); + assert_eq!(::VestingSchedule::vesting_balance(&alice()), Some(45)); + assert_eq!(::VestingSchedule::vesting_balance(&bob()), Some(140)); + System::set_block_number(101); + assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(alice()))); + assert_ok!(vest_call.clone().dispatch(RuntimeOrigin::signed(bob()))); + assert_eq!(::VestingSchedule::vesting_balance(&alice()), None); + assert_eq!(::VestingSchedule::vesting_balance(&bob()), None); + }); +} + +#[test] +fn payout_handles_basic_errors() { + new_test_ext().execute_with(|| { + // Wrong Origin + assert_noop!(Purchase::payout(RuntimeOrigin::signed(alice()), alice(),), BadOrigin); + // Account with Existing Vesting Schedule + Balances::make_free_balance_be(&bob(), 100); + assert_ok!(::VestingSchedule::add_vesting_schedule(&bob(), 100, 1, 50,)); + assert_noop!( + Purchase::payout(RuntimeOrigin::signed(payment_account()), bob(),), + Error::::VestingScheduleExists + ); + // Invalid Account (never created) + assert_noop!( + Purchase::payout(RuntimeOrigin::signed(payment_account()), alice(),), + Error::::InvalidAccount + ); + // Invalid Account (created, but not valid) + assert_ok!(Purchase::create_account( + RuntimeOrigin::signed(validity_origin()), + alice(), + alice_signature().to_vec() + )); + assert_noop!( + Purchase::payout(RuntimeOrigin::signed(payment_account()), alice(),), + Error::::InvalidAccount + ); + // Not enough funds in payment account + assert_ok!(Purchase::update_validity_status( + RuntimeOrigin::signed(validity_origin()), + alice(), + AccountValidity::ValidHigh, + )); + assert_ok!(Purchase::update_balance( + RuntimeOrigin::signed(validity_origin()), + alice(), + 100_000, + 100_000, + Permill::zero(), + )); + assert_noop!( + Purchase::payout(RuntimeOrigin::signed(payment_account()), alice()), + ArithmeticError::Underflow + ); + }); +} + +#[test] +fn remove_pallet_works() { + new_test_ext().execute_with(|| { + let account_status = AccountStatus { + validity: AccountValidity::Completed, + free_balance: 1234, + locked_balance: 4321, + signature: b"my signature".to_vec(), + vat: Permill::from_percent(50), + }; + + // Add some storage. + Accounts::::insert(alice(), account_status.clone()); + Accounts::::insert(bob(), account_status); + PaymentAccount::::put(alice()); + Statement::::put(b"hello, world!".to_vec()); + UnlockBlock::::put(4); + + // Verify storage exists. + assert_eq!(Accounts::::iter().count(), 2); + assert!(PaymentAccount::::exists()); + assert!(Statement::::exists()); + assert!(UnlockBlock::::exists()); + + // Remove storage. + remove_pallet::(); + + // Verify storage is gone. + assert_eq!(Accounts::::iter().count(), 0); + assert!(!PaymentAccount::::exists()); + assert!(!Statement::::exists()); + assert!(!UnlockBlock::::exists()); + }); +} diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index 37fe7f0b59e9..32ea4fdd2f27 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -138,6 +138,13 @@ where .map(|()| hash) .map_err(|_| SendError::Transport(&"Error placing into DMP queue")) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(location: Option) { + if let Some((0, [Parachain(id)])) = location.as_ref().map(|l| l.unpack()) { + dmp::Pallet::::make_parachain_reachable(*id); + } + } } impl InspectMessageQueues for ChildParachainRouter { @@ -157,7 +164,7 @@ impl InspectMessageQueues for ChildParachainRouter>, PriceForDelivery: PriceForMessageDelivery, Parachain: Get, - ToParachainHelper: EnsureForParachain, + ToParachainHelper: polkadot_runtime_parachains::EnsureForParachain, > xcm_builder::EnsureDelivery for ToParachainDeliveryHelper< XcmConfig, @@ -219,6 +226,9 @@ impl< return (None, None) } + // allow more initialization for target parachain + ToParachainHelper::ensure(Parachain::get()); + let mut fees_mode = None; if !XcmConfig::FeeManager::is_waived(Some(origin_ref), fee_reason) { // if not waived, we need to set up accounts for paying and receiving fees @@ -238,9 +248,6 @@ impl< XcmConfig::AssetTransactor::deposit_asset(&fee, &origin_ref, None).unwrap(); } - // allow more initialization for target parachain - ToParachainHelper::ensure(Parachain::get()); - // expected worst case - direct withdraw fees_mode = Some(FeesMode { jit_withdraw: true }); } @@ -248,18 +255,6 @@ impl< } } -/// Ensure more initialization for `ParaId`. (e.g. open HRMP channels, ...) -#[cfg(feature = "runtime-benchmarks")] -pub trait EnsureForParachain { - fn ensure(para_id: ParaId); -} -#[cfg(feature = "runtime-benchmarks")] -impl EnsureForParachain for () { - fn ensure(_: ParaId) { - // doing nothing - } -} - #[cfg(test)] mod tests { use super::*; @@ -349,6 +344,8 @@ mod tests { c.max_downward_message_size = u32::MAX; }); + dmp::Pallet::::make_parachain_reachable(5555); + // Check that the good message is validated: assert_ok!(::validate( &mut Some(dest.into()), diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index 3709e1eb697e..beb7e3236d5a 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -5,15 +5,17 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Runtime metric interface for the Polkadot node" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -sp-tracing = { workspace = true } codec = { workspace = true } -polkadot-primitives = { workspace = true } frame-benchmarking = { optional = true, workspace = true } +polkadot-primitives = { workspace = true } +sp-tracing = { workspace = true } bs58 = { features = ["alloc"], workspace = true } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index a3eec3f9d961..7c00995d2291 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -5,37 +5,42 @@ description = "Relay Chain runtime code responsible for Parachains." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -impl-trait-for-tuples = { workspace = true } +bitflags = { workspace = true } bitvec = { features = ["alloc"], workspace = true } codec = { features = ["derive", "max-encoded-len"], workspace = true } +derive_more = { workspace = true, default-features = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } -derive_more = { workspace = true, default-features = true } -bitflags = { workspace = true } sp-api = { workspace = true } +sp-application-crypto = { optional = true, workspace = true } +sp-arithmetic = { workspace = true } +sp-core = { features = ["serde"], workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } +sp-keystore = { optional = true, workspace = true } sp-runtime = { features = ["serde"], workspace = true } sp-session = { workspace = true } sp-staking = { features = ["serde"], workspace = true } -sp-core = { features = ["serde"], workspace = true } -sp-keystore = { optional = true, workspace = true } -sp-application-crypto = { optional = true, workspace = true } -sp-tracing = { optional = true, workspace = true } -sp-arithmetic = { workspace = true } sp-std = { workspace = true, optional = true } +sp-tracing = { optional = true, workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } -pallet-balances = { workspace = true } pallet-babe = { workspace = true } +pallet-balances = { workspace = true } pallet-broker = { workspace = true } pallet-message-queue = { workspace = true } pallet-mmr = { workspace = true, optional = true } @@ -43,36 +48,33 @@ pallet-session = { workspace = true } pallet-staking = { workspace = true } pallet-timestamp = { workspace = true } pallet-vesting = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } +polkadot-primitives = { workspace = true } xcm = { workspace = true } xcm-executor = { workspace = true } -polkadot-primitives = { workspace = true } +polkadot-core-primitives = { workspace = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-runtime-metrics = { workspace = true } rand = { workspace = true } rand_chacha = { workspace = true } static_assertions = { optional = true, workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true } -polkadot-runtime-metrics = { workspace = true } -polkadot-core-primitives = { workspace = true } [dev-dependencies] polkadot-primitives = { workspace = true, features = ["test"] } +assert_matches = { workspace = true } +frame-support-test = { workspace = true } futures = { workspace = true } hex-literal = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -frame-support-test = { workspace = true } -sc-keystore = { workspace = true, default-features = true } polkadot-primitives-test-helpers = { workspace = true } -sp-tracing = { workspace = true, default-features = true } -sp-crypto-hashing = { workspace = true, default-features = true } -thousands = { workspace = true } -assert_matches = { workspace = true } rstest = { workspace = true } +sc-keystore = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +thousands = { workspace = true } [features] default = ["std"] @@ -138,6 +140,7 @@ runtime-benchmarks = [ "sp-std", "static_assertions", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support-test/try-runtime", diff --git a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs index 33a36a1bb2ea..866d52dc9848 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/mod.rs @@ -236,17 +236,9 @@ pub mod pallet { #[pallet::error] pub enum Error { AssignmentsEmpty, - /// Assignments together exceeded 57600. - OverScheduled, - /// Assignments together less than 57600 - UnderScheduled, /// assign_core is only allowed to append new assignments at the end of already existing - /// ones. + /// ones or update the last entry. DisallowedInsert, - /// Tried to insert a schedule for the same core and block number as an existing schedule - DuplicateInsert, - /// Tried to add an unsorted set of assignments - AssignmentsNotSorted, } } @@ -387,67 +379,56 @@ impl Pallet { /// Append another assignment for a core. /// - /// Important only appending is allowed. Meaning, all already existing assignments must have a - /// begin smaller than the one passed here. This restriction exists, because it makes the - /// insertion O(1) and the author could not think of a reason, why this restriction should be - /// causing any problems. Inserting arbitrarily causes a `DispatchError::DisallowedInsert` - /// error. This restriction could easily be lifted if need be and in fact an implementation is - /// available - /// [here](https://github.com/paritytech/polkadot-sdk/pull/1694/commits/c0c23b01fd2830910cde92c11960dad12cdff398#diff-0c85a46e448de79a5452395829986ee8747e17a857c27ab624304987d2dde8baR386). - /// The problem is that insertion complexity then depends on the size of the existing queue, - /// which makes determining weights hard and could lead to issues like overweight blocks (at - /// least in theory). + /// Important: Only appending is allowed or insertion into the last item. Meaning, + /// all already existing assignments must have a `begin` smaller or equal than the one passed + /// here. + /// Updating the last entry is supported to allow for making a core assignment multiple calls to + /// assign_core. Thus if you have too much interlacing for e.g. a single UMP message you can + /// split that up into multiple messages, each triggering a call to `assign_core`, together + /// forming the total assignment. + /// + /// Inserting arbitrarily causes a `DispatchError::DisallowedInsert` error. + // With this restriction this function allows for O(1) complexity. It could easily be lifted, if + // need be and in fact an implementation is available + // [here](https://github.com/paritytech/polkadot-sdk/pull/1694/commits/c0c23b01fd2830910cde92c11960dad12cdff398#diff-0c85a46e448de79a5452395829986ee8747e17a857c27ab624304987d2dde8baR386). + // The problem is that insertion complexity then depends on the size of the existing queue, + // which makes determining weights hard and could lead to issues like overweight blocks (at + // least in theory). pub fn assign_core( core_idx: CoreIndex, begin: BlockNumberFor, - assignments: Vec<(CoreAssignment, PartsOf57600)>, + mut assignments: Vec<(CoreAssignment, PartsOf57600)>, end_hint: Option>, ) -> Result<(), DispatchError> { // There should be at least one assignment. ensure!(!assignments.is_empty(), Error::::AssignmentsEmpty); - // Checking for sort and unique manually, since we don't have access to iterator tools. - // This way of checking uniqueness only works since we also check sortedness. - assignments.iter().map(|x| &x.0).try_fold(None, |prev, cur| { - if prev.map_or(false, |p| p >= cur) { - Err(Error::::AssignmentsNotSorted) - } else { - Ok(Some(cur)) - } - })?; - - // Check that the total parts between all assignments are equal to 57600 - let parts_sum = assignments - .iter() - .map(|assignment| assignment.1) - .try_fold(PartsOf57600::ZERO, |sum, parts| { - sum.checked_add(parts).ok_or(Error::::OverScheduled) - })?; - ensure!(parts_sum.is_full(), Error::::UnderScheduled); - CoreDescriptors::::mutate(core_idx, |core_descriptor| { let new_queue = match core_descriptor.queue { Some(queue) => { - ensure!(begin > queue.last, Error::::DisallowedInsert); - - CoreSchedules::::try_mutate((queue.last, core_idx), |schedule| { - if let Some(schedule) = schedule.as_mut() { - debug_assert!(schedule.next_schedule.is_none(), "queue.end was supposed to be the end, so the next item must be `None`!"); - schedule.next_schedule = Some(begin); + ensure!(begin >= queue.last, Error::::DisallowedInsert); + + // Update queue if we are appending: + if begin > queue.last { + CoreSchedules::::mutate((queue.last, core_idx), |schedule| { + if let Some(schedule) = schedule.as_mut() { + debug_assert!(schedule.next_schedule.is_none(), "queue.end was supposed to be the end, so the next item must be `None`!"); + schedule.next_schedule = Some(begin); + } else { + defensive!("Queue end entry does not exist?"); + } + }); + } + + CoreSchedules::::mutate((begin, core_idx), |schedule| { + let assignments = if let Some(mut old_schedule) = schedule.take() { + old_schedule.assignments.append(&mut assignments); + old_schedule.assignments } else { - defensive!("Queue end entry does not exist?"); - } - CoreSchedules::::try_mutate((begin, core_idx), |schedule| { - // It should already be impossible to overwrite an existing schedule due - // to strictly increasing block number. But we check here for safety and - // in case the design changes. - ensure!(schedule.is_none(), Error::::DuplicateInsert); - *schedule = - Some(Schedule { assignments, end_hint, next_schedule: None }); - Ok::<(), DispatchError>(()) - })?; - Ok::<(), DispatchError>(()) - })?; + assignments + }; + *schedule = Some(Schedule { assignments, end_hint, next_schedule: None }); + }); QueueDescriptor { first: queue.first, last: begin } }, diff --git a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs index 25007f0eed6a..ab011bfc4ae1 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs @@ -235,10 +235,7 @@ fn assign_core_works_with_prior_schedule() { } #[test] -// Invariants: We assume that CoreSchedules is append only and consumed. In other words new -// schedules inserted for a core must have a higher block number than all of the already existing -// schedules. -fn assign_core_enforces_higher_block_number() { +fn assign_core_enforces_higher_or_equal_block_number() { let core_idx = CoreIndex(0); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { @@ -255,7 +252,7 @@ fn assign_core_enforces_higher_block_number() { assert_ok!(CoretimeAssigner::assign_core( core_idx, BlockNumberFor::::from(15u32), - default_test_assignments(), + vec![(CoreAssignment::Idle, PartsOf57600(28800))], None, )); @@ -281,32 +278,27 @@ fn assign_core_enforces_higher_block_number() { ), Error::::DisallowedInsert ); + // Call assign core again on last entry should work: + assert_eq!( + CoretimeAssigner::assign_core( + core_idx, + BlockNumberFor::::from(15u32), + vec![(CoreAssignment::Pool, PartsOf57600(28800))], + None, + ), + Ok(()) + ); }); } #[test] fn assign_core_enforces_well_formed_schedule() { - let para_id = ParaId::from(1u32); let core_idx = CoreIndex(0); new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { run_to_block(1, |n| if n == 1 { Some(Default::default()) } else { None }); let empty_assignments: Vec<(CoreAssignment, PartsOf57600)> = vec![]; - let overscheduled = vec![ - (CoreAssignment::Pool, PartsOf57600::FULL), - (CoreAssignment::Task(para_id.into()), PartsOf57600::FULL), - ]; - let underscheduled = vec![(CoreAssignment::Pool, PartsOf57600(30000))]; - let not_unique = vec![ - (CoreAssignment::Pool, PartsOf57600::FULL / 2), - (CoreAssignment::Pool, PartsOf57600::FULL / 2), - ]; - let not_sorted = vec![ - (CoreAssignment::Task(para_id.into()), PartsOf57600(19200)), - (CoreAssignment::Pool, PartsOf57600(19200)), - (CoreAssignment::Idle, PartsOf57600(19200)), - ]; // Attempting assign_core with malformed assignments such that all error cases // are tested @@ -319,42 +311,6 @@ fn assign_core_enforces_well_formed_schedule() { ), Error::::AssignmentsEmpty ); - assert_noop!( - CoretimeAssigner::assign_core( - core_idx, - BlockNumberFor::::from(11u32), - overscheduled, - None, - ), - Error::::OverScheduled - ); - assert_noop!( - CoretimeAssigner::assign_core( - core_idx, - BlockNumberFor::::from(11u32), - underscheduled, - None, - ), - Error::::UnderScheduled - ); - assert_noop!( - CoretimeAssigner::assign_core( - core_idx, - BlockNumberFor::::from(11u32), - not_unique, - None, - ), - Error::::AssignmentsNotSorted - ); - assert_noop!( - CoretimeAssigner::assign_core( - core_idx, - BlockNumberFor::::from(11u32), - not_sorted, - None, - ), - Error::::AssignmentsNotSorted - ); }); } @@ -374,7 +330,14 @@ fn next_schedule_always_points_to_next_work_plan_item() { Schedule { next_schedule: Some(start_4), ..default_test_schedule() }; let expected_schedule_4 = Schedule { next_schedule: Some(start_5), ..default_test_schedule() }; - let expected_schedule_5 = default_test_schedule(); + let expected_schedule_5 = Schedule { + next_schedule: None, + end_hint: None, + assignments: vec![ + (CoreAssignment::Pool, PartsOf57600(28800)), + (CoreAssignment::Idle, PartsOf57600(28800)), + ], + }; // Call assign_core for each of five schedules assert_ok!(CoretimeAssigner::assign_core( @@ -408,7 +371,14 @@ fn next_schedule_always_points_to_next_work_plan_item() { assert_ok!(CoretimeAssigner::assign_core( core_idx, BlockNumberFor::::from(start_5), - default_test_assignments(), + vec![(CoreAssignment::Pool, PartsOf57600(28800))], + None, + )); + // Test updating last entry once more: + assert_ok!(CoretimeAssigner::assign_core( + core_idx, + BlockNumberFor::::from(start_5), + vec![(CoreAssignment::Idle, PartsOf57600(28800))], None, )); diff --git a/polkadot/runtime/parachains/src/coretime/benchmarking.rs b/polkadot/runtime/parachains/src/coretime/benchmarking.rs index 6d593f1954ff..49e3d8a88c01 100644 --- a/polkadot/runtime/parachains/src/coretime/benchmarking.rs +++ b/polkadot/runtime/parachains/src/coretime/benchmarking.rs @@ -43,6 +43,8 @@ mod benchmarks { .unwrap(); on_demand::Revenue::::put(rev); + crate::paras::Heads::::insert(ParaId::from(T::BrokerId::get()), vec![1, 2, 3]); + ::Currency::make_free_balance_be( &>::account_id(), minimum_balance * (mhr * (mhr + 1)).into(), diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index 52189be3d247..c3a1ebe82432 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -42,7 +42,9 @@ mod v_coretime { use sp_arithmetic::traits::SaturatedConversion; use sp_core::Get; use sp_runtime::BoundedVec; - use xcm::prelude::{send_xcm, Instruction, Junction, Location, SendError, WeightLimit, Xcm}; + use xcm::prelude::{ + send_xcm, Instruction, Junction, Location, SendError, SendXcm, WeightLimit, Xcm, + }; /// Return information about a legacy lease of a parachain. pub trait GetLegacyLease { @@ -62,10 +64,10 @@ mod v_coretime { impl< T: Config, - SendXcm: xcm::v4::SendXcm, + XcmSender: SendXcm, LegacyLease: GetLegacyLease>, const TIMESLICE_PERIOD: u32, - > MigrateToCoretime + > MigrateToCoretime { fn already_migrated() -> bool { // We are using the assigner coretime because the coretime pallet doesn't has any @@ -95,10 +97,10 @@ mod v_coretime { impl< T: Config + crate::dmp::Config, - SendXcm: xcm::v4::SendXcm, + XcmSender: SendXcm, LegacyLease: GetLegacyLease>, const TIMESLICE_PERIOD: u32, - > OnRuntimeUpgrade for MigrateToCoretime + > OnRuntimeUpgrade for MigrateToCoretime { fn on_runtime_upgrade() -> Weight { if Self::already_migrated() { @@ -106,7 +108,7 @@ mod v_coretime { } log::info!("Migrating existing parachains to coretime."); - migrate_to_coretime::() + migrate_to_coretime::() } #[cfg(feature = "try-runtime")] @@ -157,7 +159,7 @@ mod v_coretime { // NOTE: Also migrates `num_cores` config value in configuration::ActiveConfig. fn migrate_to_coretime< T: Config, - SendXcm: xcm::v4::SendXcm, + XcmSender: SendXcm, LegacyLease: GetLegacyLease>, const TIMESLICE_PERIOD: u32, >() -> Weight { @@ -198,9 +200,12 @@ mod v_coretime { c.scheduler_params.num_cores = total_cores; }); - if let Err(err) = - migrate_send_assignments_to_coretime_chain::( - ) { + if let Err(err) = migrate_send_assignments_to_coretime_chain::< + T, + XcmSender, + LegacyLease, + TIMESLICE_PERIOD, + >() { log::error!("Sending legacy chain data to coretime chain failed: {:?}", err); } @@ -215,7 +220,7 @@ mod v_coretime { fn migrate_send_assignments_to_coretime_chain< T: Config, - SendXcm: xcm::v4::SendXcm, + XcmSender: SendXcm, LegacyLease: GetLegacyLease>, const TIMESLICE_PERIOD: u32, >() -> result::Result<(), SendError> { @@ -300,7 +305,7 @@ mod v_coretime { }; for message in messages { - send_xcm::( + send_xcm::( Location::new(0, Junction::Parachain(T::BrokerId::get())), message, )?; diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index 9b9bdb86878f..5656e92b90be 100644 --- a/polkadot/runtime/parachains/src/coretime/mod.rs +++ b/polkadot/runtime/parachains/src/coretime/mod.rs @@ -30,20 +30,7 @@ use pallet_broker::{CoreAssignment, CoreIndex as BrokerCoreIndex}; use polkadot_primitives::{Balance, BlockNumber, CoreIndex, Id as ParaId}; use sp_arithmetic::traits::SaturatedConversion; use sp_runtime::traits::TryConvert; -use xcm::{ - prelude::{send_xcm, Instruction, Junction, Location, OriginKind, SendXcm, WeightLimit, Xcm}, - v4::{ - Asset, - AssetFilter::Wild, - AssetId, Assets, Error as XcmError, - Fungibility::Fungible, - Instruction::{DepositAsset, ReceiveTeleportedAsset}, - Junctions::Here, - Reanchorable, - WildAsset::AllCounted, - XcmContext, - }, -}; +use xcm::prelude::*; use xcm_executor::traits::TransactAsset; use crate::{ @@ -119,7 +106,7 @@ pub mod pallet { use crate::configuration; use sp_runtime::traits::TryConvert; - use xcm::v4::InteriorLocation; + use xcm::latest::InteriorLocation; use xcm_executor::traits::TransactAsset; use super::*; @@ -351,7 +338,7 @@ impl OnNewSession> for Pallet { fn mk_coretime_call(call: crate::coretime::CoretimeCalls) -> Instruction<()> { Instruction::Transact { origin_kind: OriginKind::Superuser, - require_weight_at_most: T::MaxXcmTransactWeight::get(), + fallback_max_weight: Some(T::MaxXcmTransactWeight::get()), call: BrokerRuntimePallets::Broker(call).encode().into(), } } @@ -362,7 +349,7 @@ fn do_notify_revenue(when: BlockNumber, raw_revenue: Balance) -> Resu weight_limit: WeightLimit::Unlimited, check_origin: None, }]; - let asset = Asset { id: AssetId(Location::here()), fun: Fungible(raw_revenue) }; + let asset = Asset { id: Location::here().into(), fun: Fungible(raw_revenue) }; let dummy_xcm_context = XcmContext { origin: None, message_id: [0; 32], topic: None }; if raw_revenue > 0 { diff --git a/polkadot/runtime/parachains/src/disputes/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/benchmarking.rs index 05f4b3f1ac81..571c44d1ac24 100644 --- a/polkadot/runtime/parachains/src/disputes/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/benchmarking.rs @@ -16,15 +16,21 @@ use super::*; -use frame_benchmarking::benchmarks; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; use sp_runtime::traits::One; -benchmarks! { - force_unfreeze { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn force_unfreeze() { Frozen::::set(Some(One::one())); - }: _(RawOrigin::Root) - verify { + + #[extrinsic_call] + _(RawOrigin::Root); + assert!(Frozen::::get().is_none()) } diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index 2e09ea667f74..95dbf2ba42bb 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -355,12 +355,12 @@ impl HandleReports for () { } pub trait WeightInfo { - fn report_dispute_lost(validator_count: ValidatorSetCount) -> Weight; + fn report_dispute_lost_unsigned(validator_count: ValidatorSetCount) -> Weight; } pub struct TestWeightInfo; impl WeightInfo for TestWeightInfo { - fn report_dispute_lost(_validator_count: ValidatorSetCount) -> Weight { + fn report_dispute_lost_unsigned(_validator_count: ValidatorSetCount) -> Weight { Weight::zero() } } @@ -445,7 +445,7 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::report_dispute_lost( + #[pallet::weight(::WeightInfo::report_dispute_lost_unsigned( key_owner_proof.validator_count() ))] pub fn report_dispute_lost_unsigned( diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index b53f98caeea3..bfd46d752438 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -18,7 +18,7 @@ use super::*; use crate::{disputes::SlashingHandler, initializer, shared}; use codec::Decode; -use frame_benchmarking::{benchmarks, whitelist_account}; +use frame_benchmarking::v2::*; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_staking::testing_utils::create_validators; @@ -29,6 +29,11 @@ use sp_session::MembershipProof; // Candidate hash of the disputed candidate. const CANDIDATE_HASH: CandidateHash = CandidateHash(Hash::zero()); +// Simplify getting the value in the benchmark +pub const fn max_validators_for() -> u32 { + <::BenchmarkingConfig as BenchmarkingConfiguration>::MAX_VALIDATORS +} + pub trait Config: pallet_session::Config + pallet_session::historical::Config @@ -106,6 +111,7 @@ where (session_index, key_owner_proof, validator_id) } +/// Submits a single `ForInvalid` dispute. fn setup_dispute(session_index: SessionIndex, validator_id: ValidatorId) -> DisputeProof where T: Config, @@ -125,6 +131,7 @@ where dispute_proof(session_index, validator_id, validator_index) } +/// Creates a `ForInvalid` dispute proof. fn dispute_proof( session_index: SessionIndex, validator_id: ValidatorId, @@ -136,27 +143,20 @@ fn dispute_proof( DisputeProof { time_slot, kind, validator_index, validator_id } } -benchmarks! { - where_clause { - where T: Config, - } - - // in this setup we have a single `ForInvalid` dispute - // submitted for a past session - report_dispute_lost { - let n in 4..<::BenchmarkingConfig as BenchmarkingConfiguration>::MAX_VALIDATORS; +#[benchmarks(where T: Config)] +mod benchmarks { + use super::*; - let origin = RawOrigin::None.into(); + #[benchmark] + fn report_dispute_lost_unsigned(n: Linear<4, { max_validators_for::() }>) { let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); + + // submit a single `ForInvalid` dispute for a past session. let dispute_proof = setup_dispute::(session_index, validator_id); - }: { - let result = Pallet::::report_dispute_lost_unsigned( - origin, - Box::new(dispute_proof), - key_owner_proof, - ); - assert!(result.is_ok()); - } verify { + + #[extrinsic_call] + _(RawOrigin::None, Box::new(dispute_proof), key_owner_proof); + let unapplied = >::get(session_index, CANDIDATE_HASH); assert!(unapplied.is_none()); } diff --git a/polkadot/runtime/parachains/src/dmp.rs b/polkadot/runtime/parachains/src/dmp.rs index 03580e11b8e9..3c9cf8004186 100644 --- a/polkadot/runtime/parachains/src/dmp.rs +++ b/polkadot/runtime/parachains/src/dmp.rs @@ -44,7 +44,7 @@ use crate::{ configuration::{self, HostConfiguration}, - initializer, FeeTracker, + initializer, paras, FeeTracker, }; use alloc::vec::Vec; use core::fmt; @@ -72,12 +72,15 @@ const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0 pub enum QueueDownwardMessageError { /// The message being sent exceeds the configured max message size. ExceedsMaxMessageSize, + /// The destination is unknown. + Unroutable, } impl From for SendError { fn from(err: QueueDownwardMessageError) -> Self { match err { QueueDownwardMessageError::ExceedsMaxMessageSize => SendError::ExceedsMaxMessageSize, + QueueDownwardMessageError::Unroutable => SendError::Unroutable, } } } @@ -116,7 +119,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + configuration::Config {} + pub trait Config: frame_system::Config + configuration::Config + paras::Config {} /// The downward messages addressed for a certain para. #[pallet::storage] @@ -200,6 +203,11 @@ impl Pallet { return Err(QueueDownwardMessageError::ExceedsMaxMessageSize) } + // If the head exists, we assume the parachain is legit and exists. + if !paras::Heads::::contains_key(para) { + return Err(QueueDownwardMessageError::Unroutable) + } + Ok(()) } @@ -217,14 +225,7 @@ impl Pallet { msg: DownwardMessage, ) -> Result<(), QueueDownwardMessageError> { let serialized_len = msg.len() as u32; - if serialized_len > config.max_downward_message_size { - return Err(QueueDownwardMessageError::ExceedsMaxMessageSize) - } - - // Hard limit on Queue size - if Self::dmq_length(para) > Self::dmq_max_length(config.max_downward_message_size) { - return Err(QueueDownwardMessageError::ExceedsMaxMessageSize) - } + Self::can_queue_downward_message(config, ¶, &msg)?; let inbound = InboundDownwardMessage { msg, sent_at: frame_system::Pallet::::block_number() }; @@ -336,6 +337,15 @@ impl Pallet { ) -> Vec>> { DownwardMessageQueues::::get(&recipient) } + + /// Make the parachain reachable for downward messages. + /// + /// Only useable in benchmarks or tests. + #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + pub fn make_parachain_reachable(para: impl Into) { + let para = para.into(); + crate::paras::Heads::::insert(para, para.encode()); + } } impl FeeTracker for Pallet { @@ -359,3 +369,10 @@ impl FeeTracker for Pallet { }) } } + +#[cfg(feature = "runtime-benchmarks")] +impl crate::EnsureForParachain for Pallet { + fn ensure(para: ParaId) { + Self::make_parachain_reachable(para); + } +} diff --git a/polkadot/runtime/parachains/src/dmp/tests.rs b/polkadot/runtime/parachains/src/dmp/tests.rs index de1515958125..617c9488bd2a 100644 --- a/polkadot/runtime/parachains/src/dmp/tests.rs +++ b/polkadot/runtime/parachains/src/dmp/tests.rs @@ -61,6 +61,12 @@ fn queue_downward_message( Dmp::queue_downward_message(&configuration::ActiveConfig::::get(), para_id, msg) } +fn register_paras(paras: &[ParaId]) { + paras.iter().for_each(|p| { + Dmp::make_parachain_reachable(*p); + }); +} + #[test] fn clean_dmp_works() { let a = ParaId::from(1312); @@ -68,6 +74,8 @@ fn clean_dmp_works() { let c = ParaId::from(123); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a, b, c]); + // enqueue downward messages to A, B and C. queue_downward_message(a, vec![1, 2, 3]).unwrap(); queue_downward_message(b, vec![4, 5, 6]).unwrap(); @@ -89,6 +97,8 @@ fn dmq_length_and_head_updated_properly() { let b = ParaId::from(228); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a, b]); + assert_eq!(Dmp::dmq_length(a), 0); assert_eq!(Dmp::dmq_length(b), 0); @@ -101,11 +111,30 @@ fn dmq_length_and_head_updated_properly() { }); } +#[test] +fn dmq_fail_if_para_does_not_exist() { + let a = ParaId::from(1312); + + new_test_ext(default_genesis_config()).execute_with(|| { + assert_eq!(Dmp::dmq_length(a), 0); + + assert!(matches!( + queue_downward_message(a, vec![1, 2, 3]), + Err(QueueDownwardMessageError::Unroutable) + )); + + assert_eq!(Dmp::dmq_length(a), 0); + assert!(Dmp::dmq_mqc_head(a).is_zero()); + }); +} + #[test] fn dmp_mqc_head_fixture() { let a = ParaId::from(2000); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a]); + run_to_block(2, None); assert!(Dmp::dmq_mqc_head(a).is_zero()); queue_downward_message(a, vec![1, 2, 3]).unwrap(); @@ -125,6 +154,8 @@ fn check_processed_downward_messages() { let a = ParaId::from(1312); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a]); + let block_number = System::block_number(); // processed_downward_messages=0 is allowed when the DMQ is empty. @@ -150,6 +181,8 @@ fn check_processed_downward_messages_advancement_rule() { let a = ParaId::from(1312); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a]); + let block_number = System::block_number(); run_to_block(block_number + 1, None); @@ -170,6 +203,8 @@ fn dmq_pruning() { let a = ParaId::from(1312); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a]); + assert_eq!(Dmp::dmq_length(a), 0); queue_downward_message(a, vec![1, 2, 3]).unwrap(); @@ -194,6 +229,8 @@ fn queue_downward_message_critical() { genesis.configuration.config.max_downward_message_size = 7; new_test_ext(genesis).execute_with(|| { + register_paras(&[a]); + let smol = [0; 3].to_vec(); let big = [0; 8].to_vec(); @@ -215,6 +252,8 @@ fn verify_dmq_mqc_head_is_externally_accessible() { let a = ParaId::from(2020); new_test_ext(default_genesis_config()).execute_with(|| { + register_paras(&[a]); + let head = sp_io::storage::get(&well_known_keys::dmq_mqc_head(a)); assert_eq!(head, None); @@ -235,9 +274,12 @@ fn verify_dmq_mqc_head_is_externally_accessible() { #[test] fn verify_fee_increase_and_decrease() { let a = ParaId::from(123); + let mut genesis = default_genesis_config(); genesis.configuration.config.max_downward_message_size = 16777216; new_test_ext(genesis).execute_with(|| { + register_paras(&[a]); + let initial = InitialFactor::get(); assert_eq!(DeliveryFeeFactor::::get(a), initial); @@ -287,6 +329,8 @@ fn verify_fee_factor_reaches_high_value() { let mut genesis = default_genesis_config(); genesis.configuration.config.max_downward_message_size = 51200; new_test_ext(genesis).execute_with(|| { + register_paras(&[a]); + let max_messages = Dmp::dmq_max_length(ActiveConfig::::get().max_downward_message_size); let mut total_fee_factor = FixedU128::from_float(1.0); diff --git a/polkadot/runtime/parachains/src/inclusion/benchmarking.rs b/polkadot/runtime/parachains/src/inclusion/benchmarking.rs index 1dac3c92cf16..ab95c5c2366a 100644 --- a/polkadot/runtime/parachains/src/inclusion/benchmarking.rs +++ b/polkadot/runtime/parachains/src/inclusion/benchmarking.rs @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use bitvec::{bitvec, prelude::Lsb0}; +use frame_benchmarking::v2::*; +use pallet_message_queue as mq; +use polkadot_primitives::{ + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateCommitments, + HrmpChannelId, OutboundHrmpMessage, SessionIndex, +}; + use super::*; use crate::{ builder::generate_validator_pairs, @@ -21,13 +29,6 @@ use crate::{ hrmp::{HrmpChannel, HrmpChannels}, initializer, HeadData, ValidationCode, }; -use bitvec::{bitvec, prelude::Lsb0}; -use frame_benchmarking::benchmarks; -use pallet_message_queue as mq; -use polkadot_primitives::{ - vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateCommitments, - HrmpChannelId, OutboundHrmpMessage, SessionIndex, -}; fn create_candidate_commitments( para_id: ParaId, @@ -70,7 +71,7 @@ fn create_candidate_commitments( BoundedVec::truncate_from(unbounded) }; - let new_validation_code = code_upgrade.then_some(ValidationCode(vec![42u8; 1024])); + let new_validation_code = code_upgrade.then_some(ValidationCode(vec![42_u8; 1024])); CandidateCommitments:: { upward_messages, @@ -87,18 +88,13 @@ fn create_messages(msg_len: usize, n_msgs: usize) -> Vec> { vec![vec![best_number; msg_len]; n_msgs] } -benchmarks! { - where_clause { - where - T: mq::Config + configuration::Config + initializer::Config, - } - - enact_candidate { - let u in 0 .. 2; - let h in 0 .. 2; - let c in 0 .. 1; +#[benchmarks(where T: mq::Config + configuration::Config + initializer::Config)] +mod benchmarks { + use super::*; - let para = 42_u32.into(); // not especially important. + #[benchmark] + fn enact_candidate(u: Linear<0, 2>, h: Linear<0, 2>, c: Linear<0, 1>) { + let para = 42_u32.into(); // not especially important. let max_len = mq::MaxMessageLenOf::::get() as usize; @@ -106,7 +102,7 @@ benchmarks! { let n_validators = config.max_validators.unwrap_or(500); let validators = generate_validator_pairs::(n_validators); - let session = SessionIndex::from(0u32); + let session = SessionIndex::from(0_u32); initializer::Pallet::::test_trigger_on_new_session( false, session, @@ -116,7 +112,7 @@ benchmarks! { let backing_group_size = config.scheduler_params.max_validators_per_core.unwrap_or(5); let head_data = HeadData(vec![0xFF; 1024]); - let relay_parent_number = BlockNumberFor::::from(10u32); + let relay_parent_number = BlockNumberFor::::from(10_u32); let commitments = create_candidate_commitments::(para, head_data, max_len, u, h, c != 0); let backers = bitvec![u8, Lsb0; 1; backing_group_size as usize]; let availability_votes = bitvec![u8, Lsb0; 1; n_validators as usize]; @@ -135,17 +131,26 @@ benchmarks! { ValidationCode(vec![1, 2, 3]).hash(), ); - let receipt = CommittedCandidateReceipt:: { - descriptor, - commitments, - }; + let receipt = CommittedCandidateReceipt:: { descriptor, commitments }; - Pallet::::receive_upward_messages(para, vec![vec![0; max_len]; 1].as_slice()); - } : { Pallet::::enact_candidate(relay_parent_number, receipt, backers, availability_votes, core_index, backing_group) } + Pallet::::receive_upward_messages(para, &vec![vec![0; max_len]; 1]); - impl_benchmark_test_suite!( + #[block] + { + Pallet::::enact_candidate( + relay_parent_number, + receipt, + backers, + availability_votes, + core_index, + backing_group, + ); + } + } + + impl_benchmark_test_suite! { Pallet, crate::mock::new_test_ext(Default::default()), crate::mock::Test - ); + } } diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index ea3a5d3cdda9..8ad9711a0f38 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -46,7 +46,7 @@ use pallet_message_queue::OnQueueChanged; use polkadot_primitives::{ effective_minimum_backing_votes, supermajority_threshold, vstaging::{ - BackedCandidate, CandidateDescriptorV2 as CandidateDescriptor, + skip_ump_signals, BackedCandidate, CandidateDescriptorV2 as CandidateDescriptor, CandidateReceiptV2 as CandidateReceipt, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, }, @@ -412,11 +412,6 @@ pub(crate) enum UmpAcceptanceCheckErr { TotalSizeExceeded { total_size: u64, limit: u64 }, /// A para-chain cannot send UMP messages while it is offboarding. IsOffboarding, - /// The allowed number of `UMPSignal` messages in the queue was exceeded. - /// Currenly only one such message is allowed. - TooManyUMPSignals { count: u32 }, - /// The UMP queue contains an invalid `UMPSignal` - NoUmpSignal, } impl fmt::Debug for UmpAcceptanceCheckErr { @@ -445,12 +440,6 @@ impl fmt::Debug for UmpAcceptanceCheckErr { UmpAcceptanceCheckErr::IsOffboarding => { write!(fmt, "upward message rejected because the para is off-boarding") }, - UmpAcceptanceCheckErr::TooManyUMPSignals { count } => { - write!(fmt, "the ump queue has too many `UMPSignal` messages ({} > 1 )", count) - }, - UmpAcceptanceCheckErr::NoUmpSignal => { - write!(fmt, "Required UMP signal not found") - }, } } } @@ -925,25 +914,7 @@ impl Pallet { upward_messages: &[UpwardMessage], ) -> Result<(), UmpAcceptanceCheckErr> { // Filter any pending UMP signals and the separator. - let upward_messages = if let Some(separator_index) = - upward_messages.iter().position(|message| message.is_empty()) - { - let (upward_messages, ump_signals) = upward_messages.split_at(separator_index); - - if ump_signals.len() > 2 { - return Err(UmpAcceptanceCheckErr::TooManyUMPSignals { - count: ump_signals.len() as u32, - }) - } - - if ump_signals.len() == 1 { - return Err(UmpAcceptanceCheckErr::NoUmpSignal) - } - - upward_messages - } else { - upward_messages - }; + let upward_messages = skip_ump_signals(upward_messages.iter()).collect::>(); // Cannot send UMP messages while off-boarding. if paras::Pallet::::is_offboarding(para) { @@ -997,10 +968,7 @@ impl Pallet { /// to deal with the messages as given. Messages that are too long will be ignored since such /// candidates should have already been rejected in [`Self::check_upward_messages`]. pub(crate) fn receive_upward_messages(para: ParaId, upward_messages: &[Vec]) { - let bounded = upward_messages - .iter() - // Stop once we hit the `UMPSignal` separator. - .take_while(|message| !message.is_empty()) + let bounded = skip_ump_signals(upward_messages.iter()) .filter_map(|d| { BoundedSlice::try_from(&d[..]) .inspect_err(|_| { diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index 828c0b9bcef2..b1ff5419470e 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -114,3 +114,19 @@ pub fn schedule_code_upgrade( pub fn set_current_head(id: ParaId, new_head: HeadData) { paras::Pallet::::set_current_head(id, new_head) } + +/// Ensure more initialization for `ParaId` when benchmarking. (e.g. open HRMP channels, ...) +#[cfg(feature = "runtime-benchmarks")] +pub trait EnsureForParachain { + fn ensure(para_id: ParaId); +} + +#[cfg(feature = "runtime-benchmarks")] +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl EnsureForParachain for Tuple { + fn ensure(para: ParaId) { + for_tuples!( #( + Tuple::ensure(para); + )* ); + } +} diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 9ef3922f0f8c..ee1990a7b618 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -30,7 +30,9 @@ use polkadot_primitives::CoreIndex; use codec::Decode; use frame_support::{ - assert_ok, derive_impl, parameter_types, + assert_ok, derive_impl, + dispatch::GetDispatchInfo, + parameter_types, traits::{ Currency, ProcessMessage, ProcessMessageError, ValidatorSet, ValidatorSetWithIdentification, }, @@ -56,7 +58,7 @@ use std::{ }; use xcm::{ prelude::XcmVersion, - v4::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}, + v5::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}, IntoVersion, VersionedXcm, WrapVersion, }; @@ -260,7 +262,7 @@ thread_local! { /// versions in the `VERSION_WRAPPER`. pub struct TestUsesOnlyStoredVersionWrapper; impl WrapVersion for TestUsesOnlyStoredVersionWrapper { - fn wrap_version( + fn wrap_version( dest: &Location, xcm: impl Into>, ) -> Result, ()> { diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 7bf8b833ed91..4d617cbb05bb 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -17,7 +17,7 @@ use super::*; use crate::configuration::HostConfiguration; use alloc::vec; -use frame_benchmarking::benchmarks; +use frame_benchmarking::v2::*; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use polkadot_primitives::{ HeadData, Id as ParaId, ValidationCode, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, @@ -84,41 +84,58 @@ fn generate_disordered_actions_queue() { }); } -benchmarks! { - force_set_current_code { - let c in MIN_CODE_SIZE .. MAX_CODE_SIZE; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn force_set_current_code(c: Linear) { let new_code = ValidationCode(vec![0; c as usize]); let para_id = ParaId::from(c as u32); CurrentCodeHash::::insert(¶_id, new_code.hash()); generate_disordered_pruning::(); - }: _(RawOrigin::Root, para_id, new_code) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, para_id, new_code); + assert_last_event::(Event::CurrentCodeUpdated(para_id).into()); } - force_set_current_head { - let s in MIN_CODE_SIZE .. MAX_HEAD_DATA_SIZE; + + #[benchmark] + fn force_set_current_head(s: Linear) { let new_head = HeadData(vec![0; s as usize]); let para_id = ParaId::from(1000); - }: _(RawOrigin::Root, para_id, new_head) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, para_id, new_head); + assert_last_event::(Event::CurrentHeadUpdated(para_id).into()); } - force_set_most_recent_context { + + #[benchmark] + fn force_set_most_recent_context() { let para_id = ParaId::from(1000); let context = BlockNumberFor::::from(1000u32); - }: _(RawOrigin::Root, para_id, context) - force_schedule_code_upgrade { - let c in MIN_CODE_SIZE .. MAX_CODE_SIZE; + + #[extrinsic_call] + _(RawOrigin::Root, para_id, context); + } + + #[benchmark] + fn force_schedule_code_upgrade(c: Linear) { let new_code = ValidationCode(vec![0; c as usize]); let para_id = ParaId::from(c as u32); let block = BlockNumberFor::::from(c); generate_disordered_upgrades::(); - }: _(RawOrigin::Root, para_id, new_code, block) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, para_id, new_code, block); + assert_last_event::(Event::CodeUpgradeScheduled(para_id).into()); } - force_note_new_head { - let s in MIN_CODE_SIZE .. MAX_HEAD_DATA_SIZE; + + #[benchmark] + fn force_note_new_head(s: Linear) { let para_id = ParaId::from(1000); let new_head = HeadData(vec![0; s as usize]); let old_code_hash = ValidationCode(vec![0]).hash(); @@ -135,70 +152,101 @@ benchmarks! { &config, UpgradeStrategy::SetGoAheadSignal, ); - }: _(RawOrigin::Root, para_id, new_head) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, para_id, new_head); + assert_last_event::(Event::NewHeadNoted(para_id).into()); } - force_queue_action { + + #[benchmark] + fn force_queue_action() { let para_id = ParaId::from(1000); generate_disordered_actions_queue::(); - }: _(RawOrigin::Root, para_id) - verify { - let next_session = crate::shared::CurrentSessionIndex::::get().saturating_add(One::one()); + + #[extrinsic_call] + _(RawOrigin::Root, para_id); + + let next_session = + crate::shared::CurrentSessionIndex::::get().saturating_add(One::one()); assert_last_event::(Event::ActionQueued(para_id, next_session).into()); } - add_trusted_validation_code { - let c in MIN_CODE_SIZE .. MAX_CODE_SIZE; + #[benchmark] + fn add_trusted_validation_code(c: Linear) { let new_code = ValidationCode(vec![0; c as usize]); pvf_check::prepare_bypassing_bench::(new_code.clone()); - }: _(RawOrigin::Root, new_code) - poke_unused_validation_code { + #[extrinsic_call] + _(RawOrigin::Root, new_code); + } + + #[benchmark] + fn poke_unused_validation_code() { let code_hash = [0; 32].into(); - }: _(RawOrigin::Root, code_hash) - include_pvf_check_statement { + #[extrinsic_call] + _(RawOrigin::Root, code_hash); + } + + #[benchmark] + fn include_pvf_check_statement() { let (stmt, signature) = pvf_check::prepare_inclusion_bench::(); - }: { - let _ = Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + + #[block] + { + let _ = + Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + } } - include_pvf_check_statement_finalize_upgrade_accept { - let (stmt, signature) = pvf_check::prepare_finalization_bench::( - VoteCause::Upgrade, - VoteOutcome::Accept, - ); - }: { - let _ = Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + #[benchmark] + fn include_pvf_check_statement_finalize_upgrade_accept() { + let (stmt, signature) = + pvf_check::prepare_finalization_bench::(VoteCause::Upgrade, VoteOutcome::Accept); + + #[block] + { + let _ = + Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + } } - include_pvf_check_statement_finalize_upgrade_reject { - let (stmt, signature) = pvf_check::prepare_finalization_bench::( - VoteCause::Upgrade, - VoteOutcome::Reject, - ); - }: { - let _ = Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + #[benchmark] + fn include_pvf_check_statement_finalize_upgrade_reject() { + let (stmt, signature) = + pvf_check::prepare_finalization_bench::(VoteCause::Upgrade, VoteOutcome::Reject); + + #[block] + { + let _ = + Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + } } - include_pvf_check_statement_finalize_onboarding_accept { - let (stmt, signature) = pvf_check::prepare_finalization_bench::( - VoteCause::Onboarding, - VoteOutcome::Accept, - ); - }: { - let _ = Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + #[benchmark] + fn include_pvf_check_statement_finalize_onboarding_accept() { + let (stmt, signature) = + pvf_check::prepare_finalization_bench::(VoteCause::Onboarding, VoteOutcome::Accept); + + #[block] + { + let _ = + Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + } } - include_pvf_check_statement_finalize_onboarding_reject { - let (stmt, signature) = pvf_check::prepare_finalization_bench::( - VoteCause::Onboarding, - VoteOutcome::Reject, - ); - }: { - let _ = Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + #[benchmark] + fn include_pvf_check_statement_finalize_onboarding_reject() { + let (stmt, signature) = + pvf_check::prepare_finalization_bench::(VoteCause::Onboarding, VoteOutcome::Reject); + + #[block] + { + let _ = + Pallet::::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature); + } } impl_benchmark_test_suite!( diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index eef26b83368f..146be0ee0aad 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -1864,11 +1864,8 @@ mod enter { v2_descriptor: true, candidate_modifier: Some(|mut candidate: CommittedCandidateReceiptV2| { if candidate.descriptor.para_id() == 1.into() { - // Drop the core selector to make it invalid - candidate - .commitments - .upward_messages - .truncate(candidate.commitments.upward_messages.len() - 1); + // Make the core selector invalid + candidate.commitments.upward_messages[1].truncate(0); } candidate }), diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 329df3a8a9de..9c111c2d28e7 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -45,7 +45,8 @@ use frame_support::{pallet_prelude::*, traits::Defensive}; use frame_system::pallet_prelude::BlockNumberFor; pub use polkadot_core_primitives::v2::BlockNumber; use polkadot_primitives::{ - CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, ValidatorIndex, + CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, SchedulerParams, + ValidatorIndex, }; use sp_runtime::traits::One; @@ -131,7 +132,7 @@ impl Pallet { pub(crate) fn initializer_on_new_session( notification: &SessionChangeNotification>, ) { - let SessionChangeNotification { validators, new_config, prev_config, .. } = notification; + let SessionChangeNotification { validators, new_config, .. } = notification; let config = new_config; let assigner_cores = config.scheduler_params.num_cores; @@ -186,7 +187,7 @@ impl Pallet { } // Resize and populate claim queue. - Self::maybe_resize_claim_queue(prev_config.scheduler_params.num_cores, assigner_cores); + Self::maybe_resize_claim_queue(); Self::populate_claim_queue_after_session_change(); let now = frame_system::Pallet::::block_number() + One::one(); @@ -203,6 +204,12 @@ impl Pallet { ValidatorGroups::::decode_len().unwrap_or(0) } + /// Expected claim queue len. Can be different than the real length if for example we don't have + /// assignments for a core. + fn expected_claim_queue_len(config: &SchedulerParams>) -> u32 { + core::cmp::min(config.num_cores, Self::num_availability_cores() as u32) + } + /// Get the group assigned to a specific core by index at the current block number. Result /// undefined if the core index is unknown or the block number is less than the session start /// index. @@ -325,11 +332,11 @@ impl Pallet { /// and fill the queue from the assignment provider. pub(crate) fn advance_claim_queue(except_for: &BTreeSet) { let config = configuration::ActiveConfig::::get(); - let num_assigner_cores = config.scheduler_params.num_cores; + let expected_claim_queue_len = Self::expected_claim_queue_len(&config.scheduler_params); // Extra sanity, config should already never be smaller than 1: let n_lookahead = config.scheduler_params.lookahead.max(1); - for core_idx in 0..num_assigner_cores { + for core_idx in 0..expected_claim_queue_len { let core_idx = CoreIndex::from(core_idx); if !except_for.contains(&core_idx) { @@ -345,13 +352,16 @@ impl Pallet { } // on new session - fn maybe_resize_claim_queue(old_core_count: u32, new_core_count: u32) { - if new_core_count < old_core_count { + fn maybe_resize_claim_queue() { + let cq = ClaimQueue::::get(); + let Some((old_max_core, _)) = cq.last_key_value() else { return }; + let config = configuration::ActiveConfig::::get(); + let new_core_count = Self::expected_claim_queue_len(&config.scheduler_params); + + if new_core_count < (old_max_core.0 + 1) { ClaimQueue::::mutate(|cq| { - let to_remove: Vec<_> = cq - .range(CoreIndex(new_core_count)..CoreIndex(old_core_count)) - .map(|(k, _)| *k) - .collect(); + let to_remove: Vec<_> = + cq.range(CoreIndex(new_core_count)..=*old_max_core).map(|(k, _)| *k).collect(); for key in to_remove { if let Some(dropped_assignments) = cq.remove(&key) { Self::push_back_to_assignment_provider(dropped_assignments.into_iter()); @@ -367,9 +377,9 @@ impl Pallet { let config = configuration::ActiveConfig::::get(); // Extra sanity, config should already never be smaller than 1: let n_lookahead = config.scheduler_params.lookahead.max(1); - let new_core_count = config.scheduler_params.num_cores; + let expected_claim_queue_len = Self::expected_claim_queue_len(&config.scheduler_params); - for core_idx in 0..new_core_count { + for core_idx in 0..expected_claim_queue_len { let core_idx = CoreIndex::from(core_idx); Self::fill_claim_queue(core_idx, n_lookahead); } diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index 5be7e084f3bc..431562c6e6fb 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -726,8 +726,26 @@ fn session_change_decreasing_number_of_cores() { [assignment_b.clone()].into_iter().collect::>() ); - // No more assignments now. Scheduler::advance_claim_queue(&Default::default()); + // No more assignments now. + assert_eq!(Scheduler::claim_queue_len(), 0); + + // Retain number of cores to 1 but remove all validator groups. The claim queue length + // should be the minimum of these two. + + // Add an assignment. + MockAssigner::add_test_assignment(assignment_b.clone()); + + run_to_block(4, |number| match number { + 4 => Some(SessionChangeNotification { + new_config: new_config.clone(), + prev_config: new_config.clone(), + validators: vec![], + ..Default::default() + }), + _ => None, + }); + assert_eq!(Scheduler::claim_queue_len(), 0); }); } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 3b11c977edf3..e7f463566e3a 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -6,44 +6,51 @@ description = "Rococo testnet Relay Chain runtime." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] +bitvec = { features = ["alloc"], workspace = true } codec = { features = ["derive", "max-encoded-len"], workspace = true } -scale-info = { features = ["derive"], workspace = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { workspace = true } serde_derive = { optional = true, workspace = true } serde_json = { features = ["alloc"], workspace = true } -static_assertions = { workspace = true, default-features = true } smallvec = { workspace = true, default-features = true } -bitvec = { features = ["alloc"], workspace = true } +static_assertions = { workspace = true, default-features = true } +binary-merkle-tree = { workspace = true } +rococo-runtime-constants = { workspace = true } +sp-api = { workspace = true } +sp-arithmetic = { workspace = true } sp-authority-discovery = { workspace = true } +sp-block-builder = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true } sp-consensus-grandpa = { workspace = true } -binary-merkle-tree = { workspace = true } -rococo-runtime-constants = { workspace = true } -sp-api = { workspace = true } +sp-core = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } -sp-offchain = { workspace = true } -sp-arithmetic = { workspace = true } sp-io = { workspace = true } +sp-keyring = { workspace = true } sp-mmr-primitives = { workspace = true } +sp-offchain = { workspace = true } sp-runtime = { workspace = true } -sp-staking = { workspace = true } -sp-core = { workspace = true } sp-session = { workspace = true } +sp-staking = { workspace = true } sp-storage = { workspace = true } -sp-version = { workspace = true } sp-transaction-pool = { workspace = true } -sp-block-builder = { workspace = true } -sp-keyring = { workspace = true } +sp-version = { workspace = true } +frame-executive = { workspace = true } +frame-support = { features = ["tuples-96"], workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-asset-rate = { workspace = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } pallet-babe = { workspace = true } @@ -52,15 +59,10 @@ pallet-beefy = { workspace = true } pallet-beefy-mmr = { workspace = true } pallet-bounties = { workspace = true } pallet-child-bounties = { workspace = true } -pallet-state-trie-migration = { workspace = true } -pallet-transaction-payment = { workspace = true } -pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-collective = { workspace = true } pallet-conviction-voting = { workspace = true } pallet-democracy = { workspace = true } pallet-elections-phragmen = { workspace = true } -pallet-asset-rate = { workspace = true } -frame-executive = { workspace = true } pallet-grandpa = { workspace = true } pallet-identity = { workspace = true } pallet-indices = { workspace = true } @@ -77,48 +79,48 @@ pallet-proxy = { workspace = true } pallet-ranked-collective = { workspace = true } pallet-recovery = { workspace = true } pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true } pallet-society = { workspace = true } -pallet-sudo = { workspace = true } -frame-support = { features = ["tuples-96"], workspace = true } pallet-staking = { workspace = true } -frame-system = { workspace = true } -frame-system-rpc-runtime-api = { workspace = true } +pallet-state-trie-migration = { workspace = true } +pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } pallet-tips = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-treasury = { workspace = true } pallet-utility = { workspace = true } pallet-vesting = { workspace = true } pallet-whitelist = { workspace = true } pallet-xcm = { workspace = true } pallet-xcm-benchmarks = { optional = true, workspace = true } -pallet-root-testing = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-metadata-hash-extension = { workspace = true } -frame-try-runtime = { optional = true, workspace = true } frame-system-benchmarking = { optional = true, workspace = true } +frame-try-runtime = { optional = true, workspace = true } hex-literal = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true } +polkadot-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } polkadot-runtime-parachains = { workspace = true } -polkadot-primitives = { workspace = true } -polkadot-parachain-primitives = { workspace = true } xcm = { workspace = true } -xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } [dev-dependencies] -tiny-keccak = { features = ["keccak"], workspace = true } -sp-keyring = { workspace = true, default-features = true } remote-externalities = { workspace = true, default-features = true } -sp-trie = { workspace = true, default-features = true } separator = { workspace = true } serde_json = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true } +sp-trie = { workspace = true, default-features = true } +tiny-keccak = { features = ["keccak"], workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } [build-dependencies] @@ -275,6 +277,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-executive/try-runtime", diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index 1d0adac44af4..cc62d230d2c0 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -5,6 +5,8 @@ description = "Constants used throughout the Rococo network." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [package.metadata.polkadot-sdk] exclude-from-umbrella = true @@ -18,9 +20,9 @@ smallvec = { workspace = true, default-features = true } frame-support = { workspace = true } polkadot-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } sp-weights = { workspace = true } -sp-core = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } diff --git a/polkadot/runtime/rococo/src/genesis_config_presets.rs b/polkadot/runtime/rococo/src/genesis_config_presets.rs index d609548aed27..a96a509b0e4d 100644 --- a/polkadot/runtime/rococo/src/genesis_config_presets.rs +++ b/polkadot/runtime/rococo/src/genesis_config_presets.rs @@ -23,6 +23,7 @@ use crate::{ #[cfg(not(feature = "std"))] use alloc::format; use alloc::{vec, vec::Vec}; +use frame_support::build_struct_json_patch; use polkadot_primitives::{AccountId, AssignmentId, SchedulerParams, ValidatorId}; use rococo_runtime_constants::currency::UNITS as ROC; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; @@ -128,7 +129,9 @@ fn default_parachains_host_configuration( allowed_ancestry_len: 2, }, node_features: bitvec::vec::BitVec::from_element( - 1u8 << (FeatureIndex::ElasticScalingMVP as usize), + 1u8 << (FeatureIndex::ElasticScalingMVP as usize) | + 1u8 << (FeatureIndex::EnableAssignmentsV2 as usize) | + 1u8 << (FeatureIndex::CandidateReceiptV2 as usize), ), scheduler_params: SchedulerParams { lookahead: 2, @@ -163,7 +166,7 @@ fn rococo_testnet_genesis( const ENDOWMENT: u128 = 1_000_000 * ROC; - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), }, @@ -185,9 +188,8 @@ fn rococo_testnet_genesis( ) }) .collect::>(), - ..Default::default() }, - babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG }, sudo: SudoConfig { key: Some(root_key.clone()) }, configuration: ConfigurationConfig { config: polkadot_runtime_parachains::configuration::HostConfiguration { @@ -198,14 +200,8 @@ fn rococo_testnet_genesis( ..default_parachains_host_configuration() }, }, - registrar: RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + registrar: RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID }, + }) } // staging_testnet @@ -427,7 +423,7 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { const ENDOWMENT: u128 = 1_000_000 * ROC; const STASH: u128 = 100 * ROC; - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -440,19 +436,12 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { .into_iter() .map(|x| (x.0.clone(), x.0, rococo_session_keys(x.2, x.3, x.4, x.5, x.6, x.7))) .collect::>(), - ..Default::default() }, - babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG }, sudo: SudoConfig { key: Some(endowed_accounts[0].clone()) }, configuration: ConfigurationConfig { config: default_parachains_host_configuration() }, - registrar: RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + registrar: RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID }, + }) } //development @@ -490,11 +479,11 @@ fn versi_local_testnet_genesis() -> serde_json::Value { /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => rococo_local_testnet_genesis(), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => rococo_development_config_genesis(), - Ok("staging_testnet") => rococo_staging_testnet_config_genesis(), - Ok("versi_local_testnet") => versi_local_testnet_genesis(), + let patch = match id.as_ref() { + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => rococo_local_testnet_genesis(), + sp_genesis_builder::DEV_RUNTIME_PRESET => rococo_development_config_genesis(), + "staging_testnet" => rococo_staging_testnet_config_genesis(), + "versi_local_testnet" => versi_local_testnet_genesis(), _ => return None, }; Some( diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs index f01440ea02bc..a5cb2eddfa0d 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -163,7 +163,7 @@ where // Poke the deposit to reserve the appropriate amount on the parachain. Transact { origin_kind: OriginKind::Superuser, - require_weight_at_most: remote_weight_limit, + fallback_max_weight: Some(remote_weight_limit), call: poke.encode().into(), }, ]); @@ -171,9 +171,14 @@ where // send let _ = >::send( RawOrigin::Root.into(), - Box::new(VersionedLocation::V4(destination)), - Box::new(VersionedXcm::V4(program)), + Box::new(VersionedLocation::from(destination)), + Box::new(VersionedXcm::from(program)), )?; Ok(()) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_identity_reaping(_: &AccountId, _: u32, _: u32) { + crate::Dmp::make_parachain_reachable(1004); + } } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index e02a28353d29..4034f8bc1431 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -20,6 +20,17 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit. #![recursion_limit = "512"] +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e"))] +// Allocate 2 MiB stack. +// +// TODO: A workaround. Invoke polkavm_derive::min_stack_size!() instead +// later on. +::core::arch::global_asm!( + ".pushsection .polkavm_min_stack_size,\"R\",@note\n", + ".4byte 2097152", + ".popsection\n", +); + extern crate alloc; use alloc::{ @@ -100,7 +111,7 @@ use pallet_session::historical as session_historical; use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo}; use sp_core::{ConstU128, ConstU8, Get, OpaqueMetadata, H256}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, @@ -168,10 +179,10 @@ pub mod fast_runtime_binary { /// Runtime version (Rococo). #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("rococo"), - impl_name: create_runtime_str!("parity-rococo-v2.0"), + spec_name: alloc::borrow::Cow::Borrowed("rococo"), + impl_name: alloc::borrow::Cow::Borrowed("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -767,6 +778,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = MaxSignatories; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -780,6 +792,7 @@ impl pallet_recovery::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type RuntimeCall = RuntimeCall; + type BlockNumberProvider = System; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; @@ -971,6 +984,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } impl parachains_origin::Config for Runtime {} @@ -1661,6 +1675,7 @@ pub mod migrations { pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; /// Weight for balance unreservations pub BalanceUnreserveWeight: Weight = weights::pallet_balances_balances::WeightInfo::::force_unreserve(); + pub BalanceTransferAllowDeath: Weight = weights::pallet_balances_balances::WeightInfo::::transfer_allow_death(); } // Special Config for Gov V1 pallets, allowing us to run migrations for them without @@ -1710,6 +1725,7 @@ pub mod migrations { paras_registrar::migration::MigrateToV1, pallet_referenda::migration::v1::MigrateV0ToV1, pallet_referenda::migration::v1::MigrateV0ToV1, + pallet_child_bounties::migration::MigrateV0ToV1, // Unlock & unreserve Gov1 funds @@ -2435,7 +2451,7 @@ sp_api::impl_runtime_apis! { config: frame_benchmarking::BenchmarkConfig, ) -> Result< Vec, - sp_runtime::RuntimeString, + alloc::string::String, > { use frame_support::traits::WhitelistedStorageKeys; use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; @@ -2467,14 +2483,14 @@ sp_api::impl_runtime_apis! { ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, AssetHubParaId, - (), + Dmp, >, polkadot_runtime_common::xcm_sender::ToParachainDeliveryHelper< XcmConfig, ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, RandomParaId, - (), + Dmp, > ); @@ -2533,7 +2549,7 @@ sp_api::impl_runtime_apis! { ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, AssetHubParaId, - (), + Dmp, >; fn valid_destination() -> Result { Ok(AssetHub::get()) diff --git a/polkadot/runtime/rococo/src/tests.rs b/polkadot/runtime/rococo/src/tests.rs index 01eaad87e342..0b46caec5a35 100644 --- a/polkadot/runtime/rococo/src/tests.rs +++ b/polkadot/runtime/rococo/src/tests.rs @@ -22,7 +22,7 @@ use std::collections::HashSet; use crate::xcm_config::LocationConverter; use frame_support::traits::WhitelistedStorageKeys; use sp_core::{crypto::Ss58Codec, hexdisplay::HexDisplay}; -use sp_keyring::AccountKeyring::Alice; +use sp_keyring::Sr25519Keyring::Alice; use xcm_runtime_apis::conversions::LocationToAccountHelper; #[test] diff --git a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs index 8f8be5f2386f..e1f630ec4ce7 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs @@ -17,25 +17,23 @@ //! Autogenerated weights for `pallet_bounties` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_bounties // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_bounties +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -63,11 +61,11 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `210` // Estimated: `3593` - // Minimum execution time: 21_772_000 picoseconds. - Weight::from_parts(22_861_341, 0) + // Minimum execution time: 26_614_000 picoseconds. + Weight::from_parts(28_274_660, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(721, 0).saturating_mul(d.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(779, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -79,8 +77,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `302` // Estimated: `3642` - // Minimum execution time: 11_218_000 picoseconds. - Weight::from_parts(11_796_000, 0) + // Minimum execution time: 14_692_000 picoseconds. + Weight::from_parts(15_070_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -91,22 +89,36 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `322` // Estimated: `3642` - // Minimum execution time: 10_959_000 picoseconds. - Weight::from_parts(11_658_000, 0) + // Minimum execution time: 13_695_000 picoseconds. + Weight::from_parts(14_220_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyApprovals` (r:1 w:1) + /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn approve_bounty_with_curator() -> Weight { + // Proof Size summary in bytes: + // Measured: `322` + // Estimated: `3642` + // Minimum execution time: 18_428_000 picoseconds. + Weight::from_parts(19_145_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `3642` - // Minimum execution time: 37_419_000 picoseconds. - Weight::from_parts(38_362_000, 0) + // Minimum execution time: 44_648_000 picoseconds. + Weight::from_parts(45_860_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -119,8 +131,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `494` // Estimated: `3642` - // Minimum execution time: 27_328_000 picoseconds. - Weight::from_parts(27_661_000, 0) + // Minimum execution time: 33_973_000 picoseconds. + Weight::from_parts(34_979_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -133,8 +145,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `400` // Estimated: `3642` - // Minimum execution time: 16_067_000 picoseconds. - Weight::from_parts(16_865_000, 0) + // Minimum execution time: 20_932_000 picoseconds. + Weight::from_parts(21_963_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -151,8 +163,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `764` // Estimated: `8799` - // Minimum execution time: 101_153_000 picoseconds. - Weight::from_parts(102_480_000, 0) + // Minimum execution time: 114_942_000 picoseconds. + Weight::from_parts(117_653_000, 0) .saturating_add(Weight::from_parts(0, 8799)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(6)) @@ -169,8 +181,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `444` // Estimated: `3642` - // Minimum execution time: 38_838_000 picoseconds. - Weight::from_parts(39_549_000, 0) + // Minimum execution time: 47_649_000 picoseconds. + Weight::from_parts(49_016_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -187,8 +199,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `680` // Estimated: `6196` - // Minimum execution time: 68_592_000 picoseconds. - Weight::from_parts(70_727_000, 0) + // Minimum execution time: 80_298_000 picoseconds. + Weight::from_parts(82_306_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) @@ -199,8 +211,8 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `358` // Estimated: `3642` - // Minimum execution time: 11_272_000 picoseconds. - Weight::from_parts(11_592_000, 0) + // Minimum execution time: 14_237_000 picoseconds. + Weight::from_parts(14_969_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -216,11 +228,11 @@ impl pallet_bounties::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + b * (297 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 2_844_000 picoseconds. - Weight::from_parts(2_900_000, 0) + // Minimum execution time: 3_174_000 picoseconds. + Weight::from_parts(3_336_000, 0) .saturating_add(Weight::from_parts(0, 1887)) - // Standard Error: 9_467 - .saturating_add(Weight::from_parts(32_326_595, 0).saturating_mul(b.into())) + // Standard Error: 10_408 + .saturating_add(Weight::from_parts(37_811_366, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index d5cf33515e6b..b60165934f92 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,27 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `65a7f4d3191f`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet +// --extrinsic=* // --chain=rococo-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights +// --wasm-execution=compiled // --steps=50 // --repeat=20 +// --heap-pages=4096 // --no-storage-info -// --no-median-slopes // --no-min-squares -// --pallet=pallet_xcm -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,38 +56,46 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 25_521_000 picoseconds. - Weight::from_parts(25_922_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `245` + // Estimated: `3710` + // Minimum execution time: 37_787_000 picoseconds. + Weight::from_parts(39_345_000, 0) + .saturating_add(Weight::from_parts(0, 3710)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 112_185_000 picoseconds. - Weight::from_parts(115_991_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `245` + // Estimated: `3710` + // Minimum execution time: 138_755_000 picoseconds. + Weight::from_parts(142_908_000, 0) + .saturating_add(Weight::from_parts(0, 3710)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) @@ -96,45 +104,54 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `232` - // Estimated: `3697` - // Minimum execution time: 108_693_000 picoseconds. - Weight::from_parts(111_853_000, 0) - .saturating_add(Weight::from_parts(0, 3697)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `297` + // Estimated: `3762` + // Minimum execution time: 134_917_000 picoseconds. + Weight::from_parts(138_809_000, 0) + .saturating_add(Weight::from_parts(0, 3762)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 113_040_000 picoseconds. - Weight::from_parts(115_635_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `245` + // Estimated: `3710` + // Minimum execution time: 141_303_000 picoseconds. + Weight::from_parts(144_640_000, 0) + .saturating_add(Weight::from_parts(0, 3710)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_979_000 picoseconds. - Weight::from_parts(7_342_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Estimated: `1485` + // Minimum execution time: 9_872_000 picoseconds. + Weight::from_parts(10_402_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -142,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_144_000 picoseconds. - Weight::from_parts(7_297_000, 0) + // Minimum execution time: 8_312_000 picoseconds. + Weight::from_parts(8_867_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -151,8 +168,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_886_000 picoseconds. - Weight::from_parts(1_995_000, 0) + // Minimum execution time: 2_524_000 picoseconds. + Weight::from_parts(2_800_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -165,18 +182,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::Queries` (r:0 w:1) /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 31_238_000 picoseconds. - Weight::from_parts(31_955_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `245` + // Estimated: `3710` + // Minimum execution time: 45_426_000 picoseconds. + Weight::from_parts(48_021_000, 0) + .saturating_add(Weight::from_parts(0, 3710)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -187,18 +206,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::Queries` (r:0 w:1) /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `360` - // Estimated: `3825` - // Minimum execution time: 37_237_000 picoseconds. - Weight::from_parts(38_569_000, 0) - .saturating_add(Weight::from_parts(0, 3825)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `425` + // Estimated: `3890` + // Minimum execution time: 50_854_000 picoseconds. + Weight::from_parts(52_044_000, 0) + .saturating_add(Weight::from_parts(0, 3890)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `XcmPallet::XcmExecutionSuspended` (r:0 w:1) @@ -207,45 +228,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_884_000 picoseconds. - Weight::from_parts(2_028_000, 0) + // Minimum execution time: 2_566_000 picoseconds. + Weight::from_parts(2_771_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmPallet::SupportedVersion` (r:5 w:2) + /// Storage: `XcmPallet::SupportedVersion` (r:6 w:2) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `22` - // Estimated: `13387` - // Minimum execution time: 16_048_000 picoseconds. - Weight::from_parts(16_617_000, 0) - .saturating_add(Weight::from_parts(0, 13387)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15862` + // Minimum execution time: 21_854_000 picoseconds. + Weight::from_parts(22_528_000, 0) + .saturating_add(Weight::from_parts(0, 15862)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifiers` (r:5 w:2) + /// Storage: `XcmPallet::VersionNotifiers` (r:6 w:2) /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `26` - // Estimated: `13391` - // Minimum execution time: 16_073_000 picoseconds. - Weight::from_parts(16_672_000, 0) - .saturating_add(Weight::from_parts(0, 13391)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15866` + // Minimum execution time: 21_821_000 picoseconds. + Weight::from_parts(22_368_000, 0) + .saturating_add(Weight::from_parts(0, 15866)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:7 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `40` - // Estimated: `15880` - // Minimum execution time: 18_422_000 picoseconds. - Weight::from_parts(18_900_000, 0) - .saturating_add(Weight::from_parts(0, 15880)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18355` + // Minimum execution time: 25_795_000 picoseconds. + Weight::from_parts(26_284_000, 0) + .saturating_add(Weight::from_parts(0, 18355)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `XcmPallet::VersionNotifyTargets` (r:2 w:1) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -253,62 +274,62 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:0) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `216` - // Estimated: `6156` - // Minimum execution time: 30_373_000 picoseconds. - Weight::from_parts(30_972_000, 0) - .saturating_add(Weight::from_parts(0, 6156)) + // Measured: `244` + // Estimated: `6184` + // Minimum execution time: 33_182_000 picoseconds. + Weight::from_parts(34_506_000, 0) + .saturating_add(Weight::from_parts(0, 6184)) .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `10959` - // Minimum execution time: 11_863_000 picoseconds. - Weight::from_parts(12_270_000, 0) - .saturating_add(Weight::from_parts(0, 10959)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `40` + // Estimated: `13405` + // Minimum execution time: 17_573_000 picoseconds. + Weight::from_parts(18_154_000, 0) + .saturating_add(Weight::from_parts(0, 13405)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:2) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `33` - // Estimated: `13398` - // Minimum execution time: 16_733_000 picoseconds. - Weight::from_parts(17_094_000, 0) - .saturating_add(Weight::from_parts(0, 13398)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15873` + // Minimum execution time: 22_491_000 picoseconds. + Weight::from_parts(22_793_000, 0) + .saturating_add(Weight::from_parts(0, 15873)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:1) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:0) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `216` - // Estimated: `13581` - // Minimum execution time: 39_236_000 picoseconds. - Weight::from_parts(40_587_000, 0) - .saturating_add(Weight::from_parts(0, 13581)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `244` + // Estimated: `16084` + // Minimum execution time: 44_441_000 picoseconds. + Weight::from_parts(45_782_000, 0) + .saturating_add(Weight::from_parts(0, 16084)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -318,8 +339,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_145_000 picoseconds. - Weight::from_parts(2_255_000, 0) + // Minimum execution time: 2_809_000 picoseconds. + Weight::from_parts(2_960_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -330,22 +351,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_518_000 picoseconds. - Weight::from_parts(22_926_000, 0) + // Minimum execution time: 26_248_000 picoseconds. + Weight::from_parts(26_996_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `23` // Estimated: `3488` - // Minimum execution time: 34_438_000 picoseconds. - Weight::from_parts(35_514_000, 0) + // Minimum execution time: 40_299_000 picoseconds. + Weight::from_parts(41_396_000, 0) .saturating_add(Weight::from_parts(0, 3488)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs index b62f36172baf..1595a6dfbe4b 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs @@ -344,4 +344,11 @@ impl pallet_xcm_benchmarks::generic::WeightInfo for Wei Weight::from_parts(1_354_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 713_000 picoseconds. + Weight::from_parts(776_000, 0) + } } diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs index bd2b0fbb8c06..eb27e5c5a897 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs @@ -24,6 +24,8 @@ use xcm::{latest::prelude::*, DoubleEncoded}; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; +use sp_runtime::BoundedVec; +use xcm::latest::AssetTransferFilter; /// Types of asset supported by the Rococo runtime. pub enum AssetTypes { @@ -112,7 +114,7 @@ impl XcmWeightInfo for RococoXcmWeight { } fn transact( _origin_kind: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -163,12 +165,35 @@ impl XcmWeightInfo for RococoXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmBalancesWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmBalancesWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmBalancesWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -266,6 +291,20 @@ impl XcmWeightInfo for RococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } #[test] diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 7d743b209124..c1d5c3fc89d9 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 30_672_000 picoseconds. - Weight::from_parts(31_677_000, 3593) + // Minimum execution time: 32_017_000 picoseconds. + Weight::from_parts(32_841_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +66,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 41_132_000 picoseconds. - Weight::from_parts(41_654_000, 6196) + // Minimum execution time: 42_570_000 picoseconds. + Weight::from_parts(43_526_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -85,8 +85,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `281` // Estimated: `6196` - // Minimum execution time: 97_174_000 picoseconds. - Weight::from_parts(99_537_000, 6196) + // Minimum execution time: 103_020_000 picoseconds. + Weight::from_parts(104_906_000, 6196) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -113,8 +113,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `281` // Estimated: `3746` - // Minimum execution time: 67_105_000 picoseconds. - Weight::from_parts(68_659_000, 3746) + // Minimum execution time: 70_944_000 picoseconds. + Weight::from_parts(73_630_000, 3746) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -124,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 30_780_000 picoseconds. - Weight::from_parts(31_496_000, 3593) + // Minimum execution time: 31_979_000 picoseconds. + Weight::from_parts(32_649_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -135,8 +135,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 23_411_000 picoseconds. - Weight::from_parts(23_891_000, 3593) + // Minimum execution time: 24_462_000 picoseconds. + Weight::from_parts(25_052_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -154,8 +154,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 61_541_000 picoseconds. - Weight::from_parts(63_677_000, 3645) + // Minimum execution time: 65_047_000 picoseconds. + Weight::from_parts(67_225_000, 3645) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -173,8 +173,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 48_574_000 picoseconds. - Weight::from_parts(49_469_000, 3645) + // Minimum execution time: 53_401_000 picoseconds. + Weight::from_parts(55_155_000, 3645) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub(crate) fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 82_584_000 picoseconds. + Weight::from_parts(84_614_000, 3645) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index df2f9b2d0e8d..2dc8880c8326 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -16,28 +16,27 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-11-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-vcatxqpx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet // --steps=50 // --repeat=20 // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::generic // --chain=rococo-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/rococo/src/weights/xcm/ +// --header=./polkadot/file_header.txt +// --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs +// --output=./polkadot/runtime/rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,130 +49,139 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 36_305_000 picoseconds. - Weight::from_parts(37_096_000, 4030) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 65_164_000 picoseconds. + Weight::from_parts(66_965_000, 3746) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } pub(crate) fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_831_000 picoseconds. - Weight::from_parts(2_904_000, 0) + // Minimum execution time: 675_000 picoseconds. + Weight::from_parts(745_000, 0) } - /// Storage: XcmPallet Queries (r:1 w:0) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + pub(crate) fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_899_000 picoseconds. + Weight::from_parts(3_090_000, 0) + } + pub(crate) fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(714_000, 0) + } + /// Storage: `XcmPallet::Queries` (r:1 w:0) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn query_response() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 11_769_000 picoseconds. - Weight::from_parts(12_122_000, 3634) + // Measured: `0` + // Estimated: `3465` + // Minimum execution time: 6_004_000 picoseconds. + Weight::from_parts(6_152_000, 3465) .saturating_add(T::DbWeight::get().reads(1)) } pub(crate) fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_293_000 picoseconds. - Weight::from_parts(12_522_000, 0) + // Minimum execution time: 7_296_000 picoseconds. + Weight::from_parts(7_533_000, 0) } pub(crate) fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_858_000 picoseconds. - Weight::from_parts(2_965_000, 0) + // Minimum execution time: 1_292_000 picoseconds. + Weight::from_parts(1_414_000, 0) } pub(crate) fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_623_000 picoseconds. - Weight::from_parts(2_774_000, 0) + // Minimum execution time: 741_000 picoseconds. + Weight::from_parts(775_000, 0) } pub(crate) fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_664_000 picoseconds. - Weight::from_parts(2_752_000, 0) + // Minimum execution time: 702_000 picoseconds. + Weight::from_parts(770_000, 0) } pub(crate) fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_646_000 picoseconds. - Weight::from_parts(2_709_000, 0) + // Minimum execution time: 648_000 picoseconds. + Weight::from_parts(744_000, 0) } pub(crate) fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_602_000 picoseconds. - Weight::from_parts(3_669_000, 0) + // Minimum execution time: 731_000 picoseconds. + Weight::from_parts(772_000, 0) + } + pub(crate) fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 790_000 picoseconds. + Weight::from_parts(843_000, 0) } pub(crate) fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_609_000 picoseconds. - Weight::from_parts(2_721_000, 0) + // Minimum execution time: 647_000 picoseconds. + Weight::from_parts(731_000, 0) } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 31_776_000 picoseconds. - Weight::from_parts(32_354_000, 4030) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 62_808_000 picoseconds. + Weight::from_parts(64_413_000, 3746) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: XcmPallet AssetTraps (r:1 w:1) - /// Proof Skipped: XcmPallet AssetTraps (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) + /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn claim_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `226` - // Estimated: `3691` - // Minimum execution time: 15_912_000 picoseconds. - Weight::from_parts(16_219_000, 3691) + // Measured: `23` + // Estimated: `3488` + // Minimum execution time: 9_298_000 picoseconds. + Weight::from_parts(9_541_000, 3488) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -181,171 +189,151 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_704_000 picoseconds. - Weight::from_parts(2_777_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(732_000, 0) } - /// Storage: XcmPallet VersionNotifyTargets (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 38_690_000 picoseconds. - Weight::from_parts(39_157_000, 4030) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 30_585_000 picoseconds. + Weight::from_parts(31_622_000, 3645) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: XcmPallet VersionNotifyTargets (r:0 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn unsubscribe_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_943_000 picoseconds. - Weight::from_parts(5_128_000, 0) + // Minimum execution time: 3_036_000 picoseconds. + Weight::from_parts(3_196_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub(crate) fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_438_000 picoseconds. - Weight::from_parts(6_500_000, 0) + // Minimum execution time: 1_035_000 picoseconds. + Weight::from_parts(1_133_000, 0) } pub(crate) fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_773_000 picoseconds. - Weight::from_parts(4_840_000, 0) + // Minimum execution time: 764_000 picoseconds. + Weight::from_parts(802_000, 0) } pub(crate) fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_818_000 picoseconds. - Weight::from_parts(2_893_000, 0) + // Minimum execution time: 682_000 picoseconds. + Weight::from_parts(724_000, 0) } pub(crate) fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_611_000 picoseconds. - Weight::from_parts(2_708_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(713_000, 0) } pub(crate) fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_870_000 picoseconds. - Weight::from_parts(2_958_000, 0) + // Minimum execution time: 857_000 picoseconds. + Weight::from_parts(917_000, 0) } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 40_735_000 picoseconds. - Weight::from_parts(66_023_000, 4030) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 72_331_000 picoseconds. + Weight::from_parts(74_740_000, 3746) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } pub(crate) fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_293_000 picoseconds. - Weight::from_parts(18_088_000, 0) + // Minimum execution time: 8_963_000 picoseconds. + Weight::from_parts(9_183_000, 0) } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `565` - // Estimated: `4030` - // Minimum execution time: 31_438_000 picoseconds. - Weight::from_parts(32_086_000, 4030) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 62_555_000 picoseconds. + Weight::from_parts(64_824_000, 3746) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } pub(crate) fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_676_000 picoseconds. - Weight::from_parts(2_746_000, 0) + // Minimum execution time: 740_000 picoseconds. + Weight::from_parts(773_000, 0) } pub(crate) fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_629_000 picoseconds. - Weight::from_parts(2_724_000, 0) + // Minimum execution time: 678_000 picoseconds. + Weight::from_parts(714_000, 0) } pub(crate) fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_602_000 picoseconds. - Weight::from_parts(2_671_000, 0) + // Minimum execution time: 656_000 picoseconds. + Weight::from_parts(703_000, 0) } pub(crate) fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_681_000 picoseconds. - Weight::from_parts(2_768_000, 0) + // Minimum execution time: 672_000 picoseconds. + Weight::from_parts(725_000, 0) } pub(crate) fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_764_000 picoseconds. - Weight::from_parts(2_865_000, 0) + // Minimum execution time: 798_000 picoseconds. + Weight::from_parts(845_000, 0) } } diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 05e0ee64820a..82a3136cc0d9 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -35,7 +35,7 @@ use polkadot_runtime_common::{ }; use rococo_runtime_constants::{currency::CENTS, system_parachain::*}; use sp_core::ConstU32; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, @@ -51,7 +51,7 @@ use xcm_executor::XcmExecutor; parameter_types! { pub TokenLocation: Location = Here.into_location(); pub RootLocation: Location = Location::here(); - pub const ThisNetwork: NetworkId = NetworkId::Rococo; + pub const ThisNetwork: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH); pub UniversalLocation: InteriorLocation = ThisNetwork::get().into(); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 90a0285cd17b..f35bb53ac904 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -16,59 +16,59 @@ log = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { workspace = true } +frame-election-provider-support = { workspace = true } +sp-api = { workspace = true } sp-authority-discovery = { workspace = true } +sp-block-builder = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true } -sp-api = { workspace = true } -sp-inherents = { workspace = true } -sp-offchain = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } -sp-staking = { workspace = true } sp-core = { workspace = true } sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } sp-mmr-primitives = { workspace = true } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } sp-session = { workspace = true } -sp-version = { workspace = true } -frame-election-provider-support = { workspace = true } +sp-staking = { workspace = true } sp-transaction-pool = { workspace = true } -sp-block-builder = { workspace = true } +sp-version = { workspace = true } +frame-executive = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } pallet-babe = { workspace = true } pallet-balances = { workspace = true } -pallet-transaction-payment = { workspace = true } -pallet-transaction-payment-rpc-runtime-api = { workspace = true } -frame-executive = { workspace = true } pallet-grandpa = { workspace = true } pallet-indices = { workspace = true } pallet-offences = { workspace = true } pallet-session = { workspace = true } -frame-support = { workspace = true } pallet-staking = { workspace = true } pallet-staking-reward-curve = { workspace = true, default-features = true } -frame-system = { workspace = true } -frame-system-rpc-runtime-api = { workspace = true } -test-runtime-constants = { workspace = true } -pallet-timestamp = { workspace = true } pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-vesting = { workspace = true } +test-runtime-constants = { workspace = true } -polkadot-runtime-common = { workspace = true } -polkadot-primitives = { workspace = true } pallet-xcm = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } polkadot-runtime-parachains = { workspace = true } +xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } -xcm = { workspace = true } [dev-dependencies] hex-literal = { workspace = true, default-features = true } -tiny-keccak = { features = ["keccak"], workspace = true } +serde_json = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } +tiny-keccak = { features = ["keccak"], workspace = true } [build-dependencies] substrate-wasm-builder = { workspace = true, default-features = true } @@ -154,4 +154,5 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 9e7ee488af72..d4031f7ac57a 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -80,7 +80,6 @@ use sp_consensus_beefy::ecdsa_crypto::{AuthorityId as BeefyId, Signature as Beef use sp_core::{ConstU32, OpaqueMetadata}; use sp_mmr_primitives as mmr; use sp_runtime::{ - create_runtime_str, curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ @@ -94,7 +93,7 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::v4::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, XcmHash}; +use xcm::latest::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, XcmHash}; pub use pallet_balances::Call as BalancesCall; #[cfg(feature = "std")] @@ -119,8 +118,8 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); /// Runtime version (Test). #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("polkadot-test-runtime"), - impl_name: create_runtime_str!("parity-polkadot-test-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("polkadot-test-runtime"), + impl_name: alloc::borrow::Cow::Borrowed("parity-polkadot-test-runtime"), authoring_version: 2, spec_version: 1056, impl_version: 0, @@ -396,7 +395,7 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = polkadot_runtime_common::StakingBenchmarkingConfig; type EventListeners = (); type WeightInfo = (); - type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; } parameter_types! { @@ -641,7 +640,7 @@ impl SendXcm for DummyXcmSender { type Ticket = (); fn validate( _: &mut Option, - _: &mut Option>, + _: &mut Option>, ) -> SendResult { Ok(((), Assets::new())) } diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index f94301baab09..e945e64e7fc0 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -6,6 +6,8 @@ description = "Westend testnet Relay Chain runtime." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -13,36 +15,36 @@ workspace = true [dependencies] bitvec = { features = ["alloc"], workspace = true } codec = { features = ["derive", "max-encoded-len"], workspace = true } -scale-info = { features = ["derive"], workspace = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { workspace = true } serde_derive = { optional = true, workspace = true } serde_json = { features = ["alloc"], workspace = true } smallvec = { workspace = true, default-features = true } -sp-authority-discovery = { workspace = true } -sp-consensus-babe = { workspace = true } -sp-consensus-beefy = { workspace = true } -sp-consensus-grandpa = { workspace = true } binary-merkle-tree = { workspace = true } -sp-inherents = { workspace = true } -sp-offchain = { workspace = true } sp-api = { workspace = true } sp-application-crypto = { workspace = true } sp-arithmetic = { workspace = true } +sp-authority-discovery = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-babe = { workspace = true } +sp-consensus-beefy = { workspace = true } +sp-consensus-grandpa = { workspace = true } +sp-core = { workspace = true } sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } sp-io = { workspace = true } +sp-keyring = { workspace = true } sp-mmr-primitives = { workspace = true } +sp-npos-elections = { workspace = true } +sp-offchain = { workspace = true } sp-runtime = { workspace = true } -sp-staking = { workspace = true } -sp-core = { workspace = true } sp-session = { workspace = true } +sp-staking = { workspace = true } sp-storage = { workspace = true } -sp-version = { workspace = true } sp-transaction-pool = { workspace = true } -sp-block-builder = { workspace = true } -sp-npos-elections = { workspace = true } -sp-keyring = { workspace = true } +sp-version = { workspace = true } frame-election-provider-support = { workspace = true } frame-executive = { workspace = true } @@ -50,7 +52,6 @@ frame-metadata-hash-extension = { workspace = true } frame-support = { features = ["experimental", "tuples-96"], workspace = true } frame-system = { workspace = true } frame-system-rpc-runtime-api = { workspace = true } -westend-runtime-constants = { workspace = true } pallet-asset-rate = { workspace = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } @@ -60,9 +61,11 @@ pallet-balances = { workspace = true } pallet-beefy = { workspace = true } pallet-beefy-mmr = { workspace = true } pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-delegated-staking = { workspace = true } pallet-democracy = { workspace = true } -pallet-elections-phragmen = { workspace = true } pallet-election-provider-multi-phase = { workspace = true } +pallet-elections-phragmen = { workspace = true } pallet-fast-unstake = { workspace = true } pallet-grandpa = { workspace = true } pallet-identity = { workspace = true } @@ -73,60 +76,59 @@ pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nomination-pools = { workspace = true } -pallet-conviction-voting = { workspace = true } +pallet-nomination-pools-runtime-api = { workspace = true } pallet-offences = { workspace = true } pallet-parameters = { workspace = true } pallet-preimage = { workspace = true } pallet-proxy = { workspace = true } pallet-recovery = { workspace = true } pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true } pallet-society = { workspace = true } pallet-staking = { workspace = true } pallet-staking-runtime-api = { workspace = true } -pallet-delegated-staking = { workspace = true } pallet-state-trie-migration = { workspace = true } pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } -pallet-nomination-pools-runtime-api = { workspace = true } pallet-treasury = { workspace = true } pallet-utility = { workspace = true } pallet-vesting = { workspace = true } pallet-whitelist = { workspace = true } pallet-xcm = { workspace = true } pallet-xcm-benchmarks = { optional = true, workspace = true } -pallet-root-testing = { workspace = true } +westend-runtime-constants = { workspace = true } frame-benchmarking = { optional = true, workspace = true } -frame-try-runtime = { optional = true, workspace = true } frame-system-benchmarking = { optional = true, workspace = true } +frame-try-runtime = { optional = true, workspace = true } +hex-literal = { workspace = true, default-features = true } pallet-election-provider-support-benchmarking = { optional = true, workspace = true } pallet-nomination-pools-benchmarking = { optional = true, workspace = true } pallet-offences-benchmarking = { optional = true, workspace = true } pallet-session-benchmarking = { optional = true, workspace = true } -hex-literal = { workspace = true, default-features = true } -polkadot-runtime-common = { workspace = true } -polkadot-primitives = { workspace = true } polkadot-parachain-primitives = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } polkadot-runtime-parachains = { workspace = true } xcm = { workspace = true } -xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } [dev-dependencies] approx = { workspace = true } -tiny-keccak = { features = ["keccak"], workspace = true } -sp-keyring = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } remote-externalities = { workspace = true, default-features = true } -tokio = { features = ["macros"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true } +tiny-keccak = { features = ["keccak"], workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } [build-dependencies] substrate-wasm-builder = { workspace = true, default-features = true } @@ -296,6 +298,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index 27d5b19b8e77..f3dbcc309ee1 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -5,6 +5,8 @@ description = "Constants used throughout the Westend network." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [package.metadata.polkadot-sdk] exclude-from-umbrella = true @@ -18,9 +20,9 @@ smallvec = { workspace = true, default-features = true } frame-support = { workspace = true } polkadot-primitives = { workspace = true } polkadot-runtime-common = { workspace = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } sp-weights = { workspace = true } -sp-core = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } diff --git a/polkadot/runtime/westend/src/genesis_config_presets.rs b/polkadot/runtime/westend/src/genesis_config_presets.rs index a9e22898ddb4..ea5aff554e8c 100644 --- a/polkadot/runtime/westend/src/genesis_config_presets.rs +++ b/polkadot/runtime/westend/src/genesis_config_presets.rs @@ -133,7 +133,8 @@ fn default_parachains_host_configuration( }, node_features: bitvec::vec::BitVec::from_element( 1u8 << (FeatureIndex::ElasticScalingMVP as usize) | - 1u8 << (FeatureIndex::EnableAssignmentsV2 as usize), + 1u8 << (FeatureIndex::EnableAssignmentsV2 as usize) | + 1u8 << (FeatureIndex::CandidateReceiptV2 as usize), ), scheduler_params: SchedulerParams { lookahead: 2, @@ -222,7 +223,7 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { // // SECRET_SEED="slow awkward present example safe bundle science ocean cradle word tennis earn" // subkey inspect -n polkadot "$SECRET_SEED" - let endowed_accounts = vec![ + let endowed_accounts: Vec = vec![ // 15S75FkhCWEowEGfxWwVfrW3LQuy8w8PNhVmrzfsVhCMjUh1 hex!["c416837e232d9603e83162ef4bda08e61580eeefe60fe92fc044aa508559ae42"].into(), ]; @@ -338,7 +339,7 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { const ENDOWMENT: u128 = 1_000_000 * WND; const STASH: u128 = 100 * WND; - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -364,7 +365,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { ) }) .collect::>(), - ..Default::default() }, staking: StakingConfig { validator_count: 50, @@ -376,19 +376,12 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), force_era: Forcing::ForceNone, slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() }, - babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG }, sudo: SudoConfig { key: Some(endowed_accounts[0].clone()) }, configuration: ConfigurationConfig { config: default_parachains_host_configuration() }, - registrar: RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + registrar: RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID }, + }) } //development @@ -411,10 +404,10 @@ fn westend_local_testnet_genesis() -> serde_json::Value { /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => westend_local_testnet_genesis(), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => westend_development_config_genesis(), - Ok("staging_testnet") => westend_staging_testnet_config_genesis(), + let patch = match id.as_ref() { + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => westend_local_testnet_genesis(), + sp_genesis_builder::DEV_RUNTIME_PRESET => westend_development_config_genesis(), + "staging_testnet" => westend_staging_testnet_config_genesis(), _ => return None, }; Some( diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs index ac3f9e679f8d..0e0d345a0ed4 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -163,17 +163,22 @@ where // Poke the deposit to reserve the appropriate amount on the parachain. Transact { origin_kind: OriginKind::Superuser, - require_weight_at_most: remote_weight_limit, call: poke.encode().into(), + fallback_max_weight: Some(remote_weight_limit), }, ]); // send let _ = >::send( RawOrigin::Root.into(), - Box::new(VersionedLocation::V4(destination)), - Box::new(VersionedXcm::V4(program)), + Box::new(VersionedLocation::from(destination)), + Box::new(VersionedXcm::from(program)), )?; Ok(()) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_identity_reaping(_: &AccountId, _: u32, _: u32) { + crate::Dmp::make_parachain_reachable(1004); + } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 251d92b03bbb..cd8eb4d2505a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -46,6 +46,7 @@ use frame_support::{ use frame_system::{EnsureRoot, EnsureSigned}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; +use pallet_nomination_pools::PoolId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo}; use polkadot_primitives::{ @@ -95,7 +96,7 @@ use sp_consensus_beefy::{ }; use sp_core::{ConstU8, OpaqueMetadata, RuntimeDebug, H256}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{ AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, @@ -168,13 +169,13 @@ pub mod fast_runtime_binary { /// Runtime version (Westend). #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("westend"), - impl_name: create_runtime_str!("parity-westend"), + spec_name: alloc::borrow::Cow::Borrowed("westend"), + impl_name: alloc::borrow::Cow::Borrowed("parity-westend"), authoring_version: 2, - spec_version: 1_016_001, + spec_version: 1_017_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 26, + transaction_version: 27, system_version: 1, }; @@ -542,7 +543,7 @@ impl Get for MaybeSignedPhase { fn get() -> u32 { // 1 day = 4 eras -> 1 week = 28 eras. We want to disable signed phase once a week to test // the fallback unsigned phase is able to compute elections on Westend. - if Staking::current_era().unwrap_or(1) % 28 == 0 { + if pallet_staking::CurrentEra::::get().unwrap_or(1) % 28 == 0 { 0 } else { SignedPhase::get() @@ -754,7 +755,7 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = polkadot_runtime_common::StakingBenchmarkingConfig; type EventListeners = (NominationPools, DelegatedStaking); type WeightInfo = weights::pallet_staking::WeightInfo; - type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; } impl pallet_fast_unstake::Config for Runtime { @@ -1003,6 +1004,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = MaxSignatories; type WeightInfo = weights::pallet_multisig::WeightInfo; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -1016,6 +1018,7 @@ impl pallet_recovery::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type RuntimeCall = RuntimeCall; + type BlockNumberProvider = System; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; @@ -1203,6 +1206,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } impl parachains_origin::Config for Runtime {} @@ -1837,6 +1841,7 @@ pub mod migrations { >, parachains_shared::migration::MigrateToV1, parachains_scheduler::migration::MigrateV2ToV3, + pallet_staking::migrations::v16::MigrateV15ToV16, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -2494,15 +2499,15 @@ sp_api::impl_runtime_apis! { NominationPools::api_pending_rewards(member).unwrap_or_default() } - fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { + fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance { NominationPools::api_points_to_balance(pool_id, points) } - fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { + fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance { NominationPools::api_balance_to_points(pool_id, new_funds) } - fn pool_pending_slash(pool_id: pallet_nomination_pools::PoolId) -> Balance { + fn pool_pending_slash(pool_id: PoolId) -> Balance { NominationPools::api_pool_pending_slash(pool_id) } @@ -2510,7 +2515,7 @@ sp_api::impl_runtime_apis! { NominationPools::api_member_pending_slash(member) } - fn pool_needs_delegate_migration(pool_id: pallet_nomination_pools::PoolId) -> bool { + fn pool_needs_delegate_migration(pool_id: PoolId) -> bool { NominationPools::api_pool_needs_delegate_migration(pool_id) } @@ -2522,9 +2527,13 @@ sp_api::impl_runtime_apis! { NominationPools::api_member_total_balance(member) } - fn pool_balance(pool_id: pallet_nomination_pools::PoolId) -> Balance { + fn pool_balance(pool_id: PoolId) -> Balance { NominationPools::api_pool_balance(pool_id) } + + fn pool_accounts(pool_id: PoolId) -> (AccountId, AccountId) { + NominationPools::api_pool_accounts(pool_id) + } } impl pallet_staking_runtime_api::StakingApi for Runtime { @@ -2592,7 +2601,7 @@ sp_api::impl_runtime_apis! { config: frame_benchmarking::BenchmarkConfig, ) -> Result< Vec, - sp_runtime::RuntimeString, + alloc::string::String, > { use frame_support::traits::WhitelistedStorageKeys; use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; @@ -2631,14 +2640,14 @@ sp_api::impl_runtime_apis! { ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, AssetHubParaId, - (), + Dmp, >, polkadot_runtime_common::xcm_sender::ToParachainDeliveryHelper< xcm_config::XcmConfig, ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, RandomParaId, - (), + Dmp, > ); @@ -2704,7 +2713,7 @@ sp_api::impl_runtime_apis! { ExistentialDepositAsset, xcm_config::PriceForChildParachainDelivery, AssetHubParaId, - (), + Dmp, >; fn valid_destination() -> Result { Ok(AssetHub::get()) @@ -2793,8 +2802,9 @@ sp_api::impl_runtime_apis! { } fn alias_origin() -> Result<(Location, Location), BenchmarkError> { - // The XCM executor of Westend doesn't have a configured `Aliasers` - Err(BenchmarkError::Skip) + let origin = Location::new(0, [Parachain(1000)]); + let target = Location::new(0, [Parachain(1000), AccountId32 { id: [128u8; 32], network: None }]); + Ok((origin, target)) } } diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 02fd6b61496b..fcdaf7ff2de6 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -23,7 +23,7 @@ use approx::assert_relative_eq; use frame_support::traits::WhitelistedStorageKeys; use pallet_staking::EraPayout; use sp_core::{crypto::Ss58Codec, hexdisplay::HexDisplay}; -use sp_keyring::AccountKeyring::Alice; +use sp_keyring::Sr25519Keyring::Alice; use xcm_runtime_apis::conversions::LocationToAccountHelper; const MILLISECONDS_PER_HOUR: u64 = 60 * 60 * 1000; diff --git a/polkadot/runtime/westend/src/weights/pallet_balances.rs b/polkadot/runtime/westend/src/weights/pallet_balances.rs index 5e91f31920ca..deaf8840462b 100644 --- a/polkadot/runtime/westend/src/weights/pallet_balances.rs +++ b/polkadot/runtime/westend/src/weights/pallet_balances.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `95c137a642c3`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=westend-dev +// --pallet=pallet_balances +// --header=/__w/polkadot-sdk/polkadot-sdk/polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_balances -// --chain=westend-dev -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,8 +56,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 43_248_000 picoseconds. - Weight::from_parts(43_872_000, 0) + // Minimum execution time: 51_474_000 picoseconds. + Weight::from_parts(52_840_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -66,8 +68,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_990_000 picoseconds. - Weight::from_parts(34_693_000, 0) + // Minimum execution time: 39_875_000 picoseconds. + Weight::from_parts(41_408_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -78,8 +80,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 12_681_000 picoseconds. - Weight::from_parts(13_183_000, 0) + // Minimum execution time: 19_614_000 picoseconds. + Weight::from_parts(20_194_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -90,8 +92,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_474_000 picoseconds. - Weight::from_parts(18_063_000, 0) + // Minimum execution time: 27_430_000 picoseconds. + Weight::from_parts(28_151_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -102,8 +104,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 45_699_000 picoseconds. - Weight::from_parts(46_099_000, 0) + // Minimum execution time: 54_131_000 picoseconds. + Weight::from_parts(54_810_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -114,8 +116,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_453_000 picoseconds. - Weight::from_parts(43_133_000, 0) + // Minimum execution time: 48_692_000 picoseconds. + Weight::from_parts(51_416_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -126,8 +128,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 15_066_000 picoseconds. - Weight::from_parts(15_605_000, 0) + // Minimum execution time: 22_604_000 picoseconds. + Weight::from_parts(23_336_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -139,11 +141,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_180_000 picoseconds. - Weight::from_parts(14_598_000, 0) + // Minimum execution time: 18_118_000 picoseconds. + Weight::from_parts(18_352_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 13_221 - .saturating_add(Weight::from_parts(13_422_901, 0).saturating_mul(u.into())) + // Standard Error: 14_688 + .saturating_add(Weight::from_parts(15_412_440, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -152,24 +154,24 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_130_000 picoseconds. - Weight::from_parts(5_257_000, 0) + // Minimum execution time: 6_779_000 picoseconds. + Weight::from_parts(7_246_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn burn_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 27_328_000 picoseconds. - Weight::from_parts(27_785_000, 0) + // Minimum execution time: 30_935_000 picoseconds. + Weight::from_parts(32_251_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn burn_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 17_797_000 picoseconds. - Weight::from_parts(18_103_000, 0) + // Minimum execution time: 21_002_000 picoseconds. + Weight::from_parts(21_760_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 10725cecf249..e2c0232139fb 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `3a528d69c69e`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=westend-dev +// --pallet=pallet_xcm +// --header=/__w/polkadot-sdk/polkadot-sdk/polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=westend-dev -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/westend/src/weights/ +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,38 +56,46 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `147` - // Estimated: `3612` - // Minimum execution time: 25_725_000 picoseconds. - Weight::from_parts(26_174_000, 0) - .saturating_add(Weight::from_parts(0, 3612)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `212` + // Estimated: `3677` + // Minimum execution time: 41_425_000 picoseconds. + Weight::from_parts(43_275_000, 0) + .saturating_add(Weight::from_parts(0, 3677)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `250` + // Measured: `315` // Estimated: `6196` - // Minimum execution time: 113_140_000 picoseconds. - Weight::from_parts(116_204_000, 0) + // Minimum execution time: 145_227_000 picoseconds. + Weight::from_parts(151_656_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) @@ -94,47 +104,54 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `302` + // Measured: `367` // Estimated: `6196` - // Minimum execution time: 108_571_000 picoseconds. - Weight::from_parts(110_650_000, 0) + // Minimum execution time: 141_439_000 picoseconds. + Weight::from_parts(146_252_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `250` + // Measured: `315` // Estimated: `6196` - // Minimum execution time: 111_836_000 picoseconds. - Weight::from_parts(114_435_000, 0) + // Minimum execution time: 146_651_000 picoseconds. + Weight::from_parts(150_134_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Estimated: `1485` + // Minimum execution time: 9_663_000 picoseconds. + Weight::from_parts(10_012_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) + .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -142,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_160_000 picoseconds. - Weight::from_parts(7_477_000, 0) + // Minimum execution time: 8_113_000 picoseconds. + Weight::from_parts(8_469_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -151,8 +168,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_934_000 picoseconds. - Weight::from_parts(2_053_000, 0) + // Minimum execution time: 2_493_000 picoseconds. + Weight::from_parts(2_630_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -165,18 +182,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::Queries` (r:0 w:1) /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `147` - // Estimated: `3612` - // Minimum execution time: 31_123_000 picoseconds. - Weight::from_parts(31_798_000, 0) - .saturating_add(Weight::from_parts(0, 3612)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `212` + // Estimated: `3677` + // Minimum execution time: 47_890_000 picoseconds. + Weight::from_parts(49_994_000, 0) + .saturating_add(Weight::from_parts(0, 3677)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -187,18 +206,20 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::Queries` (r:0 w:1) /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `327` - // Estimated: `3792` - // Minimum execution time: 35_175_000 picoseconds. - Weight::from_parts(36_098_000, 0) - .saturating_add(Weight::from_parts(0, 3792)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `392` + // Estimated: `3857` + // Minimum execution time: 52_967_000 picoseconds. + Weight::from_parts(55_345_000, 0) + .saturating_add(Weight::from_parts(0, 3857)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `XcmPallet::XcmExecutionSuspended` (r:0 w:1) @@ -207,45 +228,45 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_974_000 picoseconds. - Weight::from_parts(2_096_000, 0) + // Minimum execution time: 2_451_000 picoseconds. + Weight::from_parts(2_623_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmPallet::SupportedVersion` (r:5 w:2) + /// Storage: `XcmPallet::SupportedVersion` (r:6 w:2) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `22` - // Estimated: `13387` - // Minimum execution time: 16_626_000 picoseconds. - Weight::from_parts(17_170_000, 0) - .saturating_add(Weight::from_parts(0, 13387)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15862` + // Minimum execution time: 22_292_000 picoseconds. + Weight::from_parts(22_860_000, 0) + .saturating_add(Weight::from_parts(0, 15862)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifiers` (r:5 w:2) + /// Storage: `XcmPallet::VersionNotifiers` (r:6 w:2) /// Proof: `XcmPallet::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `26` - // Estimated: `13391` - // Minimum execution time: 16_937_000 picoseconds. - Weight::from_parts(17_447_000, 0) - .saturating_add(Weight::from_parts(0, 13391)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15866` + // Minimum execution time: 21_847_000 picoseconds. + Weight::from_parts(22_419_000, 0) + .saturating_add(Weight::from_parts(0, 15866)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:7 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `40` - // Estimated: `15880` - // Minimum execution time: 19_157_000 picoseconds. - Weight::from_parts(19_659_000, 0) - .saturating_add(Weight::from_parts(0, 15880)) - .saturating_add(T::DbWeight::get().reads(6)) + // Estimated: `18355` + // Minimum execution time: 24_764_000 picoseconds. + Weight::from_parts(25_873_000, 0) + .saturating_add(Weight::from_parts(0, 18355)) + .saturating_add(T::DbWeight::get().reads(7)) } /// Storage: `XcmPallet::VersionNotifyTargets` (r:2 w:1) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -253,62 +274,62 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:0) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `183` - // Estimated: `6123` - // Minimum execution time: 30_699_000 picoseconds. - Weight::from_parts(31_537_000, 0) - .saturating_add(Weight::from_parts(0, 6123)) + // Measured: `211` + // Estimated: `6151` + // Minimum execution time: 36_482_000 picoseconds. + Weight::from_parts(37_672_000, 0) + .saturating_add(Weight::from_parts(0, 6151)) .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:4 w:0) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:0) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `10959` - // Minimum execution time: 12_303_000 picoseconds. - Weight::from_parts(12_670_000, 0) - .saturating_add(Weight::from_parts(0, 10959)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `40` + // Estimated: `13405` + // Minimum execution time: 17_580_000 picoseconds. + Weight::from_parts(17_908_000, 0) + .saturating_add(Weight::from_parts(0, 13405)) + .saturating_add(T::DbWeight::get().reads(5)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:2) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `33` - // Estimated: `13398` - // Minimum execution time: 17_129_000 picoseconds. - Weight::from_parts(17_668_000, 0) - .saturating_add(Weight::from_parts(0, 13398)) - .saturating_add(T::DbWeight::get().reads(5)) + // Estimated: `15873` + // Minimum execution time: 21_946_000 picoseconds. + Weight::from_parts(22_548_000, 0) + .saturating_add(Weight::from_parts(0, 15873)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:5 w:2) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:6 w:1) /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:0) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:1 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `183` - // Estimated: `13548` - // Minimum execution time: 39_960_000 picoseconds. - Weight::from_parts(41_068_000, 0) - .saturating_add(Weight::from_parts(0, 13548)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `211` + // Estimated: `16051` + // Minimum execution time: 47_261_000 picoseconds. + Weight::from_parts(48_970_000, 0) + .saturating_add(Weight::from_parts(0, 16051)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -318,8 +339,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_333_000 picoseconds. - Weight::from_parts(2_504_000, 0) + // Minimum execution time: 2_794_000 picoseconds. + Weight::from_parts(2_895_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -330,22 +351,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_932_000 picoseconds. - Weight::from_parts(23_307_000, 0) + // Minimum execution time: 25_946_000 picoseconds. + Weight::from_parts(26_503_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `XcmPallet::ShouldRecordXcm` (r:1 w:0) + /// Proof: `XcmPallet::ShouldRecordXcm` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) fn claim_assets() -> Weight { // Proof Size summary in bytes: // Measured: `23` // Estimated: `3488` - // Minimum execution time: 34_558_000 picoseconds. - Weight::from_parts(35_299_000, 0) + // Minimum execution time: 40_780_000 picoseconds. + Weight::from_parts(41_910_000, 0) .saturating_add(Weight::from_parts(0, 3488)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs index a035ea2b0b5e..f4dbca0f29ff 100644 --- a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs +++ b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs @@ -85,7 +85,7 @@ impl polkadot_runtime_parachains::disputes::slashing::W /// Storage: Staking UnappliedSlashes (r:1 w:1) /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) /// The range of component `n` is `[4, 300]`. - fn report_dispute_lost(n: u32, ) -> Weight { + fn report_dispute_lost_unsigned(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4531 + n * (189 ±0)` // Estimated: `7843 + n * (192 ±0)` diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs index cb5894ea51e3..a5fb82a66837 100644 --- a/polkadot/runtime/westend/src/weights/xcm/mod.rs +++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs @@ -27,6 +27,8 @@ use xcm::{ use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; +use sp_runtime::BoundedVec; +use xcm::latest::AssetTransferFilter; /// Types of asset supported by the westend runtime. pub enum AssetTypes { @@ -115,7 +117,7 @@ impl XcmWeightInfo for WestendXcmWeight { } fn transact( _origin_kind: &OriginKind, - _require_weight_at_most: &Weight, + _fallback_max_weight: &Option, _call: &DoubleEncoded, ) -> Weight { XcmGeneric::::transact() @@ -166,12 +168,35 @@ impl XcmWeightInfo for WestendXcmWeight { fn initiate_teleport(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmBalancesWeight::::initiate_teleport()) } + fn initiate_transfer( + _dest: &Location, + remote_fees: &Option, + _preserve_origin: &bool, + assets: &Vec, + _xcm: &Xcm<()>, + ) -> Weight { + let mut weight = if let Some(remote_fees) = remote_fees { + let fees = remote_fees.inner(); + fees.weigh_assets(XcmBalancesWeight::::initiate_transfer()) + } else { + Weight::zero() + }; + for asset_filter in assets { + let assets = asset_filter.inner(); + let extra = assets.weigh_assets(XcmBalancesWeight::::initiate_transfer()); + weight = weight.saturating_add(extra); + } + weight + } fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight { XcmGeneric::::report_holding() } fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> Weight { XcmGeneric::::buy_execution() } + fn pay_fees(_asset: &Asset) -> Weight { + XcmGeneric::::pay_fees() + } fn refund_surplus() -> Weight { XcmGeneric::::refund_surplus() } @@ -184,6 +209,17 @@ impl XcmWeightInfo for WestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_hints(hints: &BoundedVec) -> Weight { + let mut weight = Weight::zero(); + for hint in hints { + match hint { + AssetClaimer { .. } => { + weight = weight.saturating_add(XcmGeneric::::asset_claimer()); + }, + } + } + weight + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -263,12 +299,14 @@ impl XcmWeightInfo for WestendXcmWeight { XcmGeneric::::clear_topic() } fn alias_origin(_: &Location) -> Weight { - // XCM Executor does not currently support alias origin operations - Weight::MAX + XcmGeneric::::alias_origin() } fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn execute_with_origin(_: &Option, _: &Xcm) -> Weight { + XcmGeneric::::execute_with_origin() + } } #[test] diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index e0c61c8e2bf2..f1ce760d48cf 100644 --- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 // Executed Command: @@ -55,8 +55,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 31_780_000 picoseconds. - Weight::from_parts(32_602_000, 3593) + // Minimum execution time: 31_578_000 picoseconds. + Weight::from_parts(32_243_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +66,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 41_818_000 picoseconds. - Weight::from_parts(42_902_000, 6196) + // Minimum execution time: 42_320_000 picoseconds. + Weight::from_parts(43_036_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -85,8 +85,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `351` // Estimated: `8799` - // Minimum execution time: 101_949_000 picoseconds. - Weight::from_parts(104_190_000, 8799) + // Minimum execution time: 101_972_000 picoseconds. + Weight::from_parts(104_288_000, 8799) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -113,8 +113,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `351` // Estimated: `6196` - // Minimum execution time: 70_123_000 picoseconds. - Weight::from_parts(72_564_000, 6196) + // Minimum execution time: 71_916_000 picoseconds. + Weight::from_parts(73_610_000, 6196) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -124,8 +124,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 31_868_000 picoseconds. - Weight::from_parts(32_388_000, 3593) + // Minimum execution time: 31_683_000 picoseconds. + Weight::from_parts(32_138_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -135,8 +135,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 24_532_000 picoseconds. - Weight::from_parts(25_166_000, 3593) + // Minimum execution time: 23_786_000 picoseconds. + Weight::from_parts(24_188_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -154,8 +154,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 63_378_000 picoseconds. - Weight::from_parts(65_002_000, 3612) + // Minimum execution time: 63_986_000 picoseconds. + Weight::from_parts(65_356_000, 3612) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -173,9 +173,28 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 49_174_000 picoseconds. - Weight::from_parts(50_356_000, 3612) + // Minimum execution time: 52_672_000 picoseconds. + Weight::from_parts(54_623_000, 3612) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + pub(crate) fn initiate_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `250` + // Estimated: `6196` + // Minimum execution time: 83_853_000 picoseconds. + Weight::from_parts(85_876_000, 6196) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } } diff --git a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 49beb85c2784..4e10e72356ab 100644 --- a/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -16,27 +16,29 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-12-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `aa8403b52523`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 // Executed Command: // target/production/polkadot // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* -// --execution=wasm +// --chain=westend-dev +// --pallet=pallet_xcm_benchmarks::generic +// --header=/__w/polkadot-sdk/polkadot-sdk/polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/xcm // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --pallet=pallet_xcm_benchmarks::generic -// --chain=westend-dev -// --header=./file_header.txt -// --template=./xcm/pallet-xcm-benchmarks/template.hbs -// --output=./runtime/westend/src/weights/xcm/ +// --template=polkadot/xcm/pallet-xcm-benchmarks/template.hbs +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,126 +51,139 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 30_790_000 picoseconds. - Weight::from_parts(31_265_000, 3634) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `351` + // Estimated: `6196` + // Minimum execution time: 74_868_000 picoseconds. + Weight::from_parts(77_531_000, 6196) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } pub(crate) fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_741_000 picoseconds. - Weight::from_parts(2_823_000, 0) + // Minimum execution time: 688_000 picoseconds. + Weight::from_parts(733_000, 0) } - /// Storage: XcmPallet Queries (r:1 w:0) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + pub(crate) fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_491_000 picoseconds. + Weight::from_parts(3_667_000, 0) + } + pub(crate) fn asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 757_000 picoseconds. + Weight::from_parts(804_000, 0) + } + /// Storage: `XcmPallet::Queries` (r:1 w:0) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn query_response() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 10_848_000 picoseconds. - Weight::from_parts(11_183_000, 3634) + // Measured: `0` + // Estimated: `3465` + // Minimum execution time: 6_322_000 picoseconds. + Weight::from_parts(6_565_000, 3465) .saturating_add(T::DbWeight::get().reads(1)) } pub(crate) fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_145_000 picoseconds. - Weight::from_parts(12_366_000, 0) + // Minimum execution time: 7_841_000 picoseconds. + Weight::from_parts(8_240_000, 0) } pub(crate) fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_837_000 picoseconds. - Weight::from_parts(2_939_000, 0) + // Minimum execution time: 1_327_000 picoseconds. + Weight::from_parts(1_460_000, 0) } pub(crate) fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_526_000 picoseconds. - Weight::from_parts(2_622_000, 0) + // Minimum execution time: 680_000 picoseconds. + Weight::from_parts(752_000, 0) } pub(crate) fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_603_000 picoseconds. - Weight::from_parts(2_642_000, 0) + // Minimum execution time: 712_000 picoseconds. + Weight::from_parts(764_000, 0) } pub(crate) fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_500_000 picoseconds. - Weight::from_parts(2_573_000, 0) + // Minimum execution time: 663_000 picoseconds. + Weight::from_parts(712_000, 0) } pub(crate) fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_323_000 picoseconds. - Weight::from_parts(3_401_000, 0) + // Minimum execution time: 756_000 picoseconds. + Weight::from_parts(801_000, 0) + } + pub(crate) fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 773_000 picoseconds. + Weight::from_parts(822_000, 0) } pub(crate) fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_557_000 picoseconds. - Weight::from_parts(2_620_000, 0) - } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(750_000, 0) + } + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 25_828_000 picoseconds. - Weight::from_parts(26_318_000, 3634) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `351` + // Estimated: `6196` + // Minimum execution time: 73_173_000 picoseconds. + Weight::from_parts(75_569_000, 6196) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: XcmPallet AssetTraps (r:1 w:1) - /// Proof Skipped: XcmPallet AssetTraps (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) + /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn claim_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `226` - // Estimated: `3691` - // Minimum execution time: 14_794_000 picoseconds. - Weight::from_parts(15_306_000, 3691) + // Measured: `23` + // Estimated: `3488` + // Minimum execution time: 9_851_000 picoseconds. + Weight::from_parts(10_087_000, 3488) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -176,165 +191,158 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_534_000 picoseconds. - Weight::from_parts(2_574_000, 0) - } - /// Storage: XcmPallet VersionNotifyTargets (r:1 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + // Minimum execution time: 673_000 picoseconds. + Weight::from_parts(744_000, 0) + } + /// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 32_218_000 picoseconds. - Weight::from_parts(32_945_000, 3634) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 35_714_000 picoseconds. + Weight::from_parts(36_987_000, 3612) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: XcmPallet VersionNotifyTargets (r:0 w:1) - /// Proof Skipped: XcmPallet VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) + /// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn unsubscribe_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_983_000 picoseconds. - Weight::from_parts(5_132_000, 0) + // Minimum execution time: 3_128_000 picoseconds. + Weight::from_parts(3_364_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub(crate) fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_101_000 picoseconds. - Weight::from_parts(4_228_000, 0) + // Minimum execution time: 1_070_000 picoseconds. + Weight::from_parts(1_188_000, 0) } pub(crate) fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_740_000 picoseconds. - Weight::from_parts(2_814_000, 0) + // Minimum execution time: 764_000 picoseconds. + Weight::from_parts(863_000, 0) } pub(crate) fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_716_000 picoseconds. - Weight::from_parts(2_795_000, 0) + // Minimum execution time: 675_000 picoseconds. + Weight::from_parts(755_000, 0) } pub(crate) fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_550_000 picoseconds. - Weight::from_parts(2_601_000, 0) + // Minimum execution time: 666_000 picoseconds. + Weight::from_parts(745_000, 0) } pub(crate) fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_762_000 picoseconds. - Weight::from_parts(2_849_000, 0) - } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + // Minimum execution time: 838_000 picoseconds. + Weight::from_parts(918_000, 0) + } + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 31_709_000 picoseconds. - Weight::from_parts(32_288_000, 3634) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `351` + // Estimated: `6196` + // Minimum execution time: 82_721_000 picoseconds. + Weight::from_parts(85_411_000, 6196) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } pub(crate) fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_209_000 picoseconds. - Weight::from_parts(7_332_000, 0) - } - /// Storage: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Proof Skipped: unknown `0x3a696e747261626c6f636b5f656e74726f7079` (r:1 w:1) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + // Minimum execution time: 8_138_000 picoseconds. + Weight::from_parts(8_344_000, 0) + } + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) pub(crate) fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `169` - // Estimated: `3634` - // Minimum execution time: 26_161_000 picoseconds. - Weight::from_parts(26_605_000, 3634) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `351` + // Estimated: `6196` + // Minimum execution time: 73_617_000 picoseconds. + Weight::from_parts(76_999_000, 6196) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } pub(crate) fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_539_000 picoseconds. - Weight::from_parts(2_647_000, 0) + // Minimum execution time: 714_000 picoseconds. + Weight::from_parts(806_000, 0) } pub(crate) fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_494_000 picoseconds. - Weight::from_parts(2_588_000, 0) + // Minimum execution time: 676_000 picoseconds. + Weight::from_parts(720_000, 0) } pub(crate) fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_510_000 picoseconds. - Weight::from_parts(2_590_000, 0) + // Minimum execution time: 666_000 picoseconds. + Weight::from_parts(731_000, 0) } pub(crate) fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_491_000 picoseconds. - Weight::from_parts(2_546_000, 0) + // Minimum execution time: 662_000 picoseconds. + Weight::from_parts(696_000, 0) } pub(crate) fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_696_000 picoseconds. - Weight::from_parts(2_816_000, 0) + // Minimum execution time: 693_000 picoseconds. + Weight::from_parts(760_000, 0) + } + pub(crate) fn alias_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 705_000 picoseconds. + Weight::from_parts(746_000, 0) } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index d75083929a04..3f6a7304c8a9 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -36,22 +36,23 @@ use sp_core::ConstU32; use westend_runtime_constants::{ currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, }; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FrameTransactionalProcessor, - FungibleAdapter, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, - OriginToPluralityVoice, SendXcmFeeToAccount, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + AccountId32Aliases, AliasChildLocation, AllowExplicitUnpaidExecutionFrom, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + ChildParachainAsNative, ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, + FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsChildSystemParachain, + IsConcrete, MintLocation, OriginToPluralityVoice, SendXcmFeeToAccount, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; parameter_types! { pub const TokenLocation: Location = Here.into_location(); pub const RootLocation: Location = Location::here(); - pub const ThisNetwork: NetworkId = Westend; + pub const ThisNetwork: NetworkId = ByGenesis(WESTEND_GENESIS_HASH); pub UniversalLocation: InteriorLocation = [GlobalConsensus(ThisNetwork::get())].into(); pub CheckAccount: AccountId = XcmPallet::check_account(); pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); @@ -183,6 +184,11 @@ pub type Barrier = TrailingSetTopicAsId<( /// We only waive fees for system functions, which these locations represent. pub type WaivedLocations = (SystemParachains, Equals, LocalPlurality); +/// We let locations alias into child locations of their own. +/// This is a very simple aliasing rule, mimicking the behaviour of +/// the `DescendOrigin` instruction. +pub type Aliasers = AliasChildLocation; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -216,7 +222,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + type Aliasers = Aliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 53ea0b74463b..1155600f3d0c 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -5,12 +5,14 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Stores messages other authorities issue about candidates in Polkadot." +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -sp-core = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } gum = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs index e3c470fcdeec..4ab6e27d2c74 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -62,14 +62,6 @@ pub trait Context { fn get_group_size(&self, group: &Self::GroupId) -> Option; } -/// Table configuration. -pub struct Config { - /// When this is true, the table will allow multiple seconded candidates - /// per authority. This flag means that higher-level code is responsible for - /// bounding the number of candidates. - pub allow_multiple_seconded: bool, -} - /// Statements circulated among peers. #[derive(PartialEq, Eq, Debug, Clone, Encode, Decode)] pub enum Statement { @@ -143,15 +135,6 @@ impl DoubleSign { } } -/// Misbehavior: declaring multiple candidates. -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct MultipleCandidates { - /// The first candidate seen. - pub first: (Candidate, Signature), - /// The second candidate seen. - pub second: (Candidate, Signature), -} - /// Misbehavior: submitted statement for wrong group. #[derive(PartialEq, Eq, Debug, Clone)] pub struct UnauthorizedStatement { @@ -165,8 +148,6 @@ pub struct UnauthorizedStatement { pub enum Misbehavior { /// Voted invalid and valid on validity. ValidityDoubleVote(ValidityDoubleVote), - /// Submitted multiple candidates. - MultipleCandidates(MultipleCandidates), /// Submitted a message that was unauthorized. UnauthorizedStatement(UnauthorizedStatement), /// Submitted two valid signatures for the same message. @@ -300,17 +281,14 @@ pub struct Table { authority_data: HashMap>, detected_misbehavior: HashMap>>, candidate_votes: HashMap>, - config: Config, } impl Table { - /// Create a new `Table` from a `Config`. - pub fn new(config: Config) -> Self { + pub fn new() -> Self { Table { authority_data: HashMap::default(), detected_misbehavior: HashMap::default(), candidate_votes: HashMap::default(), - config, } } @@ -408,33 +386,7 @@ impl Table { // if digest is different, fetch candidate and // note misbehavior. let existing = occ.get_mut(); - - if !self.config.allow_multiple_seconded && existing.proposals.len() == 1 { - let (old_digest, old_sig) = &existing.proposals[0]; - - if old_digest != &digest { - const EXISTENCE_PROOF: &str = - "when proposal first received from authority, candidate \ - votes entry is created. proposal here is `Some`, therefore \ - candidate votes entry exists; qed"; - - let old_candidate = self - .candidate_votes - .get(old_digest) - .expect(EXISTENCE_PROOF) - .candidate - .clone(); - - return Err(Misbehavior::MultipleCandidates(MultipleCandidates { - first: (old_candidate, old_sig.clone()), - second: (candidate, signature.clone()), - })) - } - - false - } else if self.config.allow_multiple_seconded && - existing.proposals.iter().any(|(ref od, _)| od == &digest) - { + if existing.proposals.iter().any(|(ref od, _)| od == &digest) { false } else { existing.proposals.push((digest.clone(), signature.clone())); @@ -591,14 +543,6 @@ mod tests { use super::*; use std::collections::HashMap; - fn create_single_seconded() -> Table { - Table::new(Config { allow_multiple_seconded: false }) - } - - fn create_many_seconded() -> Table { - Table::new(Config { allow_multiple_seconded: true }) - } - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct AuthorityId(usize); @@ -646,42 +590,6 @@ mod tests { } } - #[test] - fn submitting_two_candidates_can_be_misbehavior() { - let context = TestContext { - authorities: { - let mut map = HashMap::new(); - map.insert(AuthorityId(1), GroupId(2)); - map - }, - }; - - let mut table = create_single_seconded(); - let statement_a = SignedStatement { - statement: Statement::Seconded(Candidate(2, 100)), - signature: Signature(1), - sender: AuthorityId(1), - }; - - let statement_b = SignedStatement { - statement: Statement::Seconded(Candidate(2, 999)), - signature: Signature(1), - sender: AuthorityId(1), - }; - - table.import_statement(&context, GroupId(2), statement_a); - assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); - - table.import_statement(&context, GroupId(2), statement_b); - assert_eq!( - table.detected_misbehavior[&AuthorityId(1)][0], - Misbehavior::MultipleCandidates(MultipleCandidates { - first: (Candidate(2, 100), Signature(1)), - second: (Candidate(2, 999), Signature(1)), - }) - ); - } - #[test] fn submitting_two_candidates_can_be_allowed() { let context = TestContext { @@ -692,7 +600,7 @@ mod tests { }, }; - let mut table = create_many_seconded(); + let mut table = Table::new(); let statement_a = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -722,7 +630,7 @@ mod tests { }, }; - let mut table = create_single_seconded(); + let mut table = Table::new(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -754,7 +662,7 @@ mod tests { }, }; - let mut table = create_single_seconded(); + let mut table = Table::new(); let candidate_a = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), @@ -798,7 +706,7 @@ mod tests { }, }; - let mut table = create_single_seconded(); + let mut table = Table::new(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -828,7 +736,7 @@ mod tests { }, }; - let mut table = create_single_seconded(); + let mut table = Table::new(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -896,7 +804,7 @@ mod tests { }; // have 2/3 validity guarantors note validity. - let mut table = create_single_seconded(); + let mut table = Table::new(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -930,7 +838,7 @@ mod tests { }, }; - let mut table = create_single_seconded(); + let mut table = Table::new(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), @@ -957,7 +865,7 @@ mod tests { }, }; - let mut table = create_single_seconded(); + let mut table = Table::new(); let statement = SignedStatement { statement: Statement::Seconded(Candidate(2, 100)), signature: Signature(1), diff --git a/polkadot/statement-table/src/lib.rs b/polkadot/statement-table/src/lib.rs index 68febf76feb3..c8ad28437f88 100644 --- a/polkadot/statement-table/src/lib.rs +++ b/polkadot/statement-table/src/lib.rs @@ -29,7 +29,7 @@ pub mod generic; -pub use generic::{Config, Context, Table}; +pub use generic::{Context, Table}; /// Concrete instantiations suitable for v2 primitives. pub mod v2 { diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 16205b0f51f5..3006d8325ef9 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -5,6 +5,8 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "CLI to generate voter bags for Polkadot runtimes" +homepage.workspace = true +repository.workspace = true [lints] workspace = true diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index 206ca8cf19a9..1a6c23e0518e 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -13,10 +13,10 @@ workspace = true westend-runtime = { workspace = true } westend-runtime-constants = { workspace = true, default-features = true } -pallet-bags-list-remote-tests = { workspace = true } -sp-tracing = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } +pallet-bags-list-remote-tests = { workspace = true } sp-core = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 862f5557a012..e90354e4e6ac 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -5,6 +5,8 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -12,22 +14,23 @@ workspace = true [dependencies] array-bytes = { workspace = true, default-features = true } bounded-collections = { features = ["serde"], workspace = true } +codec = { features = ["derive", "max-encoded-len"], workspace = true } derivative = { features = ["use_core"], workspace = true } +environmental = { workspace = true } +frame-support = { workspace = true } +hex-literal = { workspace = true, default-features = true } impl-trait-for-tuples = { workspace = true } log = { workspace = true } -codec = { features = ["derive", "max-encoded-len"], workspace = true } scale-info = { features = ["derive", "serde"], workspace = true } +schemars = { default-features = true, optional = true, workspace = true } +serde = { features = ["alloc", "derive", "rc"], workspace = true } sp-runtime = { workspace = true } sp-weights = { features = ["serde"], workspace = true } -serde = { features = ["alloc", "derive", "rc"], workspace = true } -schemars = { default-features = true, optional = true, workspace = true } xcm-procedural = { workspace = true, default-features = true } -environmental = { workspace = true } [dev-dependencies] -sp-io = { workspace = true, default-features = true } hex = { workspace = true, default-features = true } -hex-literal = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] @@ -36,6 +39,7 @@ std = [ "bounded-collections/std", "codec/std", "environmental/std", + "frame-support/std", "log/std", "scale-info/std", "serde/std", @@ -47,3 +51,7 @@ json-schema = [ "dep:schemars", "sp-weights/json-schema", ] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/polkadot/xcm/docs/Cargo.toml b/polkadot/xcm/docs/Cargo.toml index 9d8f4c0a6430..6fa7ea9a23a9 100644 --- a/polkadot/xcm/docs/Cargo.toml +++ b/polkadot/xcm/docs/Cargo.toml @@ -10,30 +10,30 @@ publish = false [dependencies] # For XCM stuff +pallet-xcm = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } xcm-builder = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } xcm-simulator = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } # For building FRAME runtimes -frame = { features = ["experimental", "runtime"], workspace = true, default-features = true } codec = { workspace = true, default-features = true } -scale-info = { workspace = true } +frame = { features = ["experimental", "runtime"], workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } -polkadot-runtime-parachains = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +scale-info = { workspace = true } +sp-io = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-std = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } # Some pallets -pallet-message-queue = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } # For building docs -simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } docify = { workspace = true } +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } [dev-dependencies] test-log = { workspace = true } 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 f8a1826b8ab1..0180354458ce 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 @@ -21,7 +21,7 @@ use frame::{ runtime::prelude::*, traits::{Everything, Nothing}, }; -use xcm::v4::prelude::*; +use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs index 686f86b37b73..cd8701dbbede 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs @@ -23,7 +23,7 @@ use frame::{ traits::{IdentityLookup, ProcessMessage, ProcessMessageError}, }; use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; -use xcm::v4::prelude::*; +use xcm::latest::prelude::*; mod xcm_config; pub use xcm_config::LocationToAccountId; 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 e7b602df7338..06b00c39e8a0 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 @@ -21,7 +21,7 @@ use frame::{ runtime::prelude::*, traits::{Everything, Nothing}, }; -use xcm::v4::prelude::*; +use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs index 792cf6149e7c..b7fdaa34ec8c 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs @@ -65,9 +65,9 @@ fn reserve_asset_transfers_work() { let assets: Assets = (Here, 50u128 * CENTS as u128).into(); assert_ok!(relay_chain::XcmPallet::transfer_assets( relay_chain::RuntimeOrigin::signed(ALICE), - Box::new(VersionedLocation::V4(destination.clone())), - Box::new(VersionedLocation::V4(beneficiary)), - Box::new(VersionedAssets::V4(assets)), + Box::new(VersionedLocation::from(destination.clone())), + Box::new(VersionedLocation::from(beneficiary)), + Box::new(VersionedAssets::from(assets)), 0, WeightLimit::Unlimited, )); @@ -101,9 +101,9 @@ fn reserve_asset_transfers_work() { let assets: Assets = (Parent, 25u128 * CENTS as u128).into(); assert_ok!(parachain::XcmPallet::transfer_assets( parachain::RuntimeOrigin::signed(BOB), - Box::new(VersionedLocation::V4(destination)), - Box::new(VersionedLocation::V4(beneficiary)), - Box::new(VersionedAssets::V4(assets)), + Box::new(VersionedLocation::from(destination)), + Box::new(VersionedLocation::from(beneficiary)), + Box::new(VersionedAssets::from(assets)), 0, WeightLimit::Unlimited, )); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index b07bdfdca3d1..5d5926ae01e0 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -5,6 +5,8 @@ edition.workspace = true license.workspace = true version = "7.0.0" description = "Benchmarks for the XCM pallet" +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,20 +16,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } +frame-benchmarking = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-runtime = { workspace = true } +log = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } -xcm-executor = { workspace = true } -frame-benchmarking = { workspace = true } +sp-runtime = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } -log = { workspace = true, default-features = true } +xcm-executor = { workspace = true } [dev-dependencies] -pallet-balances = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } # temp @@ -62,4 +64,5 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 6ce49074a6e2..4428076aa077 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -24,7 +24,7 @@ use frame_support::{ weights::Weight, }; use sp_runtime::traits::{Bounded, Zero}; -use xcm::latest::{prelude::*, MAX_ITEMS_IN_ASSETS}; +use xcm::latest::{prelude::*, AssetTransferFilter, MAX_ITEMS_IN_ASSETS}; use xcm_executor::traits::{ConvertLocation, FeeReason, TransactAsset}; benchmarks_instance_pallet! { @@ -231,6 +231,13 @@ benchmarks_instance_pallet! { let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); assert!(T::TransactAsset::balance(&dest_account).is_zero()); + // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + let (_, _) = T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &dest_location, + FeeReason::ChargeFees, + ); + let mut executor = new_executor::(Default::default()); executor.set_holding(holding.into()); let instruction = Instruction::>::DepositAsset { @@ -257,6 +264,13 @@ benchmarks_instance_pallet! { let dest_account = T::AccountIdConverter::convert_location(&dest_location).unwrap(); assert!(T::TransactAsset::balance(&dest_account).is_zero()); + // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + let (_, _) = T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &dest_location, + FeeReason::ChargeFees, + ); + let mut executor = new_executor::(Default::default()); executor.set_holding(holding.into()); let instruction = Instruction::>::DepositReserveAsset { @@ -281,12 +295,20 @@ benchmarks_instance_pallet! { // Checked account starts at zero assert!(T::CheckedAccount::get().map_or(true, |(c, _)| T::TransactAsset::balance(&c).is_zero())); + let dest_location = T::valid_destination()?; + + // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + let (_, _) = T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &dest_location, + FeeReason::ChargeFees, + ); let mut executor = new_executor::(Default::default()); executor.set_holding(holding.into()); let instruction = Instruction::>::InitiateTeleport { assets: asset.into(), - dest: T::valid_destination()?, + dest: dest_location, xcm: Xcm::new(), }; let xcm = Xcm(vec![instruction]); @@ -299,6 +321,42 @@ benchmarks_instance_pallet! { } } + initiate_transfer { + let (sender_account, sender_location) = account_and_location::(1); + let asset = T::get_asset(); + let mut holding = T::worst_case_holding(1); + let dest_location = T::valid_destination()?; + + // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + let (_, _) = T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &dest_location, + FeeReason::ChargeFees, + ); + + let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + + // Add our asset to the holding. + holding.push(asset.clone()); + + let mut executor = new_executor::(sender_location); + executor.set_holding(holding.into()); + let instruction = Instruction::>::InitiateTransfer { + destination: dest_location, + // ReserveDeposit is the most expensive filter. + remote_fees: Some(AssetTransferFilter::ReserveDeposit(asset.clone().into())), + // It's more expensive if we reanchor the origin. + preserve_origin: true, + assets: vec![AssetTransferFilter::ReserveDeposit(asset.into())], + remote_xcm: Xcm::new(), + }; + let xcm = Xcm(vec![instruction]); + }: { + executor.bench_process(xcm)?; + } verify { + assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); + } + impl_benchmark_test_suite!( Pallet, crate::fungible::mock::new_test_ext(), diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index f1ec3f604d7b..1c62bb5886d8 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -13,13 +13,14 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +#![cfg(feature = "runtime-benchmarks")] use super::*; use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf}; use alloc::{vec, vec::Vec}; use codec::Encode; -use frame_benchmarking::{benchmarks, BenchmarkError}; -use frame_support::{dispatch::GetDispatchInfo, traits::fungible::Inspect}; +use frame_benchmarking::v2::*; +use frame_support::{traits::fungible::Inspect, BoundedVec}; use xcm::{ latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight, MAX_ITEMS_IN_ASSETS}, DoubleEncoded, @@ -29,16 +30,21 @@ use xcm_executor::{ ExecutorError, FeesMode, }; -benchmarks! { - report_holding { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn report_holding() -> Result<(), BenchmarkError> { let (sender_account, sender_location) = account_and_location::(1); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &sender_location, - &destination, - FeeReason::Report, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::Report, + ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); // generate holding and add possible required fees @@ -64,21 +70,33 @@ benchmarks! { query_id: Default::default(), max_weight: Weight::MAX, }, - // Worst case is looking through all holdings for every asset explicitly - respecting the limit `MAX_ITEMS_IN_ASSETS`. - assets: Definite(holding.into_inner().into_iter().take(MAX_ITEMS_IN_ASSETS).collect::>().into()), + // Worst case is looking through all holdings for every asset explicitly - respecting + // the limit `MAX_ITEMS_IN_ASSETS`. + assets: Definite( + holding + .into_inner() + .into_iter() + .take(MAX_ITEMS_IN_ASSETS) + .collect::>() + .into(), + ), }; let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // Check we charged the delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); + + Ok(()) } // This benchmark does not use any additional orders or instructions. This should be managed // by the `deep` and `shallow` implementation. - buy_execution { + #[benchmark] + fn buy_execution() -> Result<(), BenchmarkError> { let holding = T::worst_case_holding(0).into(); let mut executor = new_executor::(Default::default()); @@ -92,135 +110,228 @@ benchmarks! { }; let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } + Ok(()) } - query_response { + #[benchmark] + fn pay_fees() -> Result<(), BenchmarkError> { + let holding = T::worst_case_holding(0).into(); + + let mut executor = new_executor::(Default::default()); + executor.set_holding(holding); + // Set some weight to be paid for. + executor.set_message_weight(Weight::from_parts(100_000_000, 100_000)); + + let fee_asset: Asset = T::fee_asset().unwrap(); + + let instruction = Instruction::>::PayFees { asset: fee_asset }; + + let xcm = Xcm(vec![instruction]); + #[block] + { + executor.bench_process(xcm)?; + } + Ok(()) + } + + #[benchmark] + fn asset_claimer() -> Result<(), BenchmarkError> { + let mut executor = new_executor::(Default::default()); + let (_, sender_location) = account_and_location::(1); + + let instruction = Instruction::SetHints { + hints: BoundedVec::::truncate_from(vec![AssetClaimer { + location: sender_location.clone(), + }]), + }; + + let xcm = Xcm(vec![instruction]); + #[block] + { + executor.bench_process(xcm)?; + } + assert_eq!(executor.asset_claimer(), Some(sender_location.clone())); + + Ok(()) + } + + #[benchmark] + fn query_response() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let (query_id, response) = T::worst_case_response(); let max_weight = Weight::MAX; let querier: Option = Some(Here.into()); let instruction = Instruction::QueryResponse { query_id, response, max_weight, querier }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + + #[block] + { + executor.bench_process(xcm)?; + } // The assert above is enough to show this XCM succeeded + + Ok(()) } // We don't care about the call itself, since that is accounted for in the weight parameter // and included in the final weight calculation. So this is just the overhead of submitting // a noop call. - transact { + #[benchmark] + fn transact() -> Result<(), BenchmarkError> { let (origin, noop_call) = T::transact_origin_and_runtime_call()?; let mut executor = new_executor::(origin); let double_encoded_noop_call: DoubleEncoded<_> = noop_call.encode().into(); let instruction = Instruction::Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: noop_call.get_dispatch_info().call_weight, call: double_encoded_noop_call, + fallback_max_weight: None, }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // TODO Make the assertion configurable? + + Ok(()) } - refund_surplus { + #[benchmark] + fn refund_surplus() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let holding_assets = T::worst_case_holding(1); // We can already buy execution since we'll load the holding register manually let asset_for_fees = T::fee_asset().unwrap(); - let previous_xcm = Xcm(vec![BuyExecution { fees: asset_for_fees, weight_limit: Limited(Weight::from_parts(1337, 1337)) }]); + let previous_xcm = Xcm(vec![BuyExecution { + fees: asset_for_fees, + weight_limit: Limited(Weight::from_parts(1337, 1337)), + }]); executor.set_holding(holding_assets.into()); executor.set_total_surplus(Weight::from_parts(1337, 1337)); executor.set_total_refunded(Weight::zero()); - executor.bench_process(previous_xcm).expect("Holding has been loaded, so we can buy execution here"); + executor + .bench_process(previous_xcm) + .expect("Holding has been loaded, so we can buy execution here"); let instruction = Instruction::>::RefundSurplus; let xcm = Xcm(vec![instruction]); - } : { - let result = executor.bench_process(xcm)?; - } verify { + #[block] + { + let _result = executor.bench_process(xcm)?; + } assert_eq!(executor.total_surplus(), &Weight::from_parts(1337, 1337)); assert_eq!(executor.total_refunded(), &Weight::from_parts(1337, 1337)); + + Ok(()) } - set_error_handler { + #[benchmark] + fn set_error_handler() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let instruction = Instruction::>::SetErrorHandler(Xcm(vec![])); let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.error_handler(), &Xcm(vec![])); + + Ok(()) } - set_appendix { + #[benchmark] + fn set_appendix() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let appendix = Xcm(vec![]); let instruction = Instruction::>::SetAppendix(appendix); let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.appendix(), &Xcm(vec![])); + Ok(()) } - clear_error { + #[benchmark] + fn clear_error() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); executor.set_error(Some((5u32, XcmError::Overflow))); let instruction = Instruction::>::ClearError; let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { - assert!(executor.error().is_none()) + #[block] + { + executor.bench_process(xcm)?; + } + assert!(executor.error().is_none()); + Ok(()) } - descend_origin { + #[benchmark] + fn descend_origin() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let who = Junctions::from([OnlyChild, OnlyChild]); let instruction = Instruction::DescendOrigin(who.clone()); let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { - assert_eq!( - executor.origin(), - &Some(Location { - parents: 0, - interior: who, - }), - ); + #[block] + { + executor.bench_process(xcm)?; + } + assert_eq!(executor.origin(), &Some(Location { parents: 0, interior: who }),); + + Ok(()) } - clear_origin { + #[benchmark] + fn execute_with_origin() -> Result<(), BenchmarkError> { + let mut executor = new_executor::(Default::default()); + let who: Junctions = Junctions::from([AccountId32 { id: [0u8; 32], network: None }]); + let instruction = Instruction::ExecuteWithOrigin { + descendant_origin: Some(who.clone()), + xcm: Xcm(vec![]), + }; + let xcm = Xcm(vec![instruction]); + #[block] + { + executor.bench_process(xcm)?; + } + assert_eq!(executor.origin(), &Some(Location { parents: 0, interior: Here }),); + + Ok(()) + } + + #[benchmark] + fn clear_origin() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let instruction = Instruction::ClearOrigin; let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.origin(), &None); + Ok(()) } - report_error { + #[benchmark] + fn report_error() -> Result<(), BenchmarkError> { let (sender_account, sender_location) = account_and_location::(1); let query_id = Default::default(); let max_weight = Default::default(); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &sender_location, - &destination, - FeeReason::Report, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::Report, + ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); let mut executor = new_executor::(sender_location); @@ -232,18 +343,21 @@ benchmarks! { } executor.set_error(Some((0u32, XcmError::Unimplemented))); - let instruction = Instruction::ReportError(QueryResponseInfo { - query_id, destination, max_weight - }); + let instruction = + Instruction::ReportError(QueryResponseInfo { query_id, destination, max_weight }); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // Check we charged the delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); + + Ok(()) } - claim_asset { + #[benchmark] + fn claim_asset() -> Result<(), BenchmarkError> { use xcm_executor::traits::DropAssets; let (origin, ticket, assets) = T::claimable_asset()?; @@ -252,11 +366,7 @@ benchmarks! { ::AssetTrap::drop_assets( &origin, assets.clone().into(), - &XcmContext { - origin: Some(origin.clone()), - message_id: [0; 32], - topic: None, - }, + &XcmContext { origin: Some(origin.clone()), message_id: [0; 32], topic: None }, ); // Assets should be in the trap now. @@ -264,28 +374,32 @@ benchmarks! { let mut executor = new_executor::(origin); let instruction = Instruction::ClaimAsset { assets: assets.clone(), ticket }; let xcm = Xcm(vec![instruction]); - } :{ - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert!(executor.holding().ensure_contains(&assets).is_ok()); + Ok(()) } - trap { + #[benchmark] + fn trap() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let instruction = Instruction::Trap(10); let xcm = Xcm(vec![instruction]); // In order to access result in the verification below, it needs to be defined here. - let mut _result = Ok(()); - } : { - _result = executor.bench_process(xcm); - } verify { - assert!(matches!(_result, Err(ExecutorError { - xcm_error: XcmError::Trap(10), - .. - }))); + let result; + #[block] + { + result = executor.bench_process(xcm); + } + assert!(matches!(result, Err(ExecutorError { xcm_error: XcmError::Trap(10), .. }))); + + Ok(()) } - subscribe_version { + #[benchmark] + fn subscribe_version() -> Result<(), BenchmarkError> { use xcm_executor::traits::VersionChangeNotifier; let origin = T::subscribe_origin()?; let query_id = Default::default(); @@ -293,40 +407,55 @@ benchmarks! { let mut executor = new_executor::(origin.clone()); let instruction = Instruction::SubscribeVersion { query_id, max_response_weight }; let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { - assert!(::SubscriptionService::is_subscribed(&origin)); + + T::DeliveryHelper::ensure_successful_delivery(&origin, &origin, FeeReason::QueryPallet); + + #[block] + { + executor.bench_process(xcm)?; + } + assert!(::SubscriptionService::is_subscribed( + &origin + )); + Ok(()) } - unsubscribe_version { + #[benchmark] + fn unsubscribe_version() -> Result<(), BenchmarkError> { use xcm_executor::traits::VersionChangeNotifier; // First we need to subscribe to notifications. let (origin, _) = T::transact_origin_and_runtime_call()?; + + T::DeliveryHelper::ensure_successful_delivery(&origin, &origin, FeeReason::QueryPallet); + let query_id = Default::default(); let max_response_weight = Default::default(); ::SubscriptionService::start( &origin, query_id, max_response_weight, - &XcmContext { - origin: Some(origin.clone()), - message_id: [0; 32], - topic: None, - }, - ).map_err(|_| "Could not start subscription")?; - assert!(::SubscriptionService::is_subscribed(&origin)); + &XcmContext { origin: Some(origin.clone()), message_id: [0; 32], topic: None }, + ) + .map_err(|_| "Could not start subscription")?; + assert!(::SubscriptionService::is_subscribed( + &origin + )); let mut executor = new_executor::(origin.clone()); let instruction = Instruction::UnsubscribeVersion; let xcm = Xcm(vec![instruction]); - } : { - executor.bench_process(xcm)?; - } verify { - assert!(!::SubscriptionService::is_subscribed(&origin)); + #[block] + { + executor.bench_process(xcm)?; + } + assert!(!::SubscriptionService::is_subscribed( + &origin + )); + Ok(()) } - burn_asset { + #[benchmark] + fn burn_asset() -> Result<(), BenchmarkError> { let holding = T::worst_case_holding(0); let assets = holding.clone(); @@ -335,13 +464,16 @@ benchmarks! { let instruction = Instruction::BurnAsset(assets.into()); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert!(executor.holding().is_empty()); + Ok(()) } - expect_asset { + #[benchmark] + fn expect_asset() -> Result<(), BenchmarkError> { let holding = T::worst_case_holding(0); let assets = holding.clone(); @@ -350,71 +482,86 @@ benchmarks! { let instruction = Instruction::ExpectAsset(assets.into()); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // `execute` completing successfully is as good as we can check. + + Ok(()) } - expect_origin { + #[benchmark] + fn expect_origin() -> Result<(), BenchmarkError> { let expected_origin = Parent.into(); let mut executor = new_executor::(Default::default()); let instruction = Instruction::ExpectOrigin(Some(expected_origin)); let xcm = Xcm(vec![instruction]); let mut _result = Ok(()); - }: { - _result = executor.bench_process(xcm); - } verify { - assert!(matches!(_result, Err(ExecutorError { - xcm_error: XcmError::ExpectationFalse, - .. - }))); + #[block] + { + _result = executor.bench_process(xcm); + } + assert!(matches!( + _result, + Err(ExecutorError { xcm_error: XcmError::ExpectationFalse, .. }) + )); + + Ok(()) } - expect_error { + #[benchmark] + fn expect_error() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); executor.set_error(Some((3u32, XcmError::Overflow))); let instruction = Instruction::ExpectError(None); let xcm = Xcm(vec![instruction]); let mut _result = Ok(()); - }: { - _result = executor.bench_process(xcm); - } verify { - assert!(matches!(_result, Err(ExecutorError { - xcm_error: XcmError::ExpectationFalse, - .. - }))); + #[block] + { + _result = executor.bench_process(xcm); + } + assert!(matches!( + _result, + Err(ExecutorError { xcm_error: XcmError::ExpectationFalse, .. }) + )); + + Ok(()) } - expect_transact_status { + #[benchmark] + fn expect_transact_status() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); - let worst_error = || -> MaybeErrorCode { - vec![0; MaxDispatchErrorLen::get() as usize].into() - }; + let worst_error = + || -> MaybeErrorCode { vec![0; MaxDispatchErrorLen::get() as usize].into() }; executor.set_transact_status(worst_error()); let instruction = Instruction::ExpectTransactStatus(worst_error()); let xcm = Xcm(vec![instruction]); let mut _result = Ok(()); - }: { - _result = executor.bench_process(xcm); - } verify { + #[block] + { + _result = executor.bench_process(xcm); + } assert!(matches!(_result, Ok(..))); + Ok(()) } - query_pallet { + #[benchmark] + fn query_pallet() -> Result<(), BenchmarkError> { let (sender_account, sender_location) = account_and_location::(1); let query_id = Default::default(); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let max_weight = Default::default(); - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &sender_location, - &destination, - FeeReason::QueryPallet, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::QueryPallet, + ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); let mut executor = new_executor::(sender_location); if let Some(expected_fees_mode) = expected_fees_mode { @@ -430,15 +577,19 @@ benchmarks! { response_info: QueryResponseInfo { destination, query_id, max_weight }, }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // Check we charged the delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 + + Ok(()) } - expect_pallet { + #[benchmark] + fn expect_pallet() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let valid_pallet = T::valid_pallet(); let instruction = Instruction::ExpectPallet { @@ -449,23 +600,27 @@ benchmarks! { min_crate_minor: valid_pallet.crate_version.minor.into(), }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // the execution succeeding is all we need to verify this xcm was successful + Ok(()) } - report_transact_status { + #[benchmark] + fn report_transact_status() -> Result<(), BenchmarkError> { let (sender_account, sender_location) = account_and_location::(1); let query_id = Default::default(); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let max_weight = Default::default(); - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &sender_location, - &destination, - FeeReason::Report, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery( + &sender_location, + &destination, + FeeReason::Report, + ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); let mut executor = new_executor::(sender_location); @@ -483,84 +638,102 @@ benchmarks! { max_weight, }); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // Check we charged the delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 + Ok(()) } - clear_transact_status { + #[benchmark] + fn clear_transact_status() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); executor.set_transact_status(b"MyError".to_vec().into()); let instruction = Instruction::ClearTransactStatus; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.transact_status(), &MaybeErrorCode::Success); + Ok(()) } - set_topic { + #[benchmark] + fn set_topic() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); let instruction = Instruction::SetTopic([1; 32]); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.topic(), &Some([1; 32])); + Ok(()) } - clear_topic { + #[benchmark] + fn clear_topic() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); executor.set_topic(Some([2; 32])); let instruction = Instruction::ClearTopic; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.topic(), &None); + Ok(()) } - exchange_asset { + #[benchmark] + fn exchange_asset() -> Result<(), BenchmarkError> { let (give, want) = T::worst_case_asset_exchange().map_err(|_| BenchmarkError::Skip)?; let assets = give.clone(); let mut executor = new_executor::(Default::default()); executor.set_holding(give.into()); - let instruction = Instruction::ExchangeAsset { - give: assets.into(), - want: want.clone(), - maximal: true, - }; + let instruction = + Instruction::ExchangeAsset { give: assets.into(), want: want.clone(), maximal: true }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.holding(), &want.into()); + Ok(()) } - universal_origin { + #[benchmark] + fn universal_origin() -> Result<(), BenchmarkError> { let (origin, alias) = T::universal_alias().map_err(|_| BenchmarkError::Skip)?; let mut executor = new_executor::(origin); let instruction = Instruction::UniversalOrigin(alias); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } use frame_support::traits::Get; let universal_location = ::UniversalLocation::get(); - assert_eq!(executor.origin(), &Some(Junctions::from([alias]).relative_to(&universal_location))); + assert_eq!( + executor.origin(), + &Some(Junctions::from([alias]).relative_to(&universal_location)) + ); + + Ok(()) } - export_message { - let x in 1 .. 1000; + #[benchmark] + fn export_message(x: Linear<1, 1000>) -> Result<(), BenchmarkError> { // The `inner_xcm` influences `ExportMessage` total weight based on // `inner_xcm.encoded_size()`, so for this benchmark use smallest encoded instruction // to approximate weight per "unit" of encoded size; then actual weight can be estimated @@ -570,11 +743,12 @@ benchmarks! { // Get `origin`, `network` and `destination` from configured runtime. let (origin, network, destination) = T::export_message_origin_and_destination()?; - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &origin, - &destination.clone().into(), - FeeReason::Export { network, destination: destination.clone() }, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery( + &origin, + &destination.clone().into(), + FeeReason::Export { network, destination: destination.clone() }, + ); let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap(); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); @@ -585,37 +759,39 @@ benchmarks! { if let Some(expected_assets_in_holding) = expected_assets_in_holding { executor.set_holding(expected_assets_in_holding.into()); } - let xcm = Xcm(vec![ExportMessage { - network, destination: destination.clone(), xcm: inner_xcm, - }]); - }: { - executor.bench_process(xcm)?; - } verify { + let xcm = + Xcm(vec![ExportMessage { network, destination: destination.clone(), xcm: inner_xcm }]); + #[block] + { + executor.bench_process(xcm)?; + } // Check we charged the delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 + Ok(()) } - set_fees_mode { + #[benchmark] + fn set_fees_mode() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); executor.set_fees_mode(FeesMode { jit_withdraw: false }); let instruction = Instruction::SetFeesMode { jit_withdraw: true }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.fees_mode(), &FeesMode { jit_withdraw: true }); + Ok(()) } - lock_asset { + #[benchmark] + fn lock_asset() -> Result<(), BenchmarkError> { let (unlocker, owner, asset) = T::unlockable_asset()?; - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &owner, - &unlocker, - FeeReason::LockAsset, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery(&owner, &unlocker, FeeReason::LockAsset); let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap(); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); @@ -635,15 +811,18 @@ benchmarks! { let instruction = Instruction::LockAsset { asset, unlocker }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // Check delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 + Ok(()) } - unlock_asset { + #[benchmark] + fn unlock_asset() -> Result<(), BenchmarkError> { use xcm_executor::traits::{AssetLock, Enact}; let (unlocker, owner, asset) = T::unlockable_asset()?; @@ -663,13 +842,15 @@ benchmarks! { // ... then unlock them with the UnlockAsset instruction. let instruction = Instruction::UnlockAsset { asset, target: owner }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { - + #[block] + { + executor.bench_process(xcm)?; + } + Ok(()) } - note_unlockable { + #[benchmark] + fn note_unlockable() -> Result<(), BenchmarkError> { use xcm_executor::traits::{AssetLock, Enact}; let (unlocker, owner, asset) = T::unlockable_asset()?; @@ -689,13 +870,15 @@ benchmarks! { // ... then note them as unlockable with the NoteUnlockable instruction. let instruction = Instruction::NoteUnlockable { asset, owner }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { - + #[block] + { + executor.bench_process(xcm)?; + } + Ok(()) } - request_unlock { + #[benchmark] + fn request_unlock() -> Result<(), BenchmarkError> { use xcm_executor::traits::{AssetLock, Enact}; let (locker, owner, asset) = T::unlockable_asset()?; @@ -710,11 +893,12 @@ benchmarks! { .enact() .map_err(|_| BenchmarkError::Skip)?; - let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( - &owner, - &locker, - FeeReason::RequestUnlock, - ); + let (expected_fees_mode, expected_assets_in_holding) = + T::DeliveryHelper::ensure_successful_delivery( + &owner, + &locker, + FeeReason::RequestUnlock, + ); let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap(); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); @@ -728,15 +912,18 @@ benchmarks! { } let instruction = Instruction::RequestUnlock { asset, locker }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } // Check we charged the delivery fees assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before); // TODO: Potentially add new trait to XcmSender to detect a queued outgoing message. #4426 + Ok(()) } - unpaid_execution { + #[benchmark] + fn unpaid_execution() -> Result<(), BenchmarkError> { let mut executor = new_executor::(Default::default()); executor.set_origin(Some(Here.into())); @@ -746,21 +933,27 @@ benchmarks! { }; let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; + #[block] + { + executor.bench_process(xcm)?; + } + Ok(()) } - alias_origin { + #[benchmark] + fn alias_origin() -> Result<(), BenchmarkError> { let (origin, target) = T::alias_origin().map_err(|_| BenchmarkError::Skip)?; let mut executor = new_executor::(origin); let instruction = Instruction::AliasOrigin(target.clone()); let xcm = Xcm(vec![instruction]); - }: { - executor.bench_process(xcm)?; - } verify { + #[block] + { + executor.bench_process(xcm)?; + } assert_eq!(executor.origin(), &Some(target)); + Ok(()) } impl_benchmark_test_suite!( diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 4d44d75e34dd..85beba03b157 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -5,6 +5,8 @@ description = "A pallet for handling XCM programs." authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -23,8 +25,8 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } xcm = { workspace = true } -xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-executor = { workspace = true } xcm-runtime-apis = { workspace = true } # marked optional, used in benchmarking @@ -33,8 +35,8 @@ pallet-balances = { optional = true, workspace = true } [dev-dependencies] pallet-assets = { workspace = true, default-features = true } -polkadot-runtime-parachains = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } [features] default = ["std"] @@ -68,6 +70,7 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index 404b9358d4d9..3ca048057ee4 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::*; -use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; +use frame_benchmarking::v2::*; use frame_support::{assert_ok, weights::Weight}; use frame_system::RawOrigin; use xcm::latest::prelude::*; @@ -83,25 +83,41 @@ pub trait Config: crate::Config { fn get_asset() -> Asset; } -benchmarks! { - send { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn send() -> Result<(), BenchmarkError> { let send_origin = T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let msg = Xcm(vec![ClearOrigin]); - let versioned_dest: VersionedLocation = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); + let versioned_dest: VersionedLocation = T::reachable_dest() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))? + .into(); let versioned_msg = VersionedXcm::from(msg); - }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) - teleport_assets { - let (asset, destination) = T::teleportable_asset_and_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )?; + // Ensure that origin can send to destination + // (e.g. setup delivery fees, ensure router setup, ...) + T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &versioned_dest.clone().try_into().unwrap(), + FeeReason::ChargeFees, + ); + + #[extrinsic_call] + _(send_origin as RuntimeOrigin, Box::new(versioned_dest), Box::new(versioned_msg)); + + Ok(()) + } + + #[benchmark] + fn teleport_assets() -> Result<(), BenchmarkError> { + let (asset, destination) = T::teleportable_asset_and_dest() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; let assets: Assets = asset.clone().into(); @@ -109,11 +125,13 @@ benchmarks! { let send_origin = RawOrigin::Signed(caller.clone()); let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmTeleportFilter::contains(&(origin_location.clone(), assets.clone().into_inner())) { + if !T::XcmTeleportFilter::contains(&(origin_location.clone(), assets.clone().into_inner())) + { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } - // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + // Ensure that origin can send to destination + // (e.g. setup delivery fees, ensure router setup, ...) let (_, _) = T::DeliveryHelper::ensure_successful_delivery( &origin_location, &destination, @@ -127,18 +145,23 @@ benchmarks! { &Asset { fun: Fungible(*amount), id: asset.id }, &origin_location, None, - ).map_err(|error| { - tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error); - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + ) + .map_err(|error| { + tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + })?; + }, + NonFungible(_instance) => { + ::AssetTransactor::deposit_asset( + &asset, + &origin_location, + None, + ) + .map_err(|error| { + tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; }, - NonFungible(instance) => { - ::AssetTransactor::deposit_asset(&asset, &origin_location, None) - .map_err(|error| { - tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) - })?; - } }; let recipient = [0u8; 32]; @@ -146,12 +169,23 @@ benchmarks! { let versioned_beneficiary: VersionedLocation = AccountId32 { network: None, id: recipient.into() }.into(); let versioned_assets: VersionedAssets = assets.into(); - }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) - reserve_transfer_assets { - let (asset, destination) = T::reserve_transferable_asset_and_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )?; + #[extrinsic_call] + _( + send_origin, + Box::new(versioned_dest), + Box::new(versioned_beneficiary), + Box::new(versioned_assets), + 0, + ); + + Ok(()) + } + + #[benchmark] + fn reserve_transfer_assets() -> Result<(), BenchmarkError> { + let (asset, destination) = T::reserve_transferable_asset_and_dest() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; let assets: Assets = asset.clone().into(); @@ -159,11 +193,15 @@ benchmarks! { let send_origin = RawOrigin::Signed(caller.clone()); let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into()) .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - if !T::XcmReserveTransferFilter::contains(&(origin_location.clone(), assets.clone().into_inner())) { + if !T::XcmReserveTransferFilter::contains(&( + origin_location.clone(), + assets.clone().into_inner(), + )) { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } - // Ensure that origin can send to destination (e.g. setup delivery fees, ensure router setup, ...) + // Ensure that origin can send to destination + // (e.g. setup delivery fees, ensure router setup, ...) let (_, _) = T::DeliveryHelper::ensure_successful_delivery( &origin_location, &destination, @@ -177,18 +215,23 @@ benchmarks! { &Asset { fun: Fungible(*amount), id: asset.id.clone() }, &origin_location, None, - ).map_err(|error| { - tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error); - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + ) + .map_err(|error| { + tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + })?; + }, + NonFungible(_instance) => { + ::AssetTransactor::deposit_asset( + &asset, + &origin_location, + None, + ) + .map_err(|error| { + tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; }, - NonFungible(instance) => { - ::AssetTransactor::deposit_asset(&asset, &origin_location, None) - .map_err(|error| { - tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) - })?; - } }; let recipient = [0u8; 32]; @@ -196,8 +239,16 @@ benchmarks! { let versioned_beneficiary: VersionedLocation = AccountId32 { network: None, id: recipient.into() }.into(); let versioned_assets: VersionedAssets = assets.into(); - }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) - verify { + + #[extrinsic_call] + _( + send_origin, + Box::new(versioned_dest), + Box::new(versioned_beneficiary), + Box::new(versioned_assets), + 0, + ); + match &asset.fun { Fungible(amount) => { assert_ok!(::AssetTransactor::withdraw_asset( @@ -206,20 +257,22 @@ benchmarks! { None, )); }, - NonFungible(instance) => { + NonFungible(_instance) => { assert_ok!(::AssetTransactor::withdraw_asset( &asset, &destination, None, )); - } + }, }; + + Ok(()) } - transfer_assets { - let (assets, fee_index, destination, verify) = T::set_up_complex_asset_transfer().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )?; + #[benchmark] + fn transfer_assets() -> Result<(), BenchmarkError> { + let (assets, _fee_index, destination, verify_fn) = T::set_up_complex_asset_transfer() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; let caller: T::AccountId = whitelisted_caller(); let send_origin = RawOrigin::Signed(caller.clone()); let recipient = [0u8; 32]; @@ -227,13 +280,32 @@ benchmarks! { let versioned_beneficiary: VersionedLocation = AccountId32 { network: None, id: recipient.into() }.into(); let versioned_assets: VersionedAssets = assets.into(); - }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0, WeightLimit::Unlimited) - verify { + + // Ensure that origin can send to destination + // (e.g. setup delivery fees, ensure router setup, ...) + T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &versioned_dest.clone().try_into().unwrap(), + FeeReason::ChargeFees, + ); + + #[extrinsic_call] + _( + send_origin, + Box::new(versioned_dest), + Box::new(versioned_beneficiary), + Box::new(versioned_assets), + 0, + WeightLimit::Unlimited, + ); + // run provided verification function - verify(); + verify_fn(); + Ok(()) } - execute { + #[benchmark] + fn execute() -> Result<(), BenchmarkError> { let execute_origin = T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone()) @@ -243,147 +315,287 @@ benchmarks! { return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) } let versioned_msg = VersionedXcm::from(msg); - }: _>(execute_origin, Box::new(versioned_msg), Weight::MAX) - force_xcm_version { - let loc = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )?; + #[extrinsic_call] + _(execute_origin as RuntimeOrigin, Box::new(versioned_msg), Weight::MAX); + + Ok(()) + } + + #[benchmark] + fn force_xcm_version() -> Result<(), BenchmarkError> { + let loc = T::reachable_dest() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; let xcm_version = 2; - }: _(RawOrigin::Root, Box::new(loc), xcm_version) - force_default_xcm_version {}: _(RawOrigin::Root, Some(2)) + #[extrinsic_call] + _(RawOrigin::Root, Box::new(loc), xcm_version); + + Ok(()) + } + + #[benchmark] + fn force_default_xcm_version() { + #[extrinsic_call] + _(RawOrigin::Root, Some(2)) + } + + #[benchmark] + fn force_subscribe_version_notify() -> Result<(), BenchmarkError> { + let versioned_loc: VersionedLocation = T::reachable_dest() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))? + .into(); + + // Ensure that origin can send to destination + // (e.g. setup delivery fees, ensure router setup, ...) + T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &versioned_loc.clone().try_into().unwrap(), + FeeReason::ChargeFees, + ); + + #[extrinsic_call] + _(RawOrigin::Root, Box::new(versioned_loc)); - force_subscribe_version_notify { - let versioned_loc: VersionedLocation = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); - }: _(RawOrigin::Root, Box::new(versioned_loc)) + Ok(()) + } - force_unsubscribe_version_notify { - let loc = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )?; + #[benchmark] + fn force_unsubscribe_version_notify() -> Result<(), BenchmarkError> { + let loc = T::reachable_dest() + .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; let versioned_loc: VersionedLocation = loc.clone().into(); + + // Ensure that origin can send to destination + // (e.g. setup delivery fees, ensure router setup, ...) + T::DeliveryHelper::ensure_successful_delivery( + &Default::default(), + &versioned_loc.clone().try_into().unwrap(), + FeeReason::ChargeFees, + ); + let _ = crate::Pallet::::request_version_notify(loc); - }: _(RawOrigin::Root, Box::new(versioned_loc)) - force_suspension {}: _(RawOrigin::Root, true) + #[extrinsic_call] + _(RawOrigin::Root, Box::new(versioned_loc)); + + Ok(()) + } - migrate_supported_version { + #[benchmark] + fn force_suspension() { + #[extrinsic_call] + _(RawOrigin::Root, true) + } + + #[benchmark] + fn migrate_supported_version() { let old_version = XCM_VERSION - 1; let loc = VersionedLocation::from(Location::from(Parent)); SupportedVersion::::insert(old_version, loc, old_version); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero()); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::MigrateSupportedVersion, + Weight::zero(), + ); + } } - migrate_version_notifiers { + #[benchmark] + fn migrate_version_notifiers() { let old_version = XCM_VERSION - 1; let loc = VersionedLocation::from(Location::from(Parent)); VersionNotifiers::::insert(old_version, loc, 0); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero()); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::MigrateVersionNotifiers, + Weight::zero(), + ); + } } - already_notified_target { - let loc = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads(1))), - )?; + #[benchmark] + fn already_notified_target() -> Result<(), BenchmarkError> { + let loc = T::reachable_dest().ok_or(BenchmarkError::Override( + BenchmarkResult::from_weight(T::DbWeight::get().reads(1)), + ))?; let loc = VersionedLocation::from(loc); let current_version = T::AdvertisedXcmVersion::get(); - VersionNotifyTargets::::insert(current_version, loc, (0, Weight::zero(), current_version)); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); + VersionNotifyTargets::::insert( + current_version, + loc, + (0, Weight::zero(), current_version), + ); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::NotifyCurrentTargets(None), + Weight::zero(), + ); + } + + Ok(()) } - notify_current_targets { - let loc = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), - )?; + #[benchmark] + fn notify_current_targets() -> Result<(), BenchmarkError> { + let loc = T::reachable_dest().ok_or(BenchmarkError::Override( + BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3)), + ))?; let loc = VersionedLocation::from(loc); let current_version = T::AdvertisedXcmVersion::get(); let old_version = current_version - 1; VersionNotifyTargets::::insert(current_version, loc, (0, Weight::zero(), old_version)); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::NotifyCurrentTargets(None), + Weight::zero(), + ); + } + + Ok(()) } - notify_target_migration_fail { + #[benchmark] + fn notify_target_migration_fail() { let newer_xcm_version = xcm::prelude::XCM_VERSION; let older_xcm_version = newer_xcm_version - 1; - let bad_location: Location = Plurality { - id: BodyId::Unit, - part: BodyPart::Voice, - }.into(); + let bad_location: Location = Plurality { id: BodyId::Unit, part: BodyPart::Voice }.into(); let bad_location = VersionedLocation::from(bad_location) .into_version(older_xcm_version) .expect("Version convertion should work"); let current_version = T::AdvertisedXcmVersion::get(); - VersionNotifyTargets::::insert(current_version, bad_location, (0, Weight::zero(), current_version)); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + VersionNotifyTargets::::insert( + current_version, + bad_location, + (0, Weight::zero(), current_version), + ); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::MigrateAndNotifyOldTargets, + Weight::zero(), + ); + } } - migrate_version_notify_targets { + #[benchmark] + fn migrate_version_notify_targets() { let current_version = T::AdvertisedXcmVersion::get(); let old_version = current_version - 1; let loc = VersionedLocation::from(Location::from(Parent)); VersionNotifyTargets::::insert(old_version, loc, (0, Weight::zero(), current_version)); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::MigrateAndNotifyOldTargets, + Weight::zero(), + ); + } } - migrate_and_notify_old_targets { - let loc = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), - )?; + #[benchmark] + fn migrate_and_notify_old_targets() -> Result<(), BenchmarkError> { + let loc = T::reachable_dest().ok_or(BenchmarkError::Override( + BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3)), + ))?; let loc = VersionedLocation::from(loc); let old_version = T::AdvertisedXcmVersion::get() - 1; VersionNotifyTargets::::insert(old_version, loc, (0, Weight::zero(), old_version)); - }: { - crate::Pallet::::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); + + #[block] + { + crate::Pallet::::check_xcm_version_change( + VersionMigrationStage::MigrateAndNotifyOldTargets, + Weight::zero(), + ); + } + + Ok(()) } - new_query { + #[benchmark] + fn new_query() { let responder = Location::from(Parent); let timeout = 1u32.into(); let match_querier = Location::from(Here); - }: { - crate::Pallet::::new_query(responder, timeout, match_querier); + + #[block] + { + crate::Pallet::::new_query(responder, timeout, match_querier); + } } - take_response { + #[benchmark] + fn take_response() { let responder = Location::from(Parent); let timeout = 1u32.into(); let match_querier = Location::from(Here); let query_id = crate::Pallet::::new_query(responder, timeout, match_querier); - let infos = (0 .. xcm::v3::MaxPalletsInfo::get()).map(|_| PalletInfo::new( - u32::MAX, - (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::>().try_into().unwrap(), - (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::>().try_into().unwrap(), - u32::MAX, - u32::MAX, - u32::MAX, - ).unwrap()).collect::>(); - crate::Pallet::::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); - }: { - as QueryHandler>::take_response(query_id); + let infos = (0..xcm::v3::MaxPalletsInfo::get()) + .map(|_| { + PalletInfo::new( + u32::MAX, + (0..xcm::v3::MaxPalletNameLen::get()) + .map(|_| 97u8) + .collect::>() + .try_into() + .unwrap(), + (0..xcm::v3::MaxPalletNameLen::get()) + .map(|_| 97u8) + .collect::>() + .try_into() + .unwrap(), + u32::MAX, + u32::MAX, + u32::MAX, + ) + .unwrap() + }) + .collect::>(); + crate::Pallet::::expect_response( + query_id, + Response::PalletsInfo(infos.try_into().unwrap()), + ); + + #[block] + { + as QueryHandler>::take_response(query_id); + } } - claim_assets { + #[benchmark] + fn claim_assets() -> Result<(), BenchmarkError> { let claim_origin = RawOrigin::Signed(whitelisted_caller()); - let claim_location = T::ExecuteXcmOrigin::try_origin(claim_origin.clone().into()).map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let claim_location = T::ExecuteXcmOrigin::try_origin(claim_origin.clone().into()) + .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; let asset: Asset = T::get_asset(); // Trap assets for claiming later crate::Pallet::::drop_assets( &claim_location, asset.clone().into(), - &XcmContext { origin: None, message_id: [0u8; 32], topic: None } + &XcmContext { origin: None, message_id: [0u8; 32], topic: None }, + ); + let versioned_assets = VersionedAssets::from(Assets::from(asset)); + + #[extrinsic_call] + _( + claim_origin, + Box::new(versioned_assets), + Box::new(VersionedLocation::from(claim_location)), ); - let versioned_assets = VersionedAssets::V4(asset.into()); - }: _>(claim_origin.into(), Box::new(versioned_assets), Box::new(VersionedLocation::V4(claim_location))) + + Ok(()) + } impl_benchmark_test_suite!( Pallet, diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 9b8f735b478f..6360298b21c3 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -75,6 +75,7 @@ use xcm_runtime_apis::{ #[cfg(any(feature = "try-runtime", test))] use sp_runtime::TryRuntimeError; +use xcm_executor::traits::{FeeManager, FeeReason}; pub trait WeightInfo { fn send() -> Weight; @@ -240,7 +241,7 @@ pub mod pallet { type XcmExecuteFilter: Contains<(Location, Xcm<::RuntimeCall>)>; /// Something to execute an XCM message. - type XcmExecutor: ExecuteXcm<::RuntimeCall> + XcmAssetTransfers; + type XcmExecutor: ExecuteXcm<::RuntimeCall> + XcmAssetTransfers + FeeManager; /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. type XcmTeleportFilter: Contains<(Location, Vec)>; @@ -362,7 +363,10 @@ pub mod pallet { let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; let message_id = Self::send_xcm(interior, dest.clone(), message.clone()) - .map_err(Error::::from)?; + .map_err(|error| { + tracing::error!(target: "xcm::pallet_xcm::send", ?error, ?dest, ?message, "XCM send failed with error"); + Error::::from(error) + })?; let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; Self::deposit_event(e); Ok(message_id) @@ -1799,7 +1803,10 @@ impl Pallet { if let Some(remote_xcm) = remote_xcm { let (ticket, price) = validate_send::(dest.clone(), remote_xcm.clone()) - .map_err(Error::::from)?; + .map_err(|error| { + tracing::error!(target: "xcm::pallet_xcm::execute_xcm_transfer", ?error, ?dest, ?remote_xcm, "XCM validate_send failed with error"); + Error::::from(error) + })?; if origin != Here.into_location() { Self::charge_fees(origin.clone(), price.clone()).map_err(|error| { tracing::error!( @@ -1809,7 +1816,11 @@ impl Pallet { Error::::FeesNotMet })?; } - let message_id = T::XcmRouter::deliver(ticket).map_err(Error::::from)?; + let message_id = T::XcmRouter::deliver(ticket) + .map_err(|error| { + tracing::error!(target: "xcm::pallet_xcm::execute_xcm_transfer", ?error, ?dest, ?remote_xcm, "XCM deliver failed with error"); + Error::::from(error) + })?; let e = Event::Sent { origin, destination: dest, message: remote_xcm, message_id }; Self::deposit_event(e); @@ -2468,17 +2479,17 @@ impl Pallet { mut message: Xcm<()>, ) -> Result { let interior = interior.into(); + let local_origin = interior.clone().into(); let dest = dest.into(); - let maybe_fee_payer = if interior != Junctions::Here { + let is_waived = + ::is_waived(Some(&local_origin), FeeReason::ChargeFees); + if interior != Junctions::Here { message.0.insert(0, DescendOrigin(interior.clone())); - Some(interior.into()) - } else { - None - }; + } tracing::debug!(target: "xcm::send_xcm", "{:?}, {:?}", dest.clone(), message.clone()); let (ticket, price) = validate_send::(dest, message)?; - if let Some(fee_payer) = maybe_fee_payer { - Self::charge_fees(fee_payer, price).map_err(|e| { + if !is_waived { + Self::charge_fees(local_origin, price).map_err(|e| { tracing::error!( target: "xcm::pallet_xcm::send_xcm", ?e, @@ -2536,7 +2547,7 @@ impl Pallet { /// /// Returns execution result, events, and any forwarded XCMs to other locations. /// Meant to be used in the `xcm_runtime_apis::dry_run::DryRunApi` runtime API. - pub fn dry_run_xcm( + pub fn dry_run_xcm( origin_location: VersionedLocation, xcm: VersionedXcm, ) -> Result::RuntimeEvent>, XcmDryRunApiError> @@ -3067,7 +3078,7 @@ impl xcm_executor::traits::AssetLock for Pallet { } impl WrapVersion for Pallet { - fn wrap_version( + fn wrap_version( dest: &Location, xcm: impl Into>, ) -> Result, ()> { diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index e98a8f8d2ce7..350530f7711f 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -482,14 +482,14 @@ fn claim_assets_works() { // Even though assets are trapped, the extrinsic returns success. assert_ok!(XcmPallet::execute( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::V4(trapping_program)), + Box::new(VersionedXcm::from(trapping_program)), BaseXcmWeight::get() * 2, )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Expected `AssetsTrapped` event info. let source: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let versioned_assets = VersionedAssets::V4(Assets::from((Here, SEND_AMOUNT))); + let versioned_assets = VersionedAssets::from(Assets::from((Here, SEND_AMOUNT))); let hash = BlakeTwo256::hash_of(&(source.clone(), versioned_assets.clone())); // Assets were indeed trapped. @@ -512,10 +512,11 @@ fn claim_assets_works() { // Now claim them with the extrinsic. assert_ok!(XcmPallet::claim_assets( RuntimeOrigin::signed(ALICE), - Box::new(VersionedAssets::V4((Here, SEND_AMOUNT).into())), - Box::new(VersionedLocation::V4( - AccountId32 { network: None, id: ALICE.clone().into() }.into() - )), + Box::new(VersionedAssets::from(Assets::from((Here, SEND_AMOUNT)))), + Box::new(VersionedLocation::from(Location::from(AccountId32 { + network: None, + id: ALICE.clone().into() + }))), )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); assert_eq!(AssetTraps::::iter().collect::>(), vec![]); diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index 83b35d19cf7e..0843da86f038 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -6,6 +6,8 @@ edition.workspace = true license.workspace = true version = "7.0.0" publish = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true @@ -14,13 +16,15 @@ workspace = true proc-macro = true [dependencies] +Inflector = { workspace = true } proc-macro2 = { workspace = true } quote = { workspace = true } syn = { workspace = true } -Inflector = { workspace = true } [dev-dependencies] trybuild = { features = ["diff"], workspace = true } # NOTE: we have to explicitly specify `std` because of trybuild # https://github.com/paritytech/polkadot-sdk/pull/5167 xcm = { workspace = true, default-features = true, features = ["std"] } +# For testing macros. +frame-support = { workspace = true } diff --git a/polkadot/xcm/procedural/src/builder_pattern.rs b/polkadot/xcm/procedural/src/builder_pattern.rs index 09ead1389d19..34b89f13422c 100644 --- a/polkadot/xcm/procedural/src/builder_pattern.rs +++ b/polkadot/xcm/procedural/src/builder_pattern.rs @@ -20,8 +20,8 @@ use inflector::Inflector; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use syn::{ - Data, DataEnum, DeriveInput, Error, Expr, ExprLit, Fields, Ident, Lit, Meta, MetaNameValue, - Result, Variant, + Data, DataEnum, DeriveInput, Error, Expr, ExprLit, Fields, GenericArgument, Ident, Lit, Meta, + MetaNameValue, PathArguments, Result, Type, TypePath, Variant, }; pub fn derive(input: DeriveInput) -> Result { @@ -29,7 +29,7 @@ pub fn derive(input: DeriveInput) -> Result { Data::Enum(data_enum) => data_enum, _ => return Err(Error::new_spanned(&input, "Expected the `Instruction` enum")), }; - let builder_raw_impl = generate_builder_raw_impl(&input.ident, data_enum); + let builder_raw_impl = generate_builder_raw_impl(&input.ident, data_enum)?; let builder_impl = generate_builder_impl(&input.ident, data_enum)?; let builder_unpaid_impl = generate_builder_unpaid_impl(&input.ident, data_enum)?; let output = quote! { @@ -83,54 +83,12 @@ pub fn derive(input: DeriveInput) -> Result { Ok(output) } -fn generate_builder_raw_impl(name: &Ident, data_enum: &DataEnum) -> TokenStream2 { - let methods = data_enum.variants.iter().map(|variant| { - let variant_name = &variant.ident; - let method_name_string = &variant_name.to_string().to_snake_case(); - let method_name = syn::Ident::new(method_name_string, variant_name.span()); - let docs = get_doc_comments(variant); - let method = match &variant.fields { - Fields::Unit => { - quote! { - pub fn #method_name(mut self) -> Self { - self.instructions.push(#name::::#variant_name); - self - } - } - }, - Fields::Unnamed(fields) => { - let arg_names: Vec<_> = fields - .unnamed - .iter() - .enumerate() - .map(|(index, _)| format_ident!("arg{}", index)) - .collect(); - let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect(); - quote! { - pub fn #method_name(mut self, #(#arg_names: impl Into<#arg_types>),*) -> Self { - #(let #arg_names = #arg_names.into();)* - self.instructions.push(#name::::#variant_name(#(#arg_names),*)); - self - } - } - }, - Fields::Named(fields) => { - let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect(); - let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); - quote! { - pub fn #method_name(mut self, #(#arg_names: impl Into<#arg_types>),*) -> Self { - #(let #arg_names = #arg_names.into();)* - self.instructions.push(#name::::#variant_name { #(#arg_names),* }); - self - } - } - }, - }; - quote! { - #(#docs)* - #method - } - }); +fn generate_builder_raw_impl(name: &Ident, data_enum: &DataEnum) -> Result { + let methods = data_enum + .variants + .iter() + .map(|variant| convert_variant_to_method(name, variant, None)) + .collect::>>()?; let output = quote! { impl XcmBuilder { #(#methods)* @@ -140,7 +98,7 @@ fn generate_builder_raw_impl(name: &Ident, data_enum: &DataEnum) -> TokenStream2 } } }; - output + Ok(output) } fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result { @@ -160,13 +118,22 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result>>()?; @@ -175,57 +142,14 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result { - let arg_names: Vec<_> = fields - .unnamed - .iter() - .enumerate() - .map(|(index, _)| format_ident!("arg{}", index)) - .collect(); - let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect(); - quote! { - #(#docs)* - pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> XcmBuilder { - let mut new_instructions = self.instructions; - #(let #arg_names = #arg_names.into();)* - new_instructions.push(#name::::#variant_name(#(#arg_names),*)); - XcmBuilder { - instructions: new_instructions, - state: core::marker::PhantomData, - } - } - } - }, - Fields::Named(fields) => { - let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect(); - let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); - quote! { - #(#docs)* - pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> XcmBuilder { - let mut new_instructions = self.instructions; - #(let #arg_names = #arg_names.into();)* - new_instructions.push(#name::::#variant_name { #(#arg_names),* }); - XcmBuilder { - instructions: new_instructions, - state: core::marker::PhantomData, - } - } - } - }, - _ => - return Err(Error::new_spanned( - variant, - "Instructions that load the holding register should take operands", - )), - }; + let method = convert_variant_to_method( + name, + variant, + Some(quote! { XcmBuilder }), + )?; Ok(method) }) - .collect::, _>>()?; + .collect::>>()?; let first_impl = quote! { impl XcmBuilder { @@ -237,73 +161,59 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result = data_enum .variants .iter() - .filter(|variant| variant.ident == "ClearOrigin") + .filter(|variant| variant.ident == "ClearOrigin" || variant.ident == "SetHints") .map(|variant| { - let variant_name = &variant.ident; - let method_name_string = &variant_name.to_string().to_snake_case(); - let method_name = syn::Ident::new(method_name_string, variant_name.span()); - let docs = get_doc_comments(variant); - let method = match &variant.fields { - Fields::Unit => { - quote! { - #(#docs)* - pub fn #method_name(mut self) -> XcmBuilder { - self.instructions.push(#name::::#variant_name); - self - } - } - }, - _ => return Err(Error::new_spanned(variant, "ClearOrigin should have no fields")), - }; + let method = convert_variant_to_method(name, variant, None)?; Ok(method) }) - .collect::, _>>()?; + .collect::>>()?; // Then we require fees to be paid - let buy_execution_method = data_enum + let pay_fees_variants = data_enum .variants .iter() - .find(|variant| variant.ident == "BuyExecution") - .map_or( - Err(Error::new_spanned(&data_enum.variants, "No BuyExecution instruction")), - |variant| { - let variant_name = &variant.ident; - let method_name_string = &variant_name.to_string().to_snake_case(); - let method_name = syn::Ident::new(method_name_string, variant_name.span()); - let docs = get_doc_comments(variant); - let fields = match &variant.fields { - Fields::Named(fields) => { - let arg_names: Vec<_> = - fields.named.iter().map(|field| &field.ident).collect(); - let arg_types: Vec<_> = - fields.named.iter().map(|field| &field.ty).collect(); - quote! { - #(#docs)* - pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> XcmBuilder { - let mut new_instructions = self.instructions; - #(let #arg_names = #arg_names.into();)* - new_instructions.push(#name::::#variant_name { #(#arg_names),* }); - XcmBuilder { - instructions: new_instructions, - state: core::marker::PhantomData, - } - } - } - }, - _ => - return Err(Error::new_spanned( - variant, - "BuyExecution should have named fields", - )), - }; - Ok(fields) - }, - )?; + .map(|variant| { + let maybe_builder_attr = variant.attrs.iter().find(|attr| match attr.meta { + Meta::List(ref list) => list.path.is_ident("builder"), + _ => false, + }); + let builder_attr = match maybe_builder_attr { + Some(builder) => builder.clone(), + None => return Ok(None), /* It's not going to be an instruction that pays fees */ + }; + let Meta::List(ref list) = builder_attr.meta else { unreachable!("We checked before") }; + let inner_ident: Ident = syn::parse2(list.tokens.clone()).map_err(|_| { + Error::new_spanned( + &builder_attr, + "Expected `builder(loads_holding)` or `builder(pays_fees)`", + ) + })?; + let ident_to_match: Ident = syn::parse_quote!(pays_fees); + if inner_ident == ident_to_match { + Ok(Some(variant)) + } else { + Ok(None) // Must have been `loads_holding` instead. + } + }) + .collect::>>()?; + + let pay_fees_methods = pay_fees_variants + .into_iter() + .flatten() + .map(|variant| { + let method = convert_variant_to_method( + name, + variant, + Some(quote! { XcmBuilder }), + )?; + Ok(method) + }) + .collect::>>()?; let second_impl = quote! { impl XcmBuilder { #(#allowed_after_load_holding_methods)* - #buy_execution_method + #(#pay_fees_methods)* } }; @@ -321,35 +231,156 @@ fn generate_builder_unpaid_impl(name: &Ident, data_enum: &DataEnum) -> Result fields, - _ => - return Err(Error::new_spanned( - unpaid_execution_variant, - "UnpaidExecution should have named fields", - )), - }; - let arg_names: Vec<_> = fields.named.iter().map(|field| &field.ident).collect(); - let arg_types: Vec<_> = fields.named.iter().map(|field| &field.ty).collect(); + let method = convert_variant_to_method( + name, + &unpaid_execution_variant, + Some(quote! { XcmBuilder }), + )?; Ok(quote! { impl XcmBuilder { - #(#docs)* - pub fn #unpaid_execution_method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> XcmBuilder { - let mut new_instructions = self.instructions; - #(let #arg_names = #arg_names.into();)* - new_instructions.push(#name::::#unpaid_execution_ident { #(#arg_names),* }); - XcmBuilder { - instructions: new_instructions, - state: core::marker::PhantomData, + #method + } + }) +} + +// Have to call with `XcmBuilder` in allowed_after_load_holding_methods. +fn convert_variant_to_method( + name: &Ident, + variant: &Variant, + maybe_return_type: Option, +) -> Result { + let variant_name = &variant.ident; + let method_name_string = &variant_name.to_string().to_snake_case(); + let method_name = syn::Ident::new(method_name_string, variant_name.span()); + let docs = get_doc_comments(variant); + let method = match &variant.fields { + Fields::Unit => + if let Some(return_type) = maybe_return_type { + quote! { + pub fn #method_name(self) -> #return_type { + let mut new_instructions = self.instructions; + new_instructions.push(#name::::#variant_name); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + } else { + quote! { + pub fn #method_name(mut self) -> Self { + self.instructions.push(#name::::#variant_name); + self + } + } + }, + Fields::Unnamed(fields) => { + let arg_names: Vec<_> = fields + .unnamed + .iter() + .enumerate() + .map(|(index, _)| format_ident!("arg{}", index)) + .collect(); + let arg_types: Vec<_> = fields.unnamed.iter().map(|field| &field.ty).collect(); + if let Some(return_type) = maybe_return_type { + quote! { + pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),*) -> #return_type { + let mut new_instructions = self.instructions; + #(let #arg_names = #arg_names.into();)* + new_instructions.push(#name::::#variant_name(#(#arg_names),*)); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + } else { + quote! { + pub fn #method_name(mut self, #(#arg_names: impl Into<#arg_types>),*) -> Self { + #(let #arg_names = #arg_names.into();)* + self.instructions.push(#name::::#variant_name(#(#arg_names),*)); + self + } } } - } + }, + Fields::Named(fields) => { + let normal_fields: Vec<_> = fields + .named + .iter() + .filter(|field| { + if let Type::Path(TypePath { path, .. }) = &field.ty { + for segment in &path.segments { + if segment.ident == format_ident!("BoundedVec") { + return false; + } + } + true + } else { + true + } + }) + .collect(); + let bounded_fields: Vec<_> = fields + .named + .iter() + .filter(|field| { + if let Type::Path(TypePath { path, .. }) = &field.ty { + for segment in &path.segments { + if segment.ident == format_ident!("BoundedVec") { + return true; + } + } + false + } else { + false + } + }) + .collect(); + let arg_names: Vec<_> = normal_fields.iter().map(|field| &field.ident).collect(); + let arg_types: Vec<_> = normal_fields.iter().map(|field| &field.ty).collect(); + let bounded_names: Vec<_> = bounded_fields.iter().map(|field| &field.ident).collect(); + let bounded_types = bounded_fields + .iter() + .map(|field| extract_generic_argument(&field.ty, 0, "BoundedVec's inner type")) + .collect::>>()?; + let bounded_sizes = bounded_fields + .iter() + .map(|field| extract_generic_argument(&field.ty, 1, "BoundedVec's size")) + .collect::>>()?; + let comma_in_the_middle = if normal_fields.is_empty() { + quote! {} + } else { + quote! {,} + }; + if let Some(return_type) = maybe_return_type { + quote! { + pub fn #method_name(self, #(#arg_names: impl Into<#arg_types>),* #comma_in_the_middle #(#bounded_names: Vec<#bounded_types>),*) -> #return_type { + let mut new_instructions = self.instructions; + #(let #arg_names = #arg_names.into();)* + #(let #bounded_names = BoundedVec::<#bounded_types, #bounded_sizes>::truncate_from(#bounded_names);)* + new_instructions.push(#name::::#variant_name { #(#arg_names),* #comma_in_the_middle #(#bounded_names),* }); + XcmBuilder { + instructions: new_instructions, + state: core::marker::PhantomData, + } + } + } + } else { + quote! { + pub fn #method_name(mut self, #(#arg_names: impl Into<#arg_types>),* #comma_in_the_middle #(#bounded_names: Vec<#bounded_types>),*) -> Self { + #(let #arg_names = #arg_names.into();)* + #(let #bounded_names = BoundedVec::<#bounded_types, #bounded_sizes>::truncate_from(#bounded_names);)* + self.instructions.push(#name::::#variant_name { #(#arg_names),* #comma_in_the_middle #(#bounded_names),* }); + self + } + } + } + }, + }; + Ok(quote! { + #(#docs)* + #method }) } @@ -367,3 +398,40 @@ fn get_doc_comments(variant: &Variant) -> Vec { .map(|doc| syn::parse_str::(&format!("/// {}", doc)).unwrap()) .collect() } + +fn extract_generic_argument<'a>( + field_ty: &'a Type, + index: usize, + expected_msg: &str, +) -> Result<&'a Ident> { + if let Type::Path(type_path) = field_ty { + if let Some(segment) = type_path.path.segments.last() { + if let PathArguments::AngleBracketed(angle_brackets) = &segment.arguments { + let args: Vec<_> = angle_brackets.args.iter().collect(); + if let Some(GenericArgument::Type(Type::Path(TypePath { path, .. }))) = + args.get(index) + { + return path.get_ident().ok_or_else(|| { + Error::new_spanned( + path, + format!("Expected an identifier for {}", expected_msg), + ) + }); + } + return Err(Error::new_spanned( + angle_brackets, + format!("Expected a generic argument at index {} for {}", index, expected_msg), + )); + } + return Err(Error::new_spanned( + &segment.arguments, + format!("Expected angle-bracketed arguments for {}", expected_msg), + )); + } + return Err(Error::new_spanned( + &type_path.path, + format!("Expected at least one path segment for {}", expected_msg), + )); + } + Err(Error::new_spanned(field_ty, format!("Expected a path type for {}", expected_msg))) +} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs b/polkadot/xcm/procedural/src/enum_variants.rs similarity index 51% rename from polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs rename to polkadot/xcm/procedural/src/enum_variants.rs index 070f0be6bacc..f9f2d9e15675 100644 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.rs +++ b/polkadot/xcm/procedural/src/enum_variants.rs @@ -14,19 +14,25 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Test error when an instruction that loads the holding register doesn't take operands. - -use xcm_procedural::Builder; - -struct Xcm(pub Vec>); - -#[derive(Builder)] -enum Instruction { - #[builder(loads_holding)] - WithdrawAsset, - BuyExecution { fees: u128 }, - UnpaidExecution { weight_limit: (u32, u32) }, - Transact { call: Call }, +//! Simple derive macro for getting the number of variants in an enum. + +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote}; +use syn::{Data, DeriveInput, Error, Result}; + +pub fn derive(input: DeriveInput) -> Result { + let data_enum = match &input.data { + Data::Enum(data_enum) => data_enum, + _ => return Err(Error::new_spanned(&input, "Expected an enum.")), + }; + let ident = format_ident!("{}NumVariants", input.ident); + let number_of_variants: usize = data_enum.variants.iter().count(); + Ok(quote! { + pub struct #ident; + impl ::frame_support::traits::Get for #ident { + fn get() -> u32 { + #number_of_variants as u32 + } + } + }) } - -fn main() {} diff --git a/polkadot/xcm/procedural/src/lib.rs b/polkadot/xcm/procedural/src/lib.rs index 4980d84d3282..0dd270286f69 100644 --- a/polkadot/xcm/procedural/src/lib.rs +++ b/polkadot/xcm/procedural/src/lib.rs @@ -20,25 +20,12 @@ use proc_macro::TokenStream; use syn::{parse_macro_input, DeriveInput}; mod builder_pattern; -mod v2; +mod enum_variants; mod v3; mod v4; +mod v5; mod weight_info; -#[proc_macro] -pub fn impl_conversion_functions_for_multilocation_v2(input: TokenStream) -> TokenStream { - v2::multilocation::generate_conversion_functions(input) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - -#[proc_macro] -pub fn impl_conversion_functions_for_junctions_v2(input: TokenStream) -> TokenStream { - v2::junctions::generate_conversion_functions(input) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - #[proc_macro_derive(XcmWeightInfoTrait)] pub fn derive_xcm_weight_info(item: TokenStream) -> TokenStream { weight_info::derive(item) @@ -72,6 +59,20 @@ pub fn impl_conversion_functions_for_junctions_v4(input: TokenStream) -> TokenSt .into() } +#[proc_macro] +pub fn impl_conversion_functions_for_junctions_v5(input: TokenStream) -> TokenStream { + v5::junctions::generate_conversion_functions(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro] +pub fn impl_conversion_functions_for_location_v5(input: TokenStream) -> TokenStream { + v5::location::generate_conversion_functions(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + /// This is called on the `Instruction` enum, not on the `Xcm` struct, /// and allows for the following syntax for building XCMs: /// let message = Xcm::builder() @@ -86,3 +87,11 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { .unwrap_or_else(syn::Error::into_compile_error) .into() } + +#[proc_macro_derive(NumVariants)] +pub fn derive_num_variants(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + enum_variants::derive(input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} diff --git a/polkadot/xcm/procedural/src/v2.rs b/polkadot/xcm/procedural/src/v2.rs deleted file mode 100644 index 6878f7755cc7..000000000000 --- a/polkadot/xcm/procedural/src/v2.rs +++ /dev/null @@ -1,226 +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 . - -use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote}; -use syn::{Result, Token}; - -pub mod multilocation { - use super::*; - - pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result { - if !input.is_empty() { - return Err(syn::Error::new(Span::call_site(), "No arguments expected")) - } - - // Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents. - let from_tuples = generate_conversion_from_tuples(8); - let from_v3 = generate_conversion_from_v3(); - - Ok(quote! { - #from_tuples - #from_v3 - }) - } - - fn generate_conversion_from_tuples(max_parents: u8) -> TokenStream { - let mut from_tuples = (0..8usize) - .map(|num_junctions| { - let junctions = - (0..=num_junctions).map(|_| format_ident!("Junction")).collect::>(); - let idents = - (0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::>(); - let variant = &format_ident!("X{}", num_junctions + 1); - let array_size = num_junctions + 1; - - let mut from_tuple = quote! { - impl From<( #(#junctions,)* )> for MultiLocation { - fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self { - MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) } - } - } - - impl From<(u8, #(#junctions),*)> for MultiLocation { - fn from( ( parents, #(#idents),* ): (u8, #(#junctions),* ) ) -> Self { - MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) } - } - } - - impl From<(Ancestor, #(#junctions),*)> for MultiLocation { - fn from( ( Ancestor(parents), #(#idents),* ): (Ancestor, #(#junctions),* ) ) -> Self { - MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) } - } - } - - impl From<[Junction; #array_size]> for MultiLocation { - fn from(j: [Junction; #array_size]) -> Self { - let [#(#idents),*] = j; - MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) } - } - } - }; - - let from_parent_tuples = (1..=max_parents).map(|cur_parents| { - let parents = - (0..cur_parents).map(|_| format_ident!("Parent")).collect::>(); - let underscores = - (0..cur_parents).map(|_| Token![_](Span::call_site())).collect::>(); - - quote! { - impl From<( #(#parents,)* #(#junctions),* )> for MultiLocation { - fn from( (#(#underscores,)* #(#idents),*): ( #(#parents,)* #(#junctions),* ) ) -> Self { - MultiLocation { parents: #cur_parents, interior: Junctions::#variant( #(#idents),* ) } - } - } - } - }); - - from_tuple.extend(from_parent_tuples); - from_tuple - }) - .collect::(); - - let from_parent_junctions_tuples = (1..=max_parents).map(|cur_parents| { - let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::>(); - let underscores = - (0..cur_parents).map(|_| Token![_](Span::call_site())).collect::>(); - - quote! { - impl From<( #(#parents,)* Junctions )> for MultiLocation { - fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self { - MultiLocation { parents: #cur_parents, interior: junctions } - } - } - } - }); - from_tuples.extend(from_parent_junctions_tuples); - - quote! { - impl From for MultiLocation { - fn from(junctions: Junctions) -> Self { - MultiLocation { parents: 0, interior: junctions } - } - } - - impl From<(u8, Junctions)> for MultiLocation { - fn from((parents, interior): (u8, Junctions)) -> Self { - MultiLocation { parents, interior } - } - } - - impl From<(Ancestor, Junctions)> for MultiLocation { - fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self { - MultiLocation { parents, interior } - } - } - - impl From<()> for MultiLocation { - fn from(_: ()) -> Self { - MultiLocation { parents: 0, interior: Junctions::Here } - } - } - - impl From<(u8,)> for MultiLocation { - fn from((parents,): (u8,)) -> Self { - MultiLocation { parents, interior: Junctions::Here } - } - } - - impl From for MultiLocation { - fn from(x: Junction) -> Self { - MultiLocation { parents: 0, interior: Junctions::X1(x) } - } - } - - impl From<[Junction; 0]> for MultiLocation { - fn from(_: [Junction; 0]) -> Self { - MultiLocation { parents: 0, interior: Junctions::Here } - } - } - - #from_tuples - } - } - - fn generate_conversion_from_v3() -> TokenStream { - let match_variants = (0..8u8) - .map(|cur_num| { - let num_ancestors = cur_num + 1; - let variant = format_ident!("X{}", num_ancestors); - let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::>(); - - quote! { - crate::v3::Junctions::#variant( #(#idents),* ) => - #variant( #( core::convert::TryInto::try_into(#idents)? ),* ), - } - }) - .collect::(); - - quote! { - impl core::convert::TryFrom for Junctions { - type Error = (); - fn try_from(mut new: crate::v3::Junctions) -> core::result::Result { - use Junctions::*; - Ok(match new { - crate::v3::Junctions::Here => Here, - #match_variants - }) - } - } - } - } -} - -pub mod junctions { - use super::*; - - pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result { - if !input.is_empty() { - return Err(syn::Error::new(Span::call_site(), "No arguments expected")) - } - - let from_slice_syntax = generate_conversion_from_slice_syntax(); - - Ok(quote! { - #from_slice_syntax - }) - } - - fn generate_conversion_from_slice_syntax() -> TokenStream { - quote! { - macro_rules! impl_junction { - ($count:expr, $variant:ident, ($($index:literal),+)) => { - /// Additional helper for building junctions - /// Useful for converting to future XCM versions - impl From<[Junction; $count]> for Junctions { - fn from(junctions: [Junction; $count]) -> Self { - Self::$variant($(junctions[$index].clone()),*) - } - } - }; - } - - impl_junction!(1, X1, (0)); - impl_junction!(2, X2, (0, 1)); - impl_junction!(3, X3, (0, 1, 2)); - impl_junction!(4, X4, (0, 1, 2, 3)); - impl_junction!(5, X5, (0, 1, 2, 3, 4)); - impl_junction!(6, X6, (0, 1, 2, 3, 4, 5)); - impl_junction!(7, X7, (0, 1, 2, 3, 4, 5, 6)); - impl_junction!(8, X8, (0, 1, 2, 3, 4, 5, 6, 7)); - } - } -} diff --git a/polkadot/xcm/procedural/src/v3.rs b/polkadot/xcm/procedural/src/v3.rs index f0556d5a8d44..1292b56277dd 100644 --- a/polkadot/xcm/procedural/src/v3.rs +++ b/polkadot/xcm/procedural/src/v3.rs @@ -127,12 +127,10 @@ pub mod junctions { } // Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents. - let from_v2 = generate_conversion_from_v2(MAX_JUNCTIONS); let from_v4 = generate_conversion_from_v4(); let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS); Ok(quote! { - #from_v2 #from_v4 #from_tuples }) @@ -194,32 +192,4 @@ pub mod junctions { } } } - - fn generate_conversion_from_v2(max_junctions: usize) -> TokenStream { - let match_variants = (0..max_junctions) - .map(|cur_num| { - let num_ancestors = cur_num + 1; - let variant = format_ident!("X{}", num_ancestors); - let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::>(); - - quote! { - crate::v2::Junctions::#variant( #(#idents),* ) => - #variant( #( core::convert::TryInto::try_into(#idents)? ),* ), - } - }) - .collect::(); - - quote! { - impl core::convert::TryFrom for Junctions { - type Error = (); - fn try_from(mut old: crate::v2::Junctions) -> core::result::Result { - use Junctions::*; - Ok(match old { - crate::v2::Junctions::Here => Here, - #match_variants - }) - } - } - } - } } diff --git a/polkadot/xcm/procedural/src/v4.rs b/polkadot/xcm/procedural/src/v4.rs index 5f5e10d3081b..9bc2f094d021 100644 --- a/polkadot/xcm/procedural/src/v4.rs +++ b/polkadot/xcm/procedural/src/v4.rs @@ -132,10 +132,12 @@ pub mod junctions { // Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents. let from_v3 = generate_conversion_from_v3(MAX_JUNCTIONS); + let from_v5 = generate_conversion_from_v5(MAX_JUNCTIONS); let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS); Ok(quote! { #from_v3 + #from_v5 #from_tuples }) } @@ -193,4 +195,43 @@ pub mod junctions { } } } + + fn generate_conversion_from_v5(max_junctions: usize) -> TokenStream { + let match_variants = (0..max_junctions) + .map(|current_number| { + let number_ancestors = current_number + 1; + let variant = format_ident!("X{}", number_ancestors); + let idents = + (0..=current_number).map(|i| format_ident!("j{}", i)).collect::>(); + let convert = idents + .iter() + .map(|ident| { + quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; } + }) + .collect::>(); + + quote! { + crate::v5::Junctions::#variant( junctions ) => { + let [#(#idents),*] = &*junctions; + #(#convert);* + [#(#idents),*].into() + }, + } + }) + .collect::(); + + quote! { + impl core::convert::TryFrom for Junctions { + type Error = (); + + fn try_from(mut new: crate::v5::Junctions) -> core::result::Result { + use Junctions::*; + Ok(match new { + crate::v5::Junctions::Here => Here, + #match_variants + }) + } + } + } + } } diff --git a/polkadot/xcm/procedural/src/v5.rs b/polkadot/xcm/procedural/src/v5.rs new file mode 100644 index 000000000000..895a323c1738 --- /dev/null +++ b/polkadot/xcm/procedural/src/v5.rs @@ -0,0 +1,198 @@ +// 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 proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote}; +use syn::{Result, Token}; + +const MAX_JUNCTIONS: usize = 8; + +pub mod location { + use super::*; + + /// Generates conversion functions from other types to the `Location` type: + /// - [PalletInstance(50), GeneralIndex(1984)].into() + /// - (Parent, Parachain(1000), AccountId32 { .. }).into() + pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result { + if !input.is_empty() { + return Err(syn::Error::new(Span::call_site(), "No arguments expected")) + } + + let from_tuples = generate_conversion_from_tuples(8, 8); + + Ok(quote! { + #from_tuples + }) + } + + fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream { + let mut from_tuples = (0..=max_junctions) + .map(|num_junctions| { + let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::>(); + let idents = + (0..num_junctions).map(|i| format_ident!("j{}", i)).collect::>(); + let array_size = num_junctions; + let interior = if num_junctions == 0 { + quote!(Junctions::Here) + } else { + let variant = format_ident!("X{}", num_junctions); + quote! { + Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) ) + } + }; + + let mut from_tuple = quote! { + impl< #(#types : Into,)* > From<( Ancestor, #( #types ),* )> for Location { + fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self { + Location { parents, interior: #interior } + } + } + + impl From<[Junction; #array_size]> for Location { + fn from(j: [Junction; #array_size]) -> Self { + let [#(#idents),*] = j; + Location { parents: 0, interior: #interior } + } + } + }; + + let from_parent_tuples = (0..=max_parents).map(|cur_parents| { + let parents = + (0..cur_parents).map(|_| format_ident!("Parent")).collect::>(); + let underscores = + (0..cur_parents).map(|_| Token![_](Span::call_site())).collect::>(); + + quote! { + impl< #(#types : Into,)* > From<( #( #parents , )* #( #types , )* )> for Location { + fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self { + Self { parents: #cur_parents as u8, interior: #interior } + } + } + } + }); + + from_tuple.extend(from_parent_tuples); + from_tuple + }) + .collect::(); + + let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| { + let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::>(); + let underscores = + (0..cur_parents).map(|_| Token![_](Span::call_site())).collect::>(); + + quote! { + impl From<( #(#parents,)* Junctions )> for Location { + fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self { + Location { parents: #cur_parents as u8, interior: junctions } + } + } + } + }); + from_tuples.extend(from_parent_junctions_tuples); + + quote! { + impl From<(Ancestor, Junctions)> for Location { + fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self { + Location { parents, interior } + } + } + + impl From for Location { + fn from(x: Junction) -> Self { + Location { parents: 0, interior: [x].into() } + } + } + + #from_tuples + } + } +} + +pub mod junctions { + use super::*; + + pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result { + if !input.is_empty() { + return Err(syn::Error::new(Span::call_site(), "No arguments expected")) + } + + // Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents. + let from_v4 = generate_conversion_from_v4(MAX_JUNCTIONS); + let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS); + + Ok(quote! { + #from_v4 + #from_tuples + }) + } + + fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream { + (1..=max_junctions) + .map(|num_junctions| { + let idents = + (0..num_junctions).map(|i| format_ident!("j{}", i)).collect::>(); + let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::>(); + + quote! { + impl<#(#types : Into,)*> From<( #(#types,)* )> for Junctions { + fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self { + [#(#idents .into()),*].into() + } + } + } + }) + .collect() + } + + fn generate_conversion_from_v4(max_junctions: usize) -> TokenStream { + let match_variants = (0..max_junctions) + .map(|cur_num| { + let num_ancestors = cur_num + 1; + let variant = format_ident!("X{}", num_ancestors); + let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::>(); + let convert = idents + .iter() + .enumerate() + .map(|(index, ident)| { + quote! { let #ident = core::convert::TryInto::try_into(slice[#index].clone())?; } + }) + .collect::>(); + + quote! { + crate::v4::Junctions::#variant( arc ) => { + let slice = &arc[..]; + #(#convert);*; + let junctions: Junctions = [#(#idents),*].into(); + junctions + }, + } + }) + .collect::(); + + quote! { + impl core::convert::TryFrom for Junctions { + type Error = (); + fn try_from(mut old: crate::v4::Junctions) -> core::result::Result { + Ok(match old { + crate::v4::Junctions::Here => Junctions::Here, + #match_variants + }) + } + } + } + } +} diff --git a/polkadot/xcm/procedural/tests/builder_pattern.rs b/polkadot/xcm/procedural/tests/builder_pattern.rs index 4202309bf3f7..3915621916d4 100644 --- a/polkadot/xcm/procedural/tests/builder_pattern.rs +++ b/polkadot/xcm/procedural/tests/builder_pattern.rs @@ -17,6 +17,7 @@ //! Test the methods generated by the Builder derive macro. //! Tests directly on the actual Xcm struct and Instruction enum. +use frame_support::BoundedVec; use xcm::latest::prelude::*; #[test] @@ -100,3 +101,61 @@ fn default_builder_allows_clear_origin_before_buy_execution() { ]) ); } + +#[test] +fn bounded_vecs_use_vecs_and_truncate_them() { + let claimer = Location::parent(); + // We can use a vec instead of a bounded vec for specifying hints. + let xcm: Xcm<()> = Xcm::builder_unsafe() + .set_hints(vec![AssetClaimer { location: claimer.clone() }]) + .build(); + assert_eq!( + xcm, + Xcm(vec![SetHints { + hints: BoundedVec::::truncate_from(vec![AssetClaimer { + location: Location::parent() + },]), + },]) + ); + + // If we include more than the limit they'll get truncated. + let xcm: Xcm<()> = Xcm::builder_unsafe() + .set_hints(vec![ + AssetClaimer { location: claimer.clone() }, + AssetClaimer { location: Location::here() }, + ]) + .build(); + assert_eq!( + xcm, + Xcm(vec![SetHints { + hints: BoundedVec::::truncate_from(vec![AssetClaimer { + location: Location::parent() + },]), + },]) + ); + + let xcm: Xcm<()> = Xcm::builder() + .withdraw_asset((Here, 100u128)) + .set_hints(vec![AssetClaimer { location: claimer }]) + .clear_origin() + .pay_fees((Here, 10u128)) + .deposit_asset(All, [0u8; 32]) + .build(); + assert_eq!( + xcm, + Xcm(vec![ + WithdrawAsset(Asset { id: AssetId(Location::here()), fun: Fungible(100) }.into()), + SetHints { + hints: BoundedVec::::truncate_from(vec![AssetClaimer { + location: Location::parent() + }]) + }, + ClearOrigin, + PayFees { asset: Asset { id: AssetId(Location::here()), fun: Fungible(10) } }, + DepositAsset { + assets: All.into(), + beneficiary: AccountId32 { id: [0u8; 32], network: None }.into() + }, + ]) + ); +} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs b/polkadot/xcm/procedural/tests/enum_variants.rs similarity index 70% rename from polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs rename to polkadot/xcm/procedural/tests/enum_variants.rs index 1ed8dd38cbad..4a5362c1579a 100644 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs +++ b/polkadot/xcm/procedural/tests/enum_variants.rs @@ -14,16 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Test error when there's no `BuyExecution` instruction. +//! Test the struct generated by the `NumVariants` derive macro. -use xcm_procedural::Builder; +use frame_support::traits::Get; +use xcm_procedural::NumVariants; -struct Xcm(pub Vec>); - -#[derive(Builder)] -enum Instruction { - UnpaidExecution { weight_limit: (u32, u32) }, - Transact { call: Call }, +#[allow(dead_code)] +#[derive(NumVariants)] +enum SomeEnum { + Variant1, + Variant2, + Variant3, } -fn main() {} +#[test] +fn num_variants_works() { + assert_eq!(SomeEnumNumVariants::get(), 3); +} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr index 978faf2e868d..e4038dc25ae6 100644 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/badly_formatted_attribute.stderr @@ -1,4 +1,4 @@ -error: Expected `builder(loads_holding)` +error: Expected `builder(loads_holding)` or `builder(pays_fees)` --> tests/ui/builder_pattern/badly_formatted_attribute.rs:25:5 | 25 | #[builder(funds_holding = 2)] diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr deleted file mode 100644 index dc8246770ba3..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: BuyExecution should have named fields - --> tests/ui/builder_pattern/buy_execution_named_fields.rs:25:5 - | -25 | BuyExecution(u128), - | ^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr deleted file mode 100644 index 0358a35ad3dd..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/loads_holding_no_operands.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: Instructions that load the holding register should take operands - --> tests/ui/builder_pattern/loads_holding_no_operands.rs:25:5 - | -25 | / #[builder(loads_holding)] -26 | | WithdrawAsset, - | |_________________^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr deleted file mode 100644 index d8798c8223f1..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: No BuyExecution instruction - --> tests/ui/builder_pattern/no_buy_execution.rs:25:5 - | -25 | / UnpaidExecution { weight_limit: (u32, u32) }, -26 | | Transact { call: Call }, - | |____________________________^ diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs deleted file mode 100644 index 5808ec571ce7..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.rs +++ /dev/null @@ -1,32 +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 . - -//! Test error when using wrong attribute. - -use xcm_procedural::Builder; - -struct Xcm(pub Vec>); - -#[derive(Builder)] -enum Instruction { - #[builder(funds_holding)] - WithdrawAsset(u128), - BuyExecution { fees: u128 }, - UnpaidExecution { weight_limit: (u32, u32) }, - Transact { call: Call }, -} - -fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr index 1ff9d1851368..c4d711e0d455 100644 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr +++ b/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr @@ -1,4 +1,4 @@ -error: Expected `builder(loads_holding)` +error: Expected `builder(loads_holding)` or `builder(pays_fees)` --> tests/ui/builder_pattern/unexpected_attribute.rs:25:5 | 25 | #[builder(funds_holding)] diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs deleted file mode 100644 index bb98d603fd91..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.rs +++ /dev/null @@ -1,30 +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 . - -//! Test error when the `BuyExecution` instruction doesn't take named fields. - -use xcm_procedural::Builder; - -struct Xcm(pub Vec>); - -#[derive(Builder)] -enum Instruction { - BuyExecution { fees: u128 }, - UnpaidExecution(u32, u32), - Transact { call: Call }, -} - -fn main() {} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr b/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr deleted file mode 100644 index 0a3c0a40a33b..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unpaid_execution_named_fields.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: UnpaidExecution should have named fields - --> tests/ui/builder_pattern/unpaid_execution_named_fields.rs:26:5 - | -26 | UnpaidExecution(u32, u32), - | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index 0b916c87f549..a41a8e797b0f 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -21,28 +21,24 @@ // // Hence, `no_std` rather than sp-runtime. #![cfg_attr(not(feature = "std"), no_std)] -// Because of XCMv2. -#![allow(deprecated)] extern crate alloc; use codec::{Decode, DecodeLimit, Encode, Error as CodecError, Input, MaxEncodedLen}; use derivative::Derivative; +use frame_support::dispatch::GetDispatchInfo; use scale_info::TypeInfo; -#[deprecated( - note = "XCMv2 will be removed once XCMv5 is released. Please use XCMv3 or XCMv4 instead." -)] -pub mod v2; pub mod v3; pub mod v4; +pub mod v5; pub mod lts { pub use super::v4::*; } pub mod latest { - pub use super::v4::*; + pub use super::v5::*; } mod double_encoded; @@ -81,12 +77,16 @@ pub trait TryAs { fn try_as(&self) -> Result<&T, ()>; } +// Macro that generated versioned wrapper types. +// NOTE: converting a v4 type into a versioned type will make it v5. macro_rules! versioned_type { ($(#[$attr:meta])* pub enum $n:ident { $(#[$index3:meta])+ V3($v3:ty), $(#[$index4:meta])+ V4($v4:ty), + $(#[$index5:meta])+ + V5($v5:ty), }) => { #[derive(Derivative, Encode, Decode, TypeInfo)] #[derivative( @@ -104,6 +104,8 @@ macro_rules! versioned_type { V3($v3), $(#[$index4])* V4($v4), + $(#[$index5])* + V5($v5), } impl $n { pub fn try_as(&self) -> Result<&T, ()> where Self: TryAs { @@ -126,11 +128,20 @@ macro_rules! versioned_type { } } } + impl TryAs<$v5> for $n { + fn try_as(&self) -> Result<&$v5, ()> { + match &self { + Self::V5(ref x) => Ok(x), + _ => Err(()), + } + } + } impl IntoVersion for $n { fn into_version(self, n: Version) -> Result { Ok(match n { 3 => Self::V3(self.try_into()?), 4 => Self::V4(self.try_into()?), + 5 => Self::V5(self.try_into()?), _ => return Err(()), }) } @@ -140,9 +151,9 @@ macro_rules! versioned_type { $n::V3(x.into()) } } - impl From<$v4> for $n { - fn from(x: $v4) -> Self { - $n::V4(x.into()) + impl> From for $n { + fn from(x: T) -> Self { + $n::V5(x.into()) } } impl TryFrom<$n> for $v3 { @@ -151,7 +162,11 @@ macro_rules! versioned_type { use $n::*; match x { V3(x) => Ok(x), - V4(x) => x.try_into(), + V4(x) => x.try_into().map_err(|_| ()), + V5(x) => { + let v4: $v4 = x.try_into().map_err(|_| ())?; + v4.try_into().map_err(|_| ()) + } } } } @@ -162,137 +177,21 @@ macro_rules! versioned_type { match x { V3(x) => x.try_into().map_err(|_| ()), V4(x) => Ok(x), + V5(x) => x.try_into().map_err(|_| ()), } } } - impl MaxEncodedLen for $n { - fn max_encoded_len() -> usize { - <$v3>::max_encoded_len() - } - } - impl IdentifyVersion for $n { - fn identify_version(&self) -> Version { - use $n::*; - match self { - V3(_) => v3::VERSION, - V4(_) => v4::VERSION, - } - } - } - }; - - ($(#[$attr:meta])* pub enum $n:ident { - $(#[$index2:meta])+ - V2($v2:ty), - $(#[$index3:meta])+ - V3($v3:ty), - $(#[$index4:meta])+ - V4($v4:ty), - }) => { - #[derive(Derivative, Encode, Decode, TypeInfo)] - #[derivative( - Clone(bound = ""), - Eq(bound = ""), - PartialEq(bound = ""), - Debug(bound = "") - )] - #[codec(encode_bound())] - #[codec(decode_bound())] - #[scale_info(replace_segment("staging_xcm", "xcm"))] - $(#[$attr])* - pub enum $n { - $(#[$index2])* - V2($v2), - $(#[$index3])* - V3($v3), - $(#[$index4])* - V4($v4), - } - impl $n { - pub fn try_as(&self) -> Result<&T, ()> where Self: TryAs { - >::try_as(&self) - } - } - impl TryAs<$v2> for $n { - fn try_as(&self) -> Result<&$v2, ()> { - match &self { - Self::V2(ref x) => Ok(x), - _ => Err(()), - } - } - } - impl TryAs<$v3> for $n { - fn try_as(&self) -> Result<&$v3, ()> { - match &self { - Self::V3(ref x) => Ok(x), - _ => Err(()), - } - } - } - impl TryAs<$v4> for $n { - fn try_as(&self) -> Result<&$v4, ()> { - match &self { - Self::V4(ref x) => Ok(x), - _ => Err(()), - } - } - } - impl IntoVersion for $n { - fn into_version(self, n: Version) -> Result { - Ok(match n { - 1 | 2 => Self::V2(self.try_into()?), - 3 => Self::V3(self.try_into()?), - 4 => Self::V4(self.try_into()?), - _ => return Err(()), - }) - } - } - impl From<$v2> for $n { - fn from(x: $v2) -> Self { - $n::V2(x) - } - } - impl> From for $n { - fn from(x: T) -> Self { - $n::V4(x.into()) - } - } - impl TryFrom<$n> for $v2 { + impl TryFrom<$n> for $v5 { type Error = (); fn try_from(x: $n) -> Result { use $n::*; match x { - V2(x) => Ok(x), - V3(x) => x.try_into(), - V4(x) => { - let v3: $v3 = x.try_into().map_err(|_| ())?; - v3.try_into() + V3(x) => { + let v4: $v4 = x.try_into().map_err(|_| ())?; + v4.try_into().map_err(|_| ()) }, - } - } - } - impl TryFrom<$n> for $v3 { - type Error = (); - fn try_from(x: $n) -> Result { - use $n::*; - match x { - V2(x) => x.try_into(), - V3(x) => Ok(x), V4(x) => x.try_into().map_err(|_| ()), - } - } - } - impl TryFrom<$n> for $v4 { - type Error = (); - fn try_from(x: $n) -> Result { - use $n::*; - match x { - V2(x) => { - let v3: $v3 = x.try_into().map_err(|_| ())?; - v3.try_into().map_err(|_| ()) - }, - V3(x) => x.try_into().map_err(|_| ()), - V4(x) => Ok(x), + V5(x) => Ok(x), } } } @@ -305,9 +204,9 @@ macro_rules! versioned_type { fn identify_version(&self) -> Version { use $n::*; match self { - V2(_) => v2::VERSION, V3(_) => v3::VERSION, V4(_) => v4::VERSION, + V5(_) => v5::VERSION, } } } @@ -321,42 +220,44 @@ versioned_type! { V3(v3::AssetId), #[codec(index = 4)] V4(v4::AssetId), + #[codec(index = 5)] + V5(v5::AssetId), } } versioned_type! { /// A single version's `Response` value, together with its version code. pub enum VersionedResponse { - #[codec(index = 2)] - V2(v2::Response), #[codec(index = 3)] V3(v3::Response), #[codec(index = 4)] V4(v4::Response), + #[codec(index = 5)] + V5(v5::Response), } } versioned_type! { /// A single `NetworkId` value, together with its version code. pub enum VersionedNetworkId { - #[codec(index = 2)] - V2(v2::NetworkId), #[codec(index = 3)] V3(v3::NetworkId), #[codec(index = 4)] V4(v4::NetworkId), + #[codec(index = 5)] + V5(v5::NetworkId), } } versioned_type! { /// A single `Junction` value, together with its version code. pub enum VersionedJunction { - #[codec(index = 2)] - V2(v2::Junction), #[codec(index = 3)] V3(v3::Junction), #[codec(index = 4)] V4(v4::Junction), + #[codec(index = 5)] + V5(v5::Junction), } } @@ -364,63 +265,51 @@ versioned_type! { /// A single `Location` value, together with its version code. #[derive(Ord, PartialOrd)] pub enum VersionedLocation { - #[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index - V2(v2::MultiLocation), #[codec(index = 3)] V3(v3::MultiLocation), #[codec(index = 4)] V4(v4::Location), + #[codec(index = 5)] + V5(v5::Location), } } -#[deprecated(note = "Use `VersionedLocation` instead")] -pub type VersionedMultiLocation = VersionedLocation; - versioned_type! { /// A single `InteriorLocation` value, together with its version code. pub enum VersionedInteriorLocation { - #[codec(index = 2)] // while this is same as v1::Junctions, VersionedInteriorLocation is introduced in v3 - V2(v2::InteriorMultiLocation), #[codec(index = 3)] V3(v3::InteriorMultiLocation), #[codec(index = 4)] V4(v4::InteriorLocation), + #[codec(index = 5)] + V5(v5::InteriorLocation), } } -#[deprecated(note = "Use `VersionedInteriorLocation` instead")] -pub type VersionedInteriorMultiLocation = VersionedInteriorLocation; - versioned_type! { /// A single `Asset` value, together with its version code. pub enum VersionedAsset { - #[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index - V2(v2::MultiAsset), #[codec(index = 3)] V3(v3::MultiAsset), #[codec(index = 4)] V4(v4::Asset), + #[codec(index = 5)] + V5(v5::Asset), } } -#[deprecated(note = "Use `VersionedAsset` instead")] -pub type VersionedMultiAsset = VersionedAsset; - versioned_type! { /// A single `MultiAssets` value, together with its version code. pub enum VersionedAssets { - #[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index - V2(v2::MultiAssets), #[codec(index = 3)] V3(v3::MultiAssets), #[codec(index = 4)] V4(v4::Assets), + #[codec(index = 5)] + V5(v5::Assets), } } -#[deprecated(note = "Use `VersionedAssets` instead")] -pub type VersionedMultiAssets = VersionedAssets; - /// A single XCM message, together with its version code. #[derive(Derivative, Encode, Decode, TypeInfo)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] @@ -429,21 +318,20 @@ pub type VersionedMultiAssets = VersionedAssets; #[scale_info(bounds(), skip_type_params(RuntimeCall))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum VersionedXcm { - #[codec(index = 2)] - #[deprecated] - V2(v2::Xcm), #[codec(index = 3)] V3(v3::Xcm), #[codec(index = 4)] V4(v4::Xcm), + #[codec(index = 5)] + V5(v5::Xcm), } -impl IntoVersion for VersionedXcm { +impl IntoVersion for VersionedXcm { fn into_version(self, n: Version) -> Result { Ok(match n { - 2 => Self::V2(self.try_into()?), 3 => Self::V3(self.try_into()?), 4 => Self::V4(self.try_into()?), + 5 => Self::V5(self.try_into()?), _ => return Err(()), }) } @@ -452,9 +340,9 @@ impl IntoVersion for VersionedXcm { impl IdentifyVersion for VersionedXcm { fn identify_version(&self) -> Version { match self { - Self::V2(_) => v2::VERSION, Self::V3(_) => v3::VERSION, Self::V4(_) => v4::VERSION, + Self::V5(_) => v5::VERSION, } } } @@ -476,12 +364,6 @@ impl VersionedXcm { } } -impl From> for VersionedXcm { - fn from(x: v2::Xcm) -> Self { - VersionedXcm::V2(x) - } -} - impl From> for VersionedXcm { fn from(x: v3::Xcm) -> Self { VersionedXcm::V3(x) @@ -494,44 +376,50 @@ impl From> for VersionedXcm { } } -impl TryFrom> for v2::Xcm { +impl From> for VersionedXcm { + fn from(x: v5::Xcm) -> Self { + VersionedXcm::V5(x) + } +} + +impl TryFrom> for v3::Xcm { type Error = (); - fn try_from(x: VersionedXcm) -> Result { + fn try_from(x: VersionedXcm) -> Result { use VersionedXcm::*; match x { - V2(x) => Ok(x), - V3(x) => x.try_into(), - V4(x) => { - let v3: v3::Xcm = x.try_into()?; - v3.try_into() + V3(x) => Ok(x), + V4(x) => x.try_into(), + V5(x) => { + let v4: v4::Xcm = x.try_into()?; + v4.try_into() }, } } } -impl TryFrom> for v3::Xcm { +impl TryFrom> for v4::Xcm { type Error = (); fn try_from(x: VersionedXcm) -> Result { use VersionedXcm::*; match x { - V2(x) => x.try_into(), - V3(x) => Ok(x), - V4(x) => x.try_into(), + V3(x) => x.try_into(), + V4(x) => Ok(x), + V5(x) => x.try_into(), } } } -impl TryFrom> for v4::Xcm { +impl TryFrom> for v5::Xcm { type Error = (); fn try_from(x: VersionedXcm) -> Result { use VersionedXcm::*; match x { - V2(x) => { - let v3: v3::Xcm = x.try_into()?; - v3.try_into() + V3(x) => { + let v4: v4::Xcm = x.try_into()?; + v4.try_into() }, - V3(x) => x.try_into(), - V4(x) => Ok(x), + V4(x) => x.try_into(), + V5(x) => Ok(x), } } } @@ -539,7 +427,7 @@ impl TryFrom> for v4::Xcm { /// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `Location` which will /// interpret it. pub trait WrapVersion { - fn wrap_version( + fn wrap_version( dest: &latest::Location, xcm: impl Into>, ) -> Result, ()>; @@ -568,28 +456,11 @@ impl WrapVersion for () { } } -/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before -/// wrapping it. -pub struct AlwaysV2; -impl WrapVersion for AlwaysV2 { - fn wrap_version( - _: &latest::Location, - xcm: impl Into>, - ) -> Result, ()> { - Ok(VersionedXcm::::V2(xcm.into().try_into()?)) - } -} -impl GetVersion for AlwaysV2 { - fn get_version_for(_dest: &latest::Location) -> Option { - Some(v2::VERSION) - } -} - /// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before /// wrapping it. pub struct AlwaysV3; impl WrapVersion for AlwaysV3 { - fn wrap_version( + fn wrap_version( _: &latest::Location, xcm: impl Into>, ) -> Result, ()> { @@ -606,7 +477,7 @@ impl GetVersion for AlwaysV3 { /// wrapping it. pub struct AlwaysV4; impl WrapVersion for AlwaysV4 { - fn wrap_version( + fn wrap_version( _: &latest::Location, xcm: impl Into>, ) -> Result, ()> { @@ -619,9 +490,26 @@ impl GetVersion for AlwaysV4 { } } +/// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before +/// wrapping it. +pub struct AlwaysV5; +impl WrapVersion for AlwaysV5 { + fn wrap_version( + _: &latest::Location, + xcm: impl Into>, + ) -> Result, ()> { + Ok(VersionedXcm::::V5(xcm.into().try_into()?)) + } +} +impl GetVersion for AlwaysV5 { + fn get_version_for(_dest: &latest::Location) -> Option { + Some(v5::VERSION) + } +} + /// `WrapVersion` implementation which attempts to always convert the XCM to the latest version /// before wrapping it. -pub type AlwaysLatest = AlwaysV4; +pub type AlwaysLatest = AlwaysV5; /// `WrapVersion` implementation which attempts to always convert the XCM to the most recent Long- /// Term-Support version before wrapping it. @@ -629,7 +517,7 @@ pub type AlwaysLts = AlwaysV4; pub mod prelude { pub use super::{ - latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, AlwaysV4, GetVersion, + latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV3, AlwaysV4, AlwaysV5, GetVersion, IdentifyVersion, IntoVersion, Unsupported, Version as XcmVersion, VersionedAsset, VersionedAssetId, VersionedAssets, VersionedInteriorLocation, VersionedLocation, VersionedResponse, VersionedXcm, WrapVersion, @@ -637,12 +525,6 @@ pub mod prelude { } pub mod opaque { - pub mod v2 { - // Everything from v2 - pub use crate::v2::*; - // Then override with the opaque types in v2 - pub use crate::v2::opaque::{Instruction, Xcm}; - } pub mod v3 { // Everything from v3 pub use crate::v3::*; @@ -655,9 +537,15 @@ pub mod opaque { // Then override with the opaque types in v4 pub use crate::v4::opaque::{Instruction, Xcm}; } + pub mod v5 { + // Everything from v4 + pub use crate::v5::*; + // Then override with the opaque types in v5 + pub use crate::v5::opaque::{Instruction, Xcm}; + } pub mod latest { - pub use super::v4::*; + pub use super::v5::*; } pub mod lts { @@ -709,7 +597,7 @@ fn size_limits() { } check_sizes! { - (crate::latest::Instruction<()>, 112), + (crate::latest::Instruction<()>, 128), (crate::latest::Asset, 80), (crate::latest::Location, 24), (crate::latest::AssetId, 40), diff --git a/polkadot/xcm/src/tests.rs b/polkadot/xcm/src/tests.rs index 4c666063f3f4..5a267b3a9048 100644 --- a/polkadot/xcm/src/tests.rs +++ b/polkadot/xcm/src/tests.rs @@ -34,43 +34,43 @@ fn encode_decode_versioned_asset_id_v3() { } #[test] -fn encode_decode_versioned_response_v2() { - let response = VersionedResponse::V2(v2::Response::Null); +fn encode_decode_versioned_response_v3() { + let response = VersionedResponse::V3(v3::Response::Null); let encoded = response.encode(); - assert_eq!(encoded, hex_literal::hex!("0200"), "encode format changed"); - assert_eq!(encoded[0], 2, "bad version number"); + assert_eq!(encoded, hex_literal::hex!("0300"), "encode format changed"); + assert_eq!(encoded[0], 3, "bad version number"); let decoded = VersionedResponse::decode(&mut &encoded[..]).unwrap(); assert_eq!(response, decoded); } #[test] -fn encode_decode_versioned_response_v3() { - let response = VersionedResponse::V3(v3::Response::Null); +fn encode_decode_versioned_response_v4() { + let response = VersionedResponse::V4(v4::Response::Null); let encoded = response.encode(); - assert_eq!(encoded, hex_literal::hex!("0300"), "encode format changed"); - assert_eq!(encoded[0], 3, "bad version number"); + assert_eq!(encoded, hex_literal::hex!("0400"), "encode format changed"); + assert_eq!(encoded[0], 4, "bad version number"); let decoded = VersionedResponse::decode(&mut &encoded[..]).unwrap(); assert_eq!(response, decoded); } #[test] -fn encode_decode_versioned_multi_location_v2() { - let location = VersionedLocation::V2(v2::MultiLocation::new(0, v2::Junctions::Here)); - let encoded = location.encode(); +fn encode_decode_versioned_response_v5() { + let response = VersionedResponse::V5(v5::Response::Null); + let encoded = response.encode(); - assert_eq!(encoded, hex_literal::hex!("010000"), "encode format changed"); - assert_eq!(encoded[0], 1, "bad version number"); // this is introduced in v1 + assert_eq!(encoded, hex_literal::hex!("0500"), "encode format changed"); + assert_eq!(encoded[0], 5, "bad version number"); - let decoded = VersionedLocation::decode(&mut &encoded[..]).unwrap(); - assert_eq!(location, decoded); + let decoded = VersionedResponse::decode(&mut &encoded[..]).unwrap(); + assert_eq!(response, decoded); } #[test] -fn encode_decode_versioned_multi_location_v3() { +fn encode_decode_versioned_location_v3() { let location = VersionedLocation::V3(v3::MultiLocation::new(0, v3::Junctions::Here)); let encoded = location.encode(); @@ -82,19 +82,31 @@ fn encode_decode_versioned_multi_location_v3() { } #[test] -fn encode_decode_versioned_interior_multi_location_v2() { - let location = VersionedInteriorLocation::V2(v2::InteriorMultiLocation::Here); +fn encode_decode_versioned_location_v4() { + let location = VersionedLocation::V4(v4::Location::new(0, v4::Junctions::Here)); let encoded = location.encode(); - assert_eq!(encoded, hex_literal::hex!("0200"), "encode format changed"); - assert_eq!(encoded[0], 2, "bad version number"); + assert_eq!(encoded, hex_literal::hex!("040000"), "encode format changed"); + assert_eq!(encoded[0], 4, "bad version number"); - let decoded = VersionedInteriorLocation::decode(&mut &encoded[..]).unwrap(); + let decoded = VersionedLocation::decode(&mut &encoded[..]).unwrap(); assert_eq!(location, decoded); } #[test] -fn encode_decode_versioned_interior_multi_location_v3() { +fn encode_decode_versioned_location_v5() { + let location = VersionedLocation::V5(v5::Location::new(0, v5::Junctions::Here)); + let encoded = location.encode(); + + assert_eq!(encoded, hex_literal::hex!("050000"), "encode format changed"); + assert_eq!(encoded[0], 5, "bad version number"); + + let decoded = VersionedLocation::decode(&mut &encoded[..]).unwrap(); + assert_eq!(location, decoded); +} + +#[test] +fn encode_decode_versioned_interior_location_v3() { let location = VersionedInteriorLocation::V3(v3::InteriorMultiLocation::Here); let encoded = location.encode(); @@ -106,19 +118,31 @@ fn encode_decode_versioned_interior_multi_location_v3() { } #[test] -fn encode_decode_versioned_multi_asset_v2() { - let asset = VersionedAsset::V2(v2::MultiAsset::from(((0, v2::Junctions::Here), 1))); - let encoded = asset.encode(); +fn encode_decode_versioned_interior_location_v4() { + let location = VersionedInteriorLocation::V4(v4::InteriorLocation::Here); + let encoded = location.encode(); - assert_eq!(encoded, hex_literal::hex!("010000000004"), "encode format changed"); - assert_eq!(encoded[0], 1, "bad version number"); + assert_eq!(encoded, hex_literal::hex!("0400"), "encode format changed"); + assert_eq!(encoded[0], 4, "bad version number"); - let decoded = VersionedAsset::decode(&mut &encoded[..]).unwrap(); - assert_eq!(asset, decoded); + let decoded = VersionedInteriorLocation::decode(&mut &encoded[..]).unwrap(); + assert_eq!(location, decoded); } #[test] -fn encode_decode_versioned_multi_asset_v3() { +fn encode_decode_versioned_interior_location_v5() { + let location = VersionedInteriorLocation::V5(v5::InteriorLocation::Here); + let encoded = location.encode(); + + assert_eq!(encoded, hex_literal::hex!("0500"), "encode format changed"); + assert_eq!(encoded[0], 5, "bad version number"); + + let decoded = VersionedInteriorLocation::decode(&mut &encoded[..]).unwrap(); + assert_eq!(location, decoded); +} + +#[test] +fn encode_decode_versioned_asset_v3() { let asset = VersionedAsset::V3(v3::MultiAsset::from((v3::MultiLocation::default(), 1))); let encoded = asset.encode(); @@ -130,22 +154,31 @@ fn encode_decode_versioned_multi_asset_v3() { } #[test] -fn encode_decode_versioned_multi_assets_v2() { - let assets = VersionedAssets::V2(v2::MultiAssets::from(vec![v2::MultiAsset::from(( - (0, v2::Junctions::Here), - 1, - ))])); - let encoded = assets.encode(); +fn encode_decode_versioned_asset_v4() { + let asset = VersionedAsset::V4(v4::Asset::from((v4::Location::default(), 1))); + let encoded = asset.encode(); - assert_eq!(encoded, hex_literal::hex!("01040000000004"), "encode format changed"); - assert_eq!(encoded[0], 1, "bad version number"); + assert_eq!(encoded, hex_literal::hex!("0400000004"), "encode format changed"); + assert_eq!(encoded[0], 4, "bad version number"); - let decoded = VersionedAssets::decode(&mut &encoded[..]).unwrap(); - assert_eq!(assets, decoded); + let decoded = VersionedAsset::decode(&mut &encoded[..]).unwrap(); + assert_eq!(asset, decoded); } #[test] -fn encode_decode_versioned_multi_assets_v3() { +fn encode_decode_versioned_asset_v5() { + let asset = VersionedAsset::V5(v5::Asset::from((v5::Location::default(), 1))); + let encoded = asset.encode(); + + assert_eq!(encoded, hex_literal::hex!("0500000004"), "encode format changed"); + assert_eq!(encoded[0], 5, "bad version number"); + + let decoded = VersionedAsset::decode(&mut &encoded[..]).unwrap(); + assert_eq!(asset, decoded); +} + +#[test] +fn encode_decode_versioned_assets_v3() { let assets = VersionedAssets::V3(v3::MultiAssets::from(vec![ (v3::MultiAsset::from((v3::MultiLocation::default(), 1))), ])); @@ -158,6 +191,34 @@ fn encode_decode_versioned_multi_assets_v3() { assert_eq!(assets, decoded); } +#[test] +fn encode_decode_versioned_assets_v4() { + let assets = VersionedAssets::V4(v4::Assets::from(vec![ + (v4::Asset::from((v4::Location::default(), 1))), + ])); + let encoded = assets.encode(); + + assert_eq!(encoded, hex_literal::hex!("040400000004"), "encode format changed"); + assert_eq!(encoded[0], 4, "bad version number"); + + let decoded = VersionedAssets::decode(&mut &encoded[..]).unwrap(); + assert_eq!(assets, decoded); +} + +#[test] +fn encode_decode_versioned_assets_v5() { + let assets = VersionedAssets::V5(v5::Assets::from(vec![ + (v5::Asset::from((v5::Location::default(), 1))), + ])); + let encoded = assets.encode(); + + assert_eq!(encoded, hex_literal::hex!("050400000004"), "encode format changed"); + assert_eq!(encoded[0], 5, "bad version number"); + + let decoded = VersionedAssets::decode(&mut &encoded[..]).unwrap(); + assert_eq!(assets, decoded); +} + #[test] fn encode_decode_versioned_xcm_v3() { let xcm = VersionedXcm::V3(v3::Xcm::<()>::new()); @@ -170,6 +231,30 @@ fn encode_decode_versioned_xcm_v3() { assert_eq!(xcm, decoded); } +#[test] +fn encode_decode_versioned_xcm_v4() { + let xcm = VersionedXcm::V4(v4::Xcm::<()>::new()); + let encoded = xcm.encode(); + + assert_eq!(encoded, hex_literal::hex!("0400"), "encode format changed"); + assert_eq!(encoded[0], 4, "bad version number"); + + let decoded = VersionedXcm::decode(&mut &encoded[..]).unwrap(); + assert_eq!(xcm, decoded); +} + +#[test] +fn encode_decode_versioned_xcm_v5() { + let xcm = VersionedXcm::V5(v5::Xcm::<()>::new()); + let encoded = xcm.encode(); + + assert_eq!(encoded, hex_literal::hex!("0500"), "encode format changed"); + assert_eq!(encoded[0], 5, "bad version number"); + + let decoded = VersionedXcm::decode(&mut &encoded[..]).unwrap(); + assert_eq!(xcm, decoded); +} + // With the renaming of the crate to `staging-xcm` the naming in the metadata changed as well and // this broke downstream users. This test ensures that the name in the metadata isn't changed. #[test] diff --git a/polkadot/xcm/src/v2/junction.rs b/polkadot/xcm/src/v2/junction.rs deleted file mode 100644 index 68a7886f3039..000000000000 --- a/polkadot/xcm/src/v2/junction.rs +++ /dev/null @@ -1,123 +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 . - -//! Support data structures for `MultiLocation`, primarily the `Junction` datatype. - -use super::{BodyId, BodyPart, Junctions, MultiLocation, NetworkId}; -use crate::v3::Junction as NewJunction; -use bounded_collections::{ConstU32, WeakBoundedVec}; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -/// A single item in a path to describe the relative location of a consensus system. -/// -/// Each item assumes a pre-existing location as its context and is defined in terms of it. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Junction { - /// An indexed parachain belonging to and operated by the context. - /// - /// Generally used when the context is a Polkadot Relay-chain. - Parachain(#[codec(compact)] u32), - /// A 32-byte identifier for an account of a specific network that is respected as a sovereign - /// endpoint within the context. - /// - /// Generally used when the context is a Substrate-based chain. - AccountId32 { network: NetworkId, id: [u8; 32] }, - /// An 8-byte index for an account of a specific network that is respected as a sovereign - /// endpoint within the context. - /// - /// May be used when the context is a Frame-based chain and includes e.g. an indices pallet. - AccountIndex64 { - network: NetworkId, - #[codec(compact)] - index: u64, - }, - /// A 20-byte identifier for an account of a specific network that is respected as a sovereign - /// endpoint within the context. - /// - /// May be used when the context is an Ethereum or Bitcoin chain or smart-contract. - AccountKey20 { network: NetworkId, key: [u8; 20] }, - /// An instanced, indexed pallet that forms a constituent part of the context. - /// - /// Generally used when the context is a Frame-based chain. - PalletInstance(u8), - /// A non-descript index within the context location. - /// - /// Usage will vary widely owing to its generality. - /// - /// NOTE: Try to avoid using this and instead use a more specific item. - GeneralIndex(#[codec(compact)] u128), - /// A nondescript datum acting as a key within the context location. - /// - /// Usage will vary widely owing to its generality. - /// - /// NOTE: Try to avoid using this and instead use a more specific item. - GeneralKey(WeakBoundedVec>), - /// The unambiguous child. - /// - /// Not currently used except as a fallback when deriving ancestry. - OnlyChild, - /// A pluralistic body existing within consensus. - /// - /// Typical to be used to represent a governance origin of a chain, but could in principle be - /// used to represent things such as multisigs also. - Plurality { id: BodyId, part: BodyPart }, -} - -impl TryFrom for Junction { - type Error = (); - - fn try_from(value: NewJunction) -> Result { - use NewJunction::*; - Ok(match value { - Parachain(id) => Self::Parachain(id), - AccountId32 { network, id } => Self::AccountId32 { network: network.try_into()?, id }, - AccountIndex64 { network, index } => - Self::AccountIndex64 { network: network.try_into()?, index }, - AccountKey20 { network, key } => - Self::AccountKey20 { network: network.try_into()?, key }, - PalletInstance(index) => Self::PalletInstance(index), - GeneralIndex(id) => Self::GeneralIndex(id), - GeneralKey { length, data } => Self::GeneralKey( - data[0..data.len().min(length as usize)] - .to_vec() - .try_into() - .expect("key is bounded to 32 and so will never be out of bounds; qed"), - ), - OnlyChild => Self::OnlyChild, - Plurality { id, part } => Self::Plurality { id: id.into(), part: part.into() }, - _ => return Err(()), - }) - } -} - -impl Junction { - /// Convert `self` into a `MultiLocation` containing 0 parents. - /// - /// Similar to `Into::into`, except that this method can be used in a const evaluation context. - pub const fn into(self) -> MultiLocation { - MultiLocation { parents: 0, interior: Junctions::X1(self) } - } - - /// Convert `self` into a `MultiLocation` containing `n` parents. - /// - /// Similar to `Self::into`, with the added ability to specify the number of parent junctions. - pub const fn into_exterior(self, n: u8) -> MultiLocation { - MultiLocation { parents: n, interior: Junctions::X1(self) } - } -} diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs deleted file mode 100644 index e3358f08d410..000000000000 --- a/polkadot/xcm/src/v2/mod.rs +++ /dev/null @@ -1,1222 +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 . - -//! # XCM Version 2 -//! -//! WARNING: DEPRECATED, please use version 3 or 4. -//! -//! Version 2 of the Cross-Consensus Message format data structures. The comprehensive list of -//! changes can be found in -//! [this PR description](https://github.com/paritytech/polkadot/pull/3629#issue-968428279). -//! -//! ## Changes to be aware of -//! The biggest change here is the restructuring of XCM messages: instead of having `Order` and -//! `Xcm` types, the `Xcm` type now simply wraps a `Vec` containing `Instruction`s. However, most -//! changes should still be automatically convertible via the `try_from` and `from` conversion -//! functions. -//! -//! ### Junction -//! - No special attention necessary -//! -//! ### `MultiLocation` -//! - No special attention necessary -//! -//! ### `MultiAsset` -//! - No special attention necessary -//! -//! ### XCM and Order -//! - `Xcm` and `Order` variants are now combined under a single `Instruction` enum. -//! - `Order` is now obsolete and replaced entirely by `Instruction`. -//! - `Xcm` is now a simple wrapper around a `Vec`. -//! - During conversion from `Order` to `Instruction`, we do not handle `BuyExecution`s that have -//! nested XCMs, i.e. if the `instructions` field in the `BuyExecution` enum struct variant is not -//! empty, then the conversion will fail. To address this, rewrite the XCM using `Instruction`s in -//! chronological order. -//! - During conversion from `Xcm` to `Instruction`, we do not handle `RelayedFrom` messages at all. -//! -//! ### XCM Pallet -//! - The `Weigher` configuration item must have sensible weights defined for `BuyExecution` and -//! `DepositAsset` instructions. Failing that, dispatch calls to `teleport_assets` and -//! `reserve_transfer_assets` will fail with `UnweighableMessage`. - -use super::{ - v3::{ - BodyId as NewBodyId, BodyPart as NewBodyPart, Instruction as NewInstruction, - NetworkId as NewNetworkId, OriginKind as NewOriginKind, Response as NewResponse, - WeightLimit as NewWeightLimit, Xcm as NewXcm, - }, - DoubleEncoded, -}; -use alloc::{vec, vec::Vec}; -use bounded_collections::{ConstU32, WeakBoundedVec}; -use codec::{ - self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput, - MaxEncodedLen, -}; -use core::{fmt::Debug, result}; -use derivative::Derivative; -use scale_info::TypeInfo; - -mod junction; -mod multiasset; -mod multilocation; -mod traits; - -pub use junction::Junction; -pub use multiasset::{ - AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, - WildFungibility, WildMultiAsset, -}; -pub use multilocation::{ - Ancestor, AncestorThen, InteriorMultiLocation, Junctions, MultiLocation, Parent, ParentThen, -}; -pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendResult, SendXcm}; - -/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] -pub enum OriginKind { - /// Origin should just be the native dispatch origin representation for the sender in the - /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin - /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a - /// primary/native dispatch origin form. - Native, - - /// Origin should just be the standard account-based origin with the sovereign account of - /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. - SovereignAccount, - - /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. - /// This will not usually be an available option. - Superuser, - - /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be - /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be - /// the `pallet_xcm::Origin::Xcm` type. - Xcm, -} - -impl From for OriginKind { - fn from(new: NewOriginKind) -> Self { - use NewOriginKind::*; - match new { - Native => Self::Native, - SovereignAccount => Self::SovereignAccount, - Superuser => Self::Superuser, - Xcm => Self::Xcm, - } - } -} - -/// A global identifier of an account-bearing consensus system. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum NetworkId { - /// Unidentified/any. - Any, - /// Some named network. - Named(WeakBoundedVec>), - /// The Polkadot Relay chain - Polkadot, - /// Kusama. - Kusama, -} - -impl TryFrom> for NetworkId { - type Error = (); - fn try_from(new: Option) -> result::Result { - match new { - None => Ok(NetworkId::Any), - Some(id) => Self::try_from(id), - } - } -} - -impl TryFrom for NetworkId { - type Error = (); - fn try_from(new: NewNetworkId) -> result::Result { - use NewNetworkId::*; - match new { - Polkadot => Ok(NetworkId::Polkadot), - Kusama => Ok(NetworkId::Kusama), - _ => Err(()), - } - } -} - -/// An identifier of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum BodyId { - /// The only body in its context. - Unit, - /// A named body. - Named(WeakBoundedVec>), - /// An indexed body. - Index(#[codec(compact)] u32), - /// The unambiguous executive body (for Polkadot, this would be the Polkadot council). - Executive, - /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). - Technical, - /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a - /// majority of lock-voters). - Legislative, - /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a - /// "grand oracle", it may be considered as that). - Judicial, - /// The unambiguous defense body (for Polkadot, an opinion on the topic given via a public - /// referendum on the `staking_admin` track). - Defense, - /// The unambiguous administration body (for Polkadot, an opinion on the topic given via a - /// public referendum on the `general_admin` track). - Administration, - /// The unambiguous treasury body (for Polkadot, an opinion on the topic given via a public - /// referendum on the `treasurer` track). - Treasury, -} - -impl From for BodyId { - fn from(n: NewBodyId) -> Self { - use NewBodyId::*; - match n { - Unit => Self::Unit, - Moniker(n) => Self::Named( - n[..] - .to_vec() - .try_into() - .expect("array size is 4 and so will never be out of bounds; qed"), - ), - Index(n) => Self::Index(n), - Executive => Self::Executive, - Technical => Self::Technical, - Legislative => Self::Legislative, - Judicial => Self::Judicial, - Defense => Self::Defense, - Administration => Self::Administration, - Treasury => Self::Treasury, - } - } -} - -/// A part of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum BodyPart { - /// The body's declaration, under whatever means it decides. - Voice, - /// A given number of members of the body. - Members { - #[codec(compact)] - count: u32, - }, - /// A given number of members of the body, out of some larger caucus. - Fraction { - #[codec(compact)] - nom: u32, - #[codec(compact)] - denom: u32, - }, - /// No less than the given proportion of members of the body. - AtLeastProportion { - #[codec(compact)] - nom: u32, - #[codec(compact)] - denom: u32, - }, - /// More than the given proportion of members of the body. - MoreThanProportion { - #[codec(compact)] - nom: u32, - #[codec(compact)] - denom: u32, - }, -} - -impl BodyPart { - /// Returns `true` if the part represents a strict majority (> 50%) of the body in question. - pub fn is_majority(&self) -> bool { - match self { - BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true, - BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true, - BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true, - _ => false, - } - } -} - -impl From for BodyPart { - fn from(n: NewBodyPart) -> Self { - use NewBodyPart::*; - match n { - Voice => Self::Voice, - Members { count } => Self::Members { count }, - Fraction { nom, denom } => Self::Fraction { nom, denom }, - AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom }, - MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom }, - } - } -} - -/// This module's XCM version. -pub const VERSION: super::Version = 2; - -/// An identifier for a query. -pub type QueryId = u64; - -/// DEPRECATED. Please use XCMv3 or XCMv4 instead. -#[derive(Derivative, Default, Encode, TypeInfo)] -#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] -#[codec(encode_bound())] -#[codec(decode_bound())] -#[scale_info(bounds(), skip_type_params(RuntimeCall))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub struct Xcm(pub Vec>); - -environmental::environmental!(instructions_count: u8); - -impl Decode for Xcm { - fn decode(input: &mut I) -> core::result::Result { - instructions_count::using_once(&mut 0, || { - let number_of_instructions: u32 = >::decode(input)?.into(); - instructions_count::with(|count| { - *count = count.saturating_add(number_of_instructions as u8); - if *count > MAX_INSTRUCTIONS_TO_DECODE { - return Err(CodecError::from("Max instructions exceeded")) - } - Ok(()) - }) - .unwrap_or(Ok(()))?; - let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?; - Ok(Self(decoded_instructions)) - }) - } -} - -/// The maximal number of instructions in an XCM before decoding fails. -/// -/// This is a deliberate limit - not a technical one. -pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; - -impl Xcm { - /// Create an empty instance. - pub fn new() -> Self { - Self(vec![]) - } - - /// Return `true` if no instructions are held in `self`. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Return the number of instructions held in `self`. - pub fn len(&self) -> usize { - self.0.len() - } - - /// Consume and either return `self` if it contains some instructions, or if it's empty, then - /// instead return the result of `f`. - pub fn or_else(self, f: impl FnOnce() -> Self) -> Self { - if self.0.is_empty() { - f() - } else { - self - } - } - - /// Return the first instruction, if any. - pub fn first(&self) -> Option<&Instruction> { - self.0.first() - } - - /// Return the last instruction, if any. - pub fn last(&self) -> Option<&Instruction> { - self.0.last() - } - - /// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise). - pub fn only(&self) -> Option<&Instruction> { - if self.0.len() == 1 { - self.0.first() - } else { - None - } - } - - /// Return the only instruction, contained in `Self`, iff only one exists (returns `self` - /// otherwise). - pub fn into_only(mut self) -> core::result::Result, Self> { - if self.0.len() == 1 { - self.0.pop().ok_or(self) - } else { - Err(self) - } - } -} - -/// A prelude for importing all types typically used when interacting with XCM messages. -pub mod prelude { - mod contents { - pub use super::super::{ - Ancestor, AncestorThen, - AssetId::{self, *}, - AssetInstance::{self, *}, - BodyId, BodyPart, Error as XcmError, ExecuteXcm, - Fungibility::{self, *}, - Instruction::*, - InteriorMultiLocation, - Junction::{self, *}, - Junctions::{self, *}, - MultiAsset, - MultiAssetFilter::{self, *}, - MultiAssets, MultiLocation, - NetworkId::{self, *}, - OriginKind, Outcome, Parent, ParentThen, QueryId, Response, Result as XcmResult, - SendError, SendResult, SendXcm, - WeightLimit::{self, *}, - WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, - WildMultiAsset::{self, *}, - XcmWeightInfo, VERSION as XCM_VERSION, - }; - } - pub use super::{Instruction, Xcm}; - pub use contents::*; - pub mod opaque { - pub use super::{ - super::opaque::{Instruction, Xcm}, - contents::*, - }; - } -} - -/// Response data to a query. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Response { - /// No response. Serves as a neutral default. - Null, - /// Some assets. - Assets(MultiAssets), - /// The outcome of an XCM instruction. - ExecutionResult(Option<(u32, Error)>), - /// An XCM version. - Version(super::Version), -} - -impl Default for Response { - fn default() -> Self { - Self::Null - } -} - -/// An optional weight limit. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum WeightLimit { - /// No weight limit imposed. - Unlimited, - /// Weight limit imposed of the inner value. - Limited(#[codec(compact)] u64), -} - -impl From> for WeightLimit { - fn from(x: Option) -> Self { - match x { - Some(w) => WeightLimit::Limited(w), - None => WeightLimit::Unlimited, - } - } -} - -impl From for Option { - fn from(x: WeightLimit) -> Self { - match x { - WeightLimit::Limited(w) => Some(w), - WeightLimit::Unlimited => None, - } - } -} - -impl TryFrom for WeightLimit { - type Error = (); - fn try_from(x: NewWeightLimit) -> result::Result { - use NewWeightLimit::*; - match x { - Limited(w) => Ok(Self::Limited(w.ref_time())), - Unlimited => Ok(Self::Unlimited), - } - } -} - -/// Local weight type; execution time in picoseconds. -pub type Weight = u64; - -/// Cross-Consensus Message: A message from one consensus system to another. -/// -/// Consensus systems that may send and receive messages include blockchains and smart contracts. -/// -/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`. -/// -/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the -/// outer XCM format, known as `VersionedXcm`. -#[derive(Derivative, Encode, Decode, TypeInfo, xcm_procedural::XcmWeightInfoTrait)] -#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] -#[codec(encode_bound())] -#[codec(decode_bound())] -#[scale_info(bounds(), skip_type_params(RuntimeCall))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Instruction { - /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding - /// Register. - /// - /// - `assets`: The asset(s) to be withdrawn into holding. - /// - /// Kind: *Command*. - /// - /// Errors: - WithdrawAsset(MultiAssets), - - /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` - /// system and equivalent derivatives should be placed into the Holding Register. - /// - /// - `assets`: The asset(s) that are minted into holding. - /// - /// Safety: `origin` must be trusted to have received and be storing `assets` such that they - /// may later be withdrawn should this system send a corresponding message. - /// - /// Kind: *Trusted Indication*. - /// - /// Errors: - ReserveAssetDeposited(MultiAssets), - - /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should - /// be created and placed into the Holding Register. - /// - /// - `assets`: The asset(s) that are minted into the Holding Register. - /// - /// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets` - /// prior as a consequence of sending this message. - /// - /// Kind: *Trusted Indication*. - /// - /// Errors: - ReceiveTeleportedAsset(MultiAssets), - - /// Respond with information that the local system is expecting. - /// - /// - `query_id`: The identifier of the query that resulted in this message being sent. - /// - `response`: The message content. - /// - `max_weight`: The maximum weight that handling this response should take. - /// - /// Safety: No concerns. - /// - /// Kind: *Information*. - /// - /// Errors: - QueryResponse { - #[codec(compact)] - query_id: QueryId, - response: Response, - #[codec(compact)] - max_weight: u64, - }, - - /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets - /// under the ownership of `beneficiary`. - /// - /// - `assets`: The asset(s) to be withdrawn. - /// - `beneficiary`: The new owner for the assets. - /// - /// Safety: No concerns. - /// - /// Kind: *Command*. - /// - /// Errors: - TransferAsset { assets: MultiAssets, beneficiary: MultiLocation }, - - /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets - /// under the ownership of `dest` within this consensus system (i.e. its sovereign account). - /// - /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given - /// `xcm`. - /// - /// - `assets`: The asset(s) to be withdrawn. - /// - `dest`: The location whose sovereign account will own the assets and thus the effective - /// beneficiary for the assets and the notification target for the reserve asset deposit - /// message. - /// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which - /// is sent onwards to `dest`. - /// - /// Safety: No concerns. - /// - /// Kind: *Command*. - /// - /// Errors: - TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, xcm: Xcm<()> }, - - /// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed - /// by the kind of origin `origin_type`. - /// - /// - `origin_type`: The means of expressing the message origin as a dispatch origin. - /// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight - /// and will be used in the weight determination arithmetic. - /// - `call`: The encoded transaction to be applied. - /// - /// Safety: No concerns. - /// - /// Kind: *Command*. - /// - /// Errors: - Transact { - origin_type: OriginKind, - #[codec(compact)] - require_weight_at_most: u64, - call: DoubleEncoded, - }, - - /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by - /// the relay-chain to a para. - /// - /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel - /// opening. - /// - `max_message_size`: The maximum size of a message proposed by the sender. - /// - `max_capacity`: The maximum number of messages that can be queued in the channel. - /// - /// Safety: The message should originate directly from the relay-chain. - /// - /// Kind: *System Notification* - HrmpNewChannelOpenRequest { - #[codec(compact)] - sender: u32, - #[codec(compact)] - max_message_size: u32, - #[codec(compact)] - max_capacity: u32, - }, - - /// A message to notify about that a previously sent open channel request has been accepted by - /// the recipient. That means that the channel will be opened during the next relay-chain - /// session change. This message is meant to be sent by the relay-chain to a para. - /// - /// Safety: The message should originate directly from the relay-chain. - /// - /// Kind: *System Notification* - /// - /// Errors: - HrmpChannelAccepted { - // NOTE: We keep this as a structured item to a) keep it consistent with the other Hrmp - // items; and b) because the field's meaning is not obvious/mentioned from the item name. - #[codec(compact)] - recipient: u32, - }, - - /// A message to notify that the other party in an open channel decided to close it. In - /// particular, `initiator` is going to close the channel opened from `sender` to the - /// `recipient`. The close will be enacted at the next relay-chain session change. This message - /// is meant to be sent by the relay-chain to a para. - /// - /// Safety: The message should originate directly from the relay-chain. - /// - /// Kind: *System Notification* - /// - /// Errors: - HrmpChannelClosing { - #[codec(compact)] - initiator: u32, - #[codec(compact)] - sender: u32, - #[codec(compact)] - recipient: u32, - }, - - /// Clear the origin. - /// - /// This may be used by the XCM author to ensure that later instructions cannot command the - /// authority of the origin (e.g. if they are being relayed from an untrusted source, as often - /// the case with `ReserveAssetDeposited`). - /// - /// Safety: No concerns. - /// - /// Kind: *Command*. - /// - /// Errors: - ClearOrigin, - - /// Mutate the origin to some interior location. - /// - /// Kind: *Command* - /// - /// Errors: - DescendOrigin(InteriorMultiLocation), - - /// Immediately report the contents of the Error Register to the given destination via XCM. - /// - /// A `QueryResponse` message of type `ExecutionOutcome` is sent to `dest` with the given - /// `query_id` and the outcome of the XCM. - /// - /// - `query_id`: An identifier that will be replicated into the returned XCM message. - /// - `dest`: A valid destination for the returned XCM message. - /// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which - /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the - /// response may not execute at all. - /// - /// Kind: *Command* - /// - /// Errors: - ReportError { - #[codec(compact)] - query_id: QueryId, - dest: MultiLocation, - #[codec(compact)] - max_response_weight: u64, - }, - - /// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under - /// the ownership of `beneficiary` within this consensus system. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. - /// Only the first `max_assets` assets/instances of those matched by `assets` will be - /// removed, prioritized under standard asset ordering. Any others will remain in holding. - /// - `beneficiary`: The new owner for the assets. - /// - /// Kind: *Command* - /// - /// Errors: - DepositAsset { - assets: MultiAssetFilter, - #[codec(compact)] - max_assets: u32, - beneficiary: MultiLocation, - }, - - /// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under - /// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign - /// account). - /// - /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. - /// Only the first `max_assets` assets/instances of those matched by `assets` will be - /// removed, prioritized under standard asset ordering. Any others will remain in holding. - /// - `dest`: The location whose sovereign account will own the assets and thus the effective - /// beneficiary for the assets and the notification target for the reserve asset deposit - /// message. - /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is - /// sent onwards to `dest`. - /// - /// Kind: *Command* - /// - /// Errors: - DepositReserveAsset { - assets: MultiAssetFilter, - #[codec(compact)] - max_assets: u32, - dest: MultiLocation, - xcm: Xcm<()>, - }, - - /// Remove the asset(s) (`give`) from the Holding Register and replace them with alternative - /// assets. - /// - /// The minimum amount of assets to be received into the Holding Register for the order not to - /// fail may be stated. - /// - /// - `give`: The asset(s) to remove from holding. - /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. - /// - /// Kind: *Command* - /// - /// Errors: - ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets }, - - /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a - /// reserve location. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The - /// sovereign account of this consensus system *on the reserve location* will have - /// appropriate assets withdrawn and `effects` will be executed on them. There will typically - /// be only one valid location on any given asset/chain combination. - /// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve - /// location*. - /// - /// Kind: *Command* - /// - /// Errors: - InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, xcm: Xcm<()> }, - - /// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message - /// to a `dest` location. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `dest`: A valid location that respects teleports coming from this location. - /// - `xcm`: The instructions to execute on the assets once arrived *on the destination - /// location*. - /// - /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for - /// all `assets`. If it does not, then the assets may be lost. - /// - /// Kind: *Command* - /// - /// Errors: - InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> }, - - /// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a - /// portion thereof. - /// - /// - `query_id`: An identifier that will be replicated into the returned XCM message. - /// - `dest`: A valid destination for the returned XCM message. This may be limited to the - /// current origin. - /// - `assets`: A filter for the assets that should be reported back. The assets reported back - /// will be, asset-wise, *the lesser of this value and the holding register*. No wildcards - /// will be used when reporting assets back. - /// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which - /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the - /// response may not execute at all. - /// - /// Kind: *Command* - /// - /// Errors: - QueryHolding { - #[codec(compact)] - query_id: QueryId, - dest: MultiLocation, - assets: MultiAssetFilter, - #[codec(compact)] - max_response_weight: u64, - }, - - /// Pay for the execution of some XCM `xcm` and `orders` with up to `weight` - /// picoseconds of execution time, paying for this with up to `fees` from the Holding Register. - /// - /// - `fees`: The asset(s) to remove from the Holding Register to pay for fees. - /// - `weight_limit`: The maximum amount of weight to purchase; this must be at least the - /// expected maximum weight of the total XCM to be executed for the - /// `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed. - /// - /// Kind: *Command* - /// - /// Errors: - BuyExecution { fees: MultiAsset, weight_limit: WeightLimit }, - - /// Refund any surplus weight previously bought with `BuyExecution`. - /// - /// Kind: *Command* - /// - /// Errors: None. - RefundSurplus, - - /// Set the Error Handler Register. This is code that should be called in the case of an error - /// happening. - /// - /// An error occurring within execution of this code will _NOT_ result in the error register - /// being set, nor will an error handler be called due to it. The error handler and appendix - /// may each still be set. - /// - /// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing - /// weight however includes only the difference between the previous handler and the new - /// handler, which can reasonably be negative, which would result in a surplus. - /// - /// Kind: *Command* - /// - /// Errors: None. - SetErrorHandler(Xcm), - - /// Set the Appendix Register. This is code that should be called after code execution - /// (including the error handler if any) is finished. This will be called regardless of whether - /// an error occurred. - /// - /// Any error occurring due to execution of this code will result in the error register being - /// set, and the error handler (if set) firing. - /// - /// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing - /// weight however includes only the difference between the previous appendix and the new - /// appendix, which can reasonably be negative, which would result in a surplus. - /// - /// Kind: *Command* - /// - /// Errors: None. - SetAppendix(Xcm), - - /// Clear the Error Register. - /// - /// Kind: *Command* - /// - /// Errors: None. - ClearError, - - /// Create some assets which are being held on behalf of the origin. - /// - /// - `assets`: The assets which are to be claimed. This must match exactly with the assets - /// claimable by the origin of the ticket. - /// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the - /// asset. - /// - /// Kind: *Command* - /// - /// Errors: - ClaimAsset { assets: MultiAssets, ticket: MultiLocation }, - - /// Always throws an error of type `Trap`. - /// - /// Kind: *Command* - /// - /// Errors: - /// - `Trap`: All circumstances, whose inner value is the same as this item's inner value. - Trap(#[codec(compact)] u64), - - /// Ask the destination system to respond with the most recent version of XCM that they - /// support in a `QueryResponse` instruction. Any changes to this should also elicit similar - /// responses when they happen. - /// - /// - `query_id`: An identifier that will be replicated into the returned XCM message. - /// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which - /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the - /// response may not execute at all. - /// - /// Kind: *Command* - /// - /// Errors: *Fallible* - SubscribeVersion { - #[codec(compact)] - query_id: QueryId, - #[codec(compact)] - max_response_weight: u64, - }, - - /// Cancel the effect of a previous `SubscribeVersion` instruction. - /// - /// Kind: *Command* - /// - /// Errors: *Fallible* - UnsubscribeVersion, -} - -impl Xcm { - pub fn into(self) -> Xcm { - Xcm::from(self) - } - pub fn from(xcm: Xcm) -> Self { - Self(xcm.0.into_iter().map(Instruction::::from).collect()) - } -} - -impl Instruction { - pub fn into(self) -> Instruction { - Instruction::from(self) - } - pub fn from(xcm: Instruction) -> Self { - use Instruction::*; - match xcm { - WithdrawAsset(assets) => WithdrawAsset(assets), - ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets), - ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets), - QueryResponse { query_id, response, max_weight } => - QueryResponse { query_id, response, max_weight }, - TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary }, - TransferReserveAsset { assets, dest, xcm } => - TransferReserveAsset { assets, dest, xcm }, - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, - HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, - HrmpChannelClosing { initiator, sender, recipient } => - HrmpChannelClosing { initiator, sender, recipient }, - Transact { origin_type, require_weight_at_most, call } => - Transact { origin_type, require_weight_at_most, call: call.into() }, - ReportError { query_id, dest, max_response_weight } => - ReportError { query_id, dest, max_response_weight }, - DepositAsset { assets, max_assets, beneficiary } => - DepositAsset { assets, max_assets, beneficiary }, - DepositReserveAsset { assets, max_assets, dest, xcm } => - DepositReserveAsset { assets, max_assets, dest, xcm }, - ExchangeAsset { give, receive } => ExchangeAsset { give, receive }, - InitiateReserveWithdraw { assets, reserve, xcm } => - InitiateReserveWithdraw { assets, reserve, xcm }, - InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm }, - QueryHolding { query_id, dest, assets, max_response_weight } => - QueryHolding { query_id, dest, assets, max_response_weight }, - BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit }, - ClearOrigin => ClearOrigin, - DescendOrigin(who) => DescendOrigin(who), - RefundSurplus => RefundSurplus, - SetErrorHandler(xcm) => SetErrorHandler(xcm.into()), - SetAppendix(xcm) => SetAppendix(xcm.into()), - ClearError => ClearError, - ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket }, - Trap(code) => Trap(code), - SubscribeVersion { query_id, max_response_weight } => - SubscribeVersion { query_id, max_response_weight }, - UnsubscribeVersion => UnsubscribeVersion, - } - } -} - -// TODO: Automate Generation -impl> GetWeight for Instruction { - fn weight(&self) -> sp_weights::Weight { - use Instruction::*; - match self { - WithdrawAsset(assets) => sp_weights::Weight::from_parts(W::withdraw_asset(assets), 0), - ReserveAssetDeposited(assets) => - sp_weights::Weight::from_parts(W::reserve_asset_deposited(assets), 0), - ReceiveTeleportedAsset(assets) => - sp_weights::Weight::from_parts(W::receive_teleported_asset(assets), 0), - QueryResponse { query_id, response, max_weight } => - sp_weights::Weight::from_parts(W::query_response(query_id, response, max_weight), 0), - TransferAsset { assets, beneficiary } => - sp_weights::Weight::from_parts(W::transfer_asset(assets, beneficiary), 0), - TransferReserveAsset { assets, dest, xcm } => - sp_weights::Weight::from_parts(W::transfer_reserve_asset(&assets, dest, xcm), 0), - Transact { origin_type, require_weight_at_most, call } => - sp_weights::Weight::from_parts( - W::transact(origin_type, require_weight_at_most, call), - 0, - ), - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => - sp_weights::Weight::from_parts( - W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity), - 0, - ), - HrmpChannelAccepted { recipient } => - sp_weights::Weight::from_parts(W::hrmp_channel_accepted(recipient), 0), - HrmpChannelClosing { initiator, sender, recipient } => sp_weights::Weight::from_parts( - W::hrmp_channel_closing(initiator, sender, recipient), - 0, - ), - ClearOrigin => sp_weights::Weight::from_parts(W::clear_origin(), 0), - DescendOrigin(who) => sp_weights::Weight::from_parts(W::descend_origin(who), 0), - ReportError { query_id, dest, max_response_weight } => sp_weights::Weight::from_parts( - W::report_error(query_id, dest, max_response_weight), - 0, - ), - DepositAsset { assets, max_assets, beneficiary } => - sp_weights::Weight::from_parts(W::deposit_asset(assets, max_assets, beneficiary), 0), - DepositReserveAsset { assets, max_assets, dest, xcm } => - sp_weights::Weight::from_parts( - W::deposit_reserve_asset(assets, max_assets, dest, xcm), - 0, - ), - ExchangeAsset { give, receive } => - sp_weights::Weight::from_parts(W::exchange_asset(give, receive), 0), - InitiateReserveWithdraw { assets, reserve, xcm } => sp_weights::Weight::from_parts( - W::initiate_reserve_withdraw(assets, reserve, xcm), - 0, - ), - InitiateTeleport { assets, dest, xcm } => - sp_weights::Weight::from_parts(W::initiate_teleport(assets, dest, xcm), 0), - QueryHolding { query_id, dest, assets, max_response_weight } => - sp_weights::Weight::from_parts( - W::query_holding(query_id, dest, assets, max_response_weight), - 0, - ), - BuyExecution { fees, weight_limit } => - sp_weights::Weight::from_parts(W::buy_execution(fees, weight_limit), 0), - RefundSurplus => sp_weights::Weight::from_parts(W::refund_surplus(), 0), - SetErrorHandler(xcm) => sp_weights::Weight::from_parts(W::set_error_handler(xcm), 0), - SetAppendix(xcm) => sp_weights::Weight::from_parts(W::set_appendix(xcm), 0), - ClearError => sp_weights::Weight::from_parts(W::clear_error(), 0), - ClaimAsset { assets, ticket } => - sp_weights::Weight::from_parts(W::claim_asset(assets, ticket), 0), - Trap(code) => sp_weights::Weight::from_parts(W::trap(code), 0), - SubscribeVersion { query_id, max_response_weight } => sp_weights::Weight::from_parts( - W::subscribe_version(query_id, max_response_weight), - 0, - ), - UnsubscribeVersion => sp_weights::Weight::from_parts(W::unsubscribe_version(), 0), - } - } -} - -pub mod opaque { - /// The basic concrete type of `Xcm`, which doesn't make any assumptions about the - /// format of a call other than it is pre-encoded. - pub type Xcm = super::Xcm<()>; - - /// The basic concrete type of `Instruction`, which doesn't make any assumptions about the - /// format of a call other than it is pre-encoded. - pub type Instruction = super::Instruction<()>; -} - -// Convert from a v3 response to a v2 response -impl TryFrom for Response { - type Error = (); - fn try_from(response: NewResponse) -> result::Result { - Ok(match response { - NewResponse::Assets(assets) => Self::Assets(assets.try_into()?), - NewResponse::Version(version) => Self::Version(version), - NewResponse::ExecutionResult(error) => Self::ExecutionResult(match error { - Some((i, e)) => Some((i, e.try_into()?)), - None => None, - }), - NewResponse::Null => Self::Null, - _ => return Err(()), - }) - } -} - -// Convert from a v3 XCM to a v2 XCM. -impl TryFrom> for Xcm { - type Error = (); - fn try_from(new_xcm: NewXcm) -> result::Result { - Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::>()?)) - } -} - -// Convert from a v3 instruction to a v2 instruction -impl TryFrom> for Instruction { - type Error = (); - fn try_from(instruction: NewInstruction) -> result::Result { - use NewInstruction::*; - Ok(match instruction { - WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?), - ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?), - ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?), - QueryResponse { query_id, response, max_weight, .. } => Self::QueryResponse { - query_id, - response: response.try_into()?, - max_weight: max_weight.ref_time(), - }, - TransferAsset { assets, beneficiary } => Self::TransferAsset { - assets: assets.try_into()?, - beneficiary: beneficiary.try_into()?, - }, - TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset { - assets: assets.try_into()?, - dest: dest.try_into()?, - xcm: xcm.try_into()?, - }, - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => - Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, - HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient }, - HrmpChannelClosing { initiator, sender, recipient } => - Self::HrmpChannelClosing { initiator, sender, recipient }, - Transact { origin_kind, require_weight_at_most, call } => Self::Transact { - origin_type: origin_kind.into(), - require_weight_at_most: require_weight_at_most.ref_time(), - call: call.into(), - }, - ReportError(response_info) => Self::ReportError { - query_id: response_info.query_id, - dest: response_info.destination.try_into()?, - max_response_weight: response_info.max_weight.ref_time(), - }, - DepositAsset { assets, beneficiary } => { - let max_assets = assets.count().ok_or(())?; - let beneficiary = beneficiary.try_into()?; - let assets = assets.try_into()?; - Self::DepositAsset { assets, max_assets, beneficiary } - }, - DepositReserveAsset { assets, dest, xcm } => { - let max_assets = assets.count().ok_or(())?; - let dest = dest.try_into()?; - let xcm = xcm.try_into()?; - let assets = assets.try_into()?; - Self::DepositReserveAsset { assets, max_assets, dest, xcm } - }, - ExchangeAsset { give, want, .. } => { - let give = give.try_into()?; - let receive = want.try_into()?; - Self::ExchangeAsset { give, receive } - }, - InitiateReserveWithdraw { assets, reserve, xcm } => { - // No `max_assets` here, so if there's a connt, then we cannot translate. - let assets = assets.try_into()?; - let reserve = reserve.try_into()?; - let xcm = xcm.try_into()?; - Self::InitiateReserveWithdraw { assets, reserve, xcm } - }, - InitiateTeleport { assets, dest, xcm } => { - // No `max_assets` here, so if there's a connt, then we cannot translate. - let assets = assets.try_into()?; - let dest = dest.try_into()?; - let xcm = xcm.try_into()?; - Self::InitiateTeleport { assets, dest, xcm } - }, - ReportHolding { response_info, assets } => Self::QueryHolding { - query_id: response_info.query_id, - dest: response_info.destination.try_into()?, - assets: assets.try_into()?, - max_response_weight: response_info.max_weight.ref_time(), - }, - BuyExecution { fees, weight_limit } => { - let fees = fees.try_into()?; - let weight_limit = weight_limit.try_into()?; - Self::BuyExecution { fees, weight_limit } - }, - ClearOrigin => Self::ClearOrigin, - DescendOrigin(who) => Self::DescendOrigin(who.try_into()?), - RefundSurplus => Self::RefundSurplus, - SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?), - SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?), - ClearError => Self::ClearError, - ClaimAsset { assets, ticket } => { - let assets = assets.try_into()?; - let ticket = ticket.try_into()?; - Self::ClaimAsset { assets, ticket } - }, - Trap(code) => Self::Trap(code), - SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion { - query_id, - max_response_weight: max_response_weight.ref_time(), - }, - UnsubscribeVersion => Self::UnsubscribeVersion, - i => { - log::debug!(target: "xcm::v3tov2", "`{i:?}` not supported by v2"); - return Err(()); - }, - }) - } -} - -#[cfg(test)] -mod tests { - use super::{prelude::*, *}; - - #[test] - fn decoding_respects_limit() { - let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]); - let encoded = max_xcm.encode(); - assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok()); - - let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]); - let encoded = big_xcm.encode(); - assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - - let nested_xcm = Xcm::<()>(vec![ - DepositReserveAsset { - assets: All.into(), - dest: Here.into(), - xcm: max_xcm, - max_assets: 1, - }; - (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize - ]); - let encoded = nested_xcm.encode(); - assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - - let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]); - let encoded = even_more_nested_xcm.encode(); - assert_eq!(encoded.len(), 345730); - // This should not decode since the limit is 100 - assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition"); - assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - } -} diff --git a/polkadot/xcm/src/v2/multiasset.rs b/polkadot/xcm/src/v2/multiasset.rs deleted file mode 100644 index 218f21b63b0a..000000000000 --- a/polkadot/xcm/src/v2/multiasset.rs +++ /dev/null @@ -1,626 +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 . - -//! Cross-Consensus Message format asset data structures. -//! -//! This encompasses four types for representing assets: -//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some -//! amount of a fungible. -//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with -//! fungibles first. -//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific -//! kind. -//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently -//! filtering an XCM holding account. - -use super::MultiLocation; -use crate::v3::{ - AssetId as NewAssetId, AssetInstance as NewAssetInstance, Fungibility as NewFungibility, - MultiAsset as NewMultiAsset, MultiAssetFilter as NewMultiAssetFilter, - MultiAssets as NewMultiAssets, WildFungibility as NewWildFungibility, - WildMultiAsset as NewWildMultiAsset, -}; -use alloc::{vec, vec::Vec}; -use codec::{self as codec, Decode, Encode}; -use core::cmp::Ordering; -use scale_info::TypeInfo; - -/// A general identifier for an instance of a non-fungible asset class. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum AssetInstance { - /// Undefined - used if the non-fungible asset class has only one instance. - Undefined, - - /// A compact index. Technically this could be greater than `u128`, but this implementation - /// supports only values up to `2**128 - 1`. - Index(#[codec(compact)] u128), - - /// A 4-byte fixed-length datum. - Array4([u8; 4]), - - /// An 8-byte fixed-length datum. - Array8([u8; 8]), - - /// A 16-byte fixed-length datum. - Array16([u8; 16]), - - /// A 32-byte fixed-length datum. - Array32([u8; 32]), - - /// An arbitrary piece of data. Use only when necessary. - Blob(Vec), -} - -impl From<()> for AssetInstance { - fn from(_: ()) -> Self { - Self::Undefined - } -} - -impl From<[u8; 4]> for AssetInstance { - fn from(x: [u8; 4]) -> Self { - Self::Array4(x) - } -} - -impl From<[u8; 8]> for AssetInstance { - fn from(x: [u8; 8]) -> Self { - Self::Array8(x) - } -} - -impl From<[u8; 16]> for AssetInstance { - fn from(x: [u8; 16]) -> Self { - Self::Array16(x) - } -} - -impl From<[u8; 32]> for AssetInstance { - fn from(x: [u8; 32]) -> Self { - Self::Array32(x) - } -} - -impl From> for AssetInstance { - fn from(x: Vec) -> Self { - Self::Blob(x) - } -} - -impl TryFrom for AssetInstance { - type Error = (); - fn try_from(value: NewAssetInstance) -> Result { - use NewAssetInstance::*; - Ok(match value { - Undefined => Self::Undefined, - Index(n) => Self::Index(n), - Array4(n) => Self::Array4(n), - Array8(n) => Self::Array8(n), - Array16(n) => Self::Array16(n), - Array32(n) => Self::Array32(n), - }) - } -} - -/// Classification of an asset being concrete or abstract. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum AssetId { - Concrete(MultiLocation), - Abstract(Vec), -} - -impl> From for AssetId { - fn from(x: T) -> Self { - Self::Concrete(x.into()) - } -} - -impl From> for AssetId { - fn from(x: Vec) -> Self { - Self::Abstract(x) - } -} - -impl TryFrom for AssetId { - type Error = (); - fn try_from(old: NewAssetId) -> Result { - use NewAssetId::*; - Ok(match old { - Concrete(l) => Self::Concrete(l.try_into()?), - Abstract(v) => { - let zeroes = v.iter().rev().position(|n| *n != 0).unwrap_or(v.len()); - Self::Abstract(v[0..(32 - zeroes)].to_vec()) - }, - }) - } -} - -impl AssetId { - /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. - pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> { - if let AssetId::Concrete(ref mut l) = self { - l.prepend_with(prepend.clone()).map_err(|_| ())?; - } - Ok(()) - } - - /// Mutate the asset to represent the same value from the perspective of a new `target` - /// location. The local chain's location is provided in `ancestry`. - pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> { - if let AssetId::Concrete(ref mut l) = self { - l.reanchor(target, ancestry)?; - } - Ok(()) - } - - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding - /// `MultiAsset` value. - pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset { - MultiAsset { fun, id: self } - } - - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding - /// `WildMultiAsset` wildcard (`AllOf`) value. - pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset { - WildMultiAsset::AllOf { fun, id: self } - } -} - -/// Classification of whether an asset is fungible or not, along with a mandatory amount or -/// instance. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Fungibility { - Fungible(#[codec(compact)] u128), - NonFungible(AssetInstance), -} - -impl Fungibility { - pub fn is_kind(&self, w: WildFungibility) -> bool { - use Fungibility::*; - use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}; - matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible)) - } -} - -impl From for Fungibility { - fn from(amount: u128) -> Fungibility { - debug_assert_ne!(amount, 0); - Fungibility::Fungible(amount) - } -} - -impl> From for Fungibility { - fn from(instance: T) -> Fungibility { - Fungibility::NonFungible(instance.into()) - } -} - -impl TryFrom for Fungibility { - type Error = (); - fn try_from(value: NewFungibility) -> Result { - use NewFungibility::*; - Ok(match value { - Fungible(n) => Self::Fungible(n), - NonFungible(i) => Self::NonFungible(i.try_into()?), - }) - } -} - -#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub struct MultiAsset { - pub id: AssetId, - pub fun: Fungibility, -} - -impl PartialOrd for MultiAsset { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for MultiAsset { - fn cmp(&self, other: &Self) -> Ordering { - match (&self.fun, &other.fun) { - (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less, - (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater, - _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)), - } - } -} - -impl, B: Into> From<(A, B)> for MultiAsset { - fn from((id, fun): (A, B)) -> MultiAsset { - MultiAsset { fun: fun.into(), id: id.into() } - } -} - -impl MultiAsset { - pub fn is_fungible(&self, maybe_id: Option) -> bool { - use Fungibility::*; - matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id) - } - - pub fn is_non_fungible(&self, maybe_id: Option) -> bool { - use Fungibility::*; - matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id) - } - - /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. - pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> { - self.id.prepend_with(prepend) - } - - /// Mutate the location of the asset identifier if concrete, giving it the same location - /// relative to a `target` context. The local context is provided as `ancestry`. - pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> { - self.id.reanchor(target, ancestry) - } - - /// Mutate the location of the asset identifier if concrete, giving it the same location - /// relative to a `target` context. The local context is provided as `ancestry`. - pub fn reanchored( - mut self, - target: &MultiLocation, - ancestry: &MultiLocation, - ) -> Result { - self.id.reanchor(target, ancestry)?; - Ok(self) - } - - /// Returns true if `self` is a super-set of the given `inner`. - pub fn contains(&self, inner: &MultiAsset) -> bool { - use Fungibility::*; - if self.id == inner.id { - match (&self.fun, &inner.fun) { - (Fungible(a), Fungible(i)) if a >= i => return true, - (NonFungible(a), NonFungible(i)) if a == i => return true, - _ => (), - } - } - false - } -} - -impl TryFrom for MultiAsset { - type Error = (); - fn try_from(new: NewMultiAsset) -> Result { - Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? }) - } -} - -/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, -/// they must be sorted. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub struct MultiAssets(Vec); - -impl Decode for MultiAssets { - fn decode(input: &mut I) -> Result { - Self::from_sorted_and_deduplicated(Vec::::decode(input)?) - .map_err(|()| "Out of order".into()) - } -} - -impl TryFrom for MultiAssets { - type Error = (); - fn try_from(new: NewMultiAssets) -> Result { - let v = new - .into_inner() - .into_iter() - .map(MultiAsset::try_from) - .collect::, ()>>()?; - Ok(MultiAssets(v)) - } -} - -impl From> for MultiAssets { - fn from(mut assets: Vec) -> Self { - let mut res = Vec::with_capacity(assets.len()); - if !assets.is_empty() { - assets.sort(); - let mut iter = assets.into_iter(); - if let Some(first) = iter.next() { - let last = iter.fold(first, |a, b| -> MultiAsset { - match (a, b) { - ( - MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id }, - MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id }, - ) if a_id == b_id => MultiAsset { - id: a_id, - fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)), - }, - ( - MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id }, - MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id }, - ) if a_id == b_id && a_instance == b_instance => - MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id }, - (to_push, to_remember) => { - res.push(to_push); - to_remember - }, - } - }); - res.push(last); - } - } - Self(res) - } -} - -impl> From for MultiAssets { - fn from(x: T) -> Self { - Self(vec![x.into()]) - } -} - -impl MultiAssets { - /// A new (empty) value. - pub fn new() -> Self { - Self(Vec::new()) - } - - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted - /// and which contain no duplicates. - /// - /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. - /// If you can't guarantee that `r` is sorted and deduplicated, then use - /// `From::>::from` which is infallible. - pub fn from_sorted_and_deduplicated(r: Vec) -> Result { - if r.is_empty() { - return Ok(Self(Vec::new())) - } - r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> { - if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { - Ok(b) - } else { - Err(()) - } - })?; - Ok(Self(r)) - } - - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted - /// and which contain no duplicates. - /// - /// In release mode, this skips any checks to ensure that `r` is correct, making it a - /// negligible-cost operation. Generally though you should avoid using it unless you have a - /// strict proof that `r` is valid. - #[cfg(test)] - pub fn from_sorted_and_deduplicated_skip_checks(r: Vec) -> Self { - Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped") - } - /// Create a new instance of `MultiAssets` from a `Vec` whose contents are sorted - /// and which contain no duplicates. - /// - /// In release mode, this skips any checks to ensure that `r` is correct, making it a - /// negligible-cost operation. Generally though you should avoid using it unless you have a - /// strict proof that `r` is valid. - /// - /// In test mode, this checks anyway and panics on fail. - #[cfg(not(test))] - pub fn from_sorted_and_deduplicated_skip_checks(r: Vec) -> Self { - Self(r) - } - - /// Add some asset onto the list, saturating. This is quite a laborious operation since it - /// maintains the ordering. - pub fn push(&mut self, a: MultiAsset) { - if let Fungibility::Fungible(ref amount) = a.fun { - for asset in self.0.iter_mut().filter(|x| x.id == a.id) { - if let Fungibility::Fungible(ref mut balance) = asset.fun { - *balance = balance.saturating_add(*amount); - return - } - } - } - self.0.push(a); - self.0.sort(); - } - - /// Returns `true` if this definitely represents no asset. - pub fn is_none(&self) -> bool { - self.0.is_empty() - } - - /// Returns true if `self` is a super-set of the given `inner`. - pub fn contains(&self, inner: &MultiAsset) -> bool { - self.0.iter().any(|i| i.contains(inner)) - } - - /// Consume `self` and return the inner vec. - pub fn drain(self) -> Vec { - self.0 - } - - /// Return a reference to the inner vec. - pub fn inner(&self) -> &Vec { - &self.0 - } - - /// Return the number of distinct asset instances contained. - pub fn len(&self) -> usize { - self.0.len() - } - - /// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location. - pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> { - self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix)) - } - - /// Mutate the location of the asset identifier if concrete, giving it the same location - /// relative to a `target` context. The local context is provided as `ancestry`. - pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> { - self.0.iter_mut().try_for_each(|i| i.reanchor(target, ancestry)) - } - - /// Return a reference to an item at a specific index or `None` if it doesn't exist. - pub fn get(&self, index: usize) -> Option<&MultiAsset> { - self.0.get(index) - } -} - -/// Classification of whether an asset is fungible or not. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum WildFungibility { - Fungible, - NonFungible, -} - -impl TryFrom for WildFungibility { - type Error = (); - fn try_from(value: NewWildFungibility) -> Result { - use NewWildFungibility::*; - Ok(match value { - Fungible => Self::Fungible, - NonFungible => Self::NonFungible, - }) - } -} - -/// A wildcard representing a set of assets. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum WildMultiAsset { - /// All assets in the holding register, up to `usize` individual assets (different instances of - /// non-fungibles could be separate assets). - All, - /// All assets in the holding register of a given fungibility and ID. If operating on - /// non-fungibles, then a limit is provided for the maximum amount of matching instances. - AllOf { id: AssetId, fun: WildFungibility }, -} - -impl WildMultiAsset { - /// Returns true if `self` is a super-set of the given `inner`. - /// - /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any - /// other non-wildcard. For more details, see the implementation and tests. - pub fn contains(&self, inner: &MultiAsset) -> bool { - use WildMultiAsset::*; - match self { - AllOf { fun, id } => inner.fun.is_kind(*fun) && &inner.id == id, - All => true, - } - } - - /// Mutate the location of the asset identifier if concrete, giving it the same location - /// relative to a `target` context. The local context is provided as `ancestry`. - pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> { - use WildMultiAsset::*; - match self { - AllOf { ref mut id, .. } => id.reanchor(target, ancestry).map_err(|_| ()), - All => Ok(()), - } - } -} - -impl, B: Into> From<(A, B)> for WildMultiAsset { - fn from((id, fun): (A, B)) -> WildMultiAsset { - WildMultiAsset::AllOf { fun: fun.into(), id: id.into() } - } -} - -/// `MultiAsset` collection, either `MultiAssets` or a single wildcard. -/// -/// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported -/// in this implementation and will result in a decode error. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum MultiAssetFilter { - Definite(MultiAssets), - Wild(WildMultiAsset), -} - -impl> From for MultiAssetFilter { - fn from(x: T) -> Self { - Self::Wild(x.into()) - } -} - -impl From for MultiAssetFilter { - fn from(x: MultiAsset) -> Self { - Self::Definite(vec![x].into()) - } -} - -impl From> for MultiAssetFilter { - fn from(x: Vec) -> Self { - Self::Definite(x.into()) - } -} - -impl From for MultiAssetFilter { - fn from(x: MultiAssets) -> Self { - Self::Definite(x) - } -} - -impl MultiAssetFilter { - /// Returns true if `self` is a super-set of the given `inner`. - /// - /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any - /// other non-wildcard. For more details, see the implementation and tests. - pub fn contains(&self, inner: &MultiAsset) -> bool { - match self { - MultiAssetFilter::Definite(ref assets) => assets.contains(inner), - MultiAssetFilter::Wild(ref wild) => wild.contains(inner), - } - } - - /// Mutate the location of the asset identifier if concrete, giving it the same location - /// relative to a `target` context. The local context is provided as `ancestry`. - pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> { - match self { - MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, ancestry), - MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, ancestry), - } - } -} - -impl TryFrom for WildMultiAsset { - type Error = (); - fn try_from(new: NewWildMultiAsset) -> Result { - use NewWildMultiAsset::*; - Ok(match new { - AllOf { id, fun } | AllOfCounted { id, fun, .. } => - Self::AllOf { id: id.try_into()?, fun: fun.try_into()? }, - All | AllCounted(_) => Self::All, - }) - } -} - -impl TryFrom for MultiAssetFilter { - type Error = (); - fn try_from(old: NewMultiAssetFilter) -> Result { - use NewMultiAssetFilter::*; - Ok(match old { - Definite(x) => Self::Definite(x.try_into()?), - Wild(x) => Self::Wild(x.try_into()?), - }) - } -} diff --git a/polkadot/xcm/src/v2/multilocation.rs b/polkadot/xcm/src/v2/multilocation.rs deleted file mode 100644 index 9399ca6619c0..000000000000 --- a/polkadot/xcm/src/v2/multilocation.rs +++ /dev/null @@ -1,1105 +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 . - -//! Cross-Consensus Message format data structures. - -use super::Junction; -use crate::v3::MultiLocation as NewMultiLocation; -use codec::{Decode, Encode, MaxEncodedLen}; -use core::{mem, result}; -use scale_info::TypeInfo; - -/// A relative path between state-bearing consensus systems. -/// -/// A location in a consensus system is defined as an *isolatable state machine* held within global -/// consensus. The location in question need not have a sophisticated consensus algorithm of its -/// own; a single account within Ethereum, for example, could be considered a location. -/// -/// A very-much non-exhaustive list of types of location include: -/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain. -/// - A layer-0 super-chain, e.g. the Polkadot Relay chain. -/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum. -/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based -/// Substrate chain. -/// - An account. -/// -/// A `MultiLocation` is a *relative identifier*, meaning that it can only be used to define the -/// relative path between two locations, and cannot generally be used to refer to a location -/// universally. It is comprised of an integer number of parents specifying the number of times to -/// "escape" upwards into the containing consensus system and then a number of *junctions*, each -/// diving down and specifying some interior portion of state (which may be considered a -/// "sub-consensus" system). -/// -/// This specific `MultiLocation` implementation uses a `Junctions` datatype which is a Rust `enum` -/// in order to make pattern matching easier. There are occasions where it is important to ensure -/// that a value is strictly an interior location, in those cases, `Junctions` may be used. -/// -/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. -#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub struct MultiLocation { - /// The number of parent junctions at the beginning of this `MultiLocation`. - pub parents: u8, - /// The interior (i.e. non-parent) junctions that this `MultiLocation` contains. - pub interior: Junctions, -} - -impl Default for MultiLocation { - fn default() -> Self { - Self { parents: 0, interior: Junctions::Here } - } -} - -/// A relative location which is constrained to be an interior location of the context. -/// -/// See also `MultiLocation`. -pub type InteriorMultiLocation = Junctions; - -impl MultiLocation { - /// Creates a new `MultiLocation` with the given number of parents and interior junctions. - pub fn new(parents: u8, junctions: Junctions) -> MultiLocation { - MultiLocation { parents, interior: junctions } - } - - /// Consume `self` and return the equivalent `VersionedLocation` value. - pub fn versioned(self) -> crate::VersionedLocation { - self.into() - } - - /// Creates a new `MultiLocation` with 0 parents and a `Here` interior. - /// - /// The resulting `MultiLocation` can be interpreted as the "current consensus system". - pub const fn here() -> MultiLocation { - MultiLocation { parents: 0, interior: Junctions::Here } - } - - /// Creates a new `MultiLocation` which evaluates to the parent context. - pub const fn parent() -> MultiLocation { - MultiLocation { parents: 1, interior: Junctions::Here } - } - - /// Creates a new `MultiLocation` which evaluates to the grand parent context. - pub const fn grandparent() -> MultiLocation { - MultiLocation { parents: 2, interior: Junctions::Here } - } - - /// Creates a new `MultiLocation` with `parents` and an empty (`Here`) interior. - pub const fn ancestor(parents: u8) -> MultiLocation { - MultiLocation { parents, interior: Junctions::Here } - } - - /// Whether the `MultiLocation` has no parents and has a `Here` interior. - pub const fn is_here(&self) -> bool { - self.parents == 0 && self.interior.len() == 0 - } - - /// Return a reference to the interior field. - pub fn interior(&self) -> &Junctions { - &self.interior - } - - /// Return a mutable reference to the interior field. - pub fn interior_mut(&mut self) -> &mut Junctions { - &mut self.interior - } - - /// Returns the number of `Parent` junctions at the beginning of `self`. - pub const fn parent_count(&self) -> u8 { - self.parents - } - - /// Returns boolean indicating whether `self` contains only the specified amount of - /// parents and no interior junctions. - pub const fn contains_parents_only(&self, count: u8) -> bool { - matches!(self.interior, Junctions::Here) && self.parents == count - } - - /// Returns the number of parents and junctions in `self`. - pub const fn len(&self) -> usize { - self.parent_count() as usize + self.interior.len() - } - - /// Returns the first interior junction, or `None` if the location is empty or contains only - /// parents. - pub fn first_interior(&self) -> Option<&Junction> { - self.interior.first() - } - - /// Returns last junction, or `None` if the location is empty or contains only parents. - pub fn last(&self) -> Option<&Junction> { - self.interior.last() - } - - /// Splits off the first interior junction, returning the remaining suffix (first item in tuple) - /// and the first element (second item in tuple) or `None` if it was empty. - pub fn split_first_interior(self) -> (MultiLocation, Option) { - let MultiLocation { parents, interior: junctions } = self; - let (suffix, first) = junctions.split_first(); - let multilocation = MultiLocation { parents, interior: suffix }; - (multilocation, first) - } - - /// Splits off the last interior junction, returning the remaining prefix (first item in tuple) - /// and the last element (second item in tuple) or `None` if it was empty or if `self` only - /// contains parents. - pub fn split_last_interior(self) -> (MultiLocation, Option) { - let MultiLocation { parents, interior: junctions } = self; - let (prefix, last) = junctions.split_last(); - let multilocation = MultiLocation { parents, interior: prefix }; - (multilocation, last) - } - - /// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in - /// case of overflow. - pub fn push_interior(&mut self, new: Junction) -> result::Result<(), Junction> { - self.interior.push(new) - } - - /// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in - /// case of overflow. - pub fn push_front_interior(&mut self, new: Junction) -> result::Result<(), Junction> { - self.interior.push_front(new) - } - - /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with - /// the original value of `self` in case of overflow. - pub fn pushed_with_interior(self, new: Junction) -> result::Result { - match self.interior.pushed_with(new) { - Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), - Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)), - } - } - - /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the - /// original value of `self` in case of overflow. - pub fn pushed_front_with_interior( - self, - new: Junction, - ) -> result::Result { - match self.interior.pushed_front_with(new) { - Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), - Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)), - } - } - - /// Returns the junction at index `i`, or `None` if the location is a parent or if the location - /// does not contain that many elements. - pub fn at(&self, i: usize) -> Option<&Junction> { - let num_parents = self.parents as usize; - if i < num_parents { - return None - } - self.interior.at(i - num_parents) - } - - /// Returns a mutable reference to the junction at index `i`, or `None` if the location is a - /// parent or if it doesn't contain that many elements. - pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { - let num_parents = self.parents as usize; - if i < num_parents { - return None - } - self.interior.at_mut(i - num_parents) - } - - /// Decrements the parent count by 1. - pub fn dec_parent(&mut self) { - self.parents = self.parents.saturating_sub(1); - } - - /// Removes the first interior junction from `self`, returning it - /// (or `None` if it was empty or if `self` contains only parents). - pub fn take_first_interior(&mut self) -> Option { - self.interior.take_first() - } - - /// Removes the last element from `interior`, returning it (or `None` if it was empty or if - /// `self` only contains parents). - pub fn take_last(&mut self) -> Option { - self.interior.take_last() - } - - /// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with - /// the junctions of `prefix` and that it has a single `Junction` item following. - /// If so, returns a reference to this `Junction` item. - /// - /// # Example - /// ```rust - /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// let mut m = MultiLocation::new(1, [PalletInstance(3), OnlyChild].into()); - /// assert_eq!( - /// m.match_and_split(&MultiLocation::new(1, [PalletInstance(3)].into())), - /// Some(&OnlyChild), - /// ); - /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None); - /// ``` - pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { - if self.parents != prefix.parents { - return None - } - self.interior.match_and_split(&prefix.interior) - } - - /// Returns whether `self` has the same number of parents as `prefix` and its junctions begins - /// with the junctions of `prefix`. - /// - /// # Example - /// ```rust - /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// let m = MultiLocation::new(1, [PalletInstance(3), OnlyChild, OnlyChild].into()); - /// assert!(m.starts_with(&MultiLocation::new(1, [PalletInstance(3)].into()))); - /// assert!(!m.starts_with(&MultiLocation::new(1, [GeneralIndex(99)].into()))); - /// assert!(!m.starts_with(&MultiLocation::new(0, [PalletInstance(3)].into()))); - /// ``` - pub fn starts_with(&self, prefix: &MultiLocation) -> bool { - if self.parents != prefix.parents { - return false - } - self.interior.starts_with(&prefix.interior) - } - - /// Mutate `self` so that it is suffixed with `suffix`. - /// - /// Does not modify `self` and returns `Err` with `suffix` in case of overflow. - /// - /// # Example - /// ```rust - /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// let mut m = MultiLocation::new(1, [Parachain(21)].into()); - /// assert_eq!(m.append_with([PalletInstance(3)].into()), Ok(())); - /// assert_eq!(m, MultiLocation::new(1, [Parachain(21), PalletInstance(3)].into())); - /// ``` - pub fn append_with(&mut self, suffix: Junctions) -> Result<(), Junctions> { - if self.interior.len().saturating_add(suffix.len()) > MAX_JUNCTIONS { - return Err(suffix) - } - for j in suffix.into_iter() { - self.interior.push(j).expect("Already checked the sum of the len()s; qed") - } - Ok(()) - } - - /// Mutate `self` so that it is prefixed with `prefix`. - /// - /// Does not modify `self` and returns `Err` with `prefix` in case of overflow. - /// - /// # Example - /// ```rust - /// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation}; - /// let mut m = MultiLocation::new(2, [PalletInstance(3)].into()); - /// assert_eq!(m.prepend_with(MultiLocation::new(1, [Parachain(21), OnlyChild].into())), Ok(())); - /// assert_eq!(m, MultiLocation::new(1, [PalletInstance(3)].into())); - /// ``` - pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { - // prefix self (suffix) - // P .. P I .. I p .. p i .. i - let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize); - let final_interior = self.interior.len().saturating_add(prepend_interior); - if final_interior > MAX_JUNCTIONS { - return Err(prefix) - } - let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len()); - let final_parents = (prefix.parents as usize).saturating_add(suffix_parents); - if final_parents > 255 { - return Err(prefix) - } - - // cancel out the final item on the prefix interior for one of the suffix's parents. - while self.parents > 0 && prefix.take_last().is_some() { - self.dec_parent(); - } - - // now we have either removed all suffix's parents or prefix interior. - // this means we can combine the prefix's and suffix's remaining parents/interior since - // we know that with at least one empty, the overall order will be respected: - // prefix self (suffix) - // P .. P (I) p .. p i .. i => P + p .. (no I) i - // -- or -- - // P .. P I .. I (p) i .. i => P (no p) .. I + i - - self.parents = self.parents.saturating_add(prefix.parents); - for j in prefix.interior.into_iter().rev() { - self.push_front_interior(j) - .expect("final_interior no greater than MAX_JUNCTIONS; qed"); - } - Ok(()) - } - - /// Consume `self` and return the value representing the same location from the point of view - /// of `target`. The context of `self` is provided as `ancestry`. - /// - /// Returns an `Err` with the unmodified `self` in the case of error. - pub fn reanchored( - mut self, - target: &MultiLocation, - ancestry: &MultiLocation, - ) -> Result { - match self.reanchor(target, ancestry) { - Ok(()) => Ok(self), - Err(()) => Err(self), - } - } - - /// Mutate `self` so that it represents the same location from the point of view of `target`. - /// The context of `self` is provided as `ancestry`. - /// - /// Does not modify `self` in case of overflow. - pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> { - // TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this. - - // 1. Use our `ancestry` to figure out how the `target` would address us. - let inverted_target = ancestry.inverted(target)?; - - // 2. Prepend `inverted_target` to `self` to get self's location from the perspective of - // `target`. - self.prepend_with(inverted_target).map_err(|_| ())?; - - // 3. Given that we know some of `target` ancestry, ensure that any parents in `self` are - // strictly needed. - self.simplify(target.interior()); - - Ok(()) - } - - /// Treating `self` as a context, determine how it would be referenced by a `target` location. - pub fn inverted(&self, target: &MultiLocation) -> Result { - use Junction::OnlyChild; - let mut ancestry = self.clone(); - let mut junctions = Junctions::Here; - for _ in 0..target.parent_count() { - junctions = junctions - .pushed_front_with(ancestry.interior.take_last().unwrap_or(OnlyChild)) - .map_err(|_| ())?; - } - let parents = target.interior().len() as u8; - Ok(MultiLocation::new(parents, junctions)) - } - - /// Remove any unneeded parents/junctions in `self` based on the given context it will be - /// interpreted in. - pub fn simplify(&mut self, context: &Junctions) { - if context.len() < self.parents as usize { - // Not enough context - return - } - while self.parents > 0 { - let maybe = context.at(context.len() - (self.parents as usize)); - match (self.interior.first(), maybe) { - (Some(i), Some(j)) if i == j => { - self.interior.take_first(); - self.parents -= 1; - }, - _ => break, - } - } - } -} - -impl TryFrom for MultiLocation { - type Error = (); - fn try_from(x: NewMultiLocation) -> result::Result { - Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? }) - } -} - -/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct Parent; -impl From for MultiLocation { - fn from(_: Parent) -> Self { - MultiLocation { parents: 1, interior: Junctions::Here } - } -} - -/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner -/// interior. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct ParentThen(pub Junctions); -impl From for MultiLocation { - fn from(ParentThen(interior): ParentThen) -> Self { - MultiLocation { parents: 1, interior } - } -} - -/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct Ancestor(pub u8); -impl From for MultiLocation { - fn from(Ancestor(parents): Ancestor) -> Self { - MultiLocation { parents, interior: Junctions::Here } - } -} - -/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the -/// inner interior. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct AncestorThen(pub u8, pub Interior); -impl> From> for MultiLocation { - fn from(AncestorThen(parents, interior): AncestorThen) -> Self { - MultiLocation { parents, interior: interior.into() } - } -} - -xcm_procedural::impl_conversion_functions_for_multilocation_v2!(); -xcm_procedural::impl_conversion_functions_for_junctions_v2!(); - -/// Maximum number of `Junction`s that a `Junctions` can contain. -const MAX_JUNCTIONS: usize = 8; - -/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions` -/// implementation uses a Rust `enum` in order to make pattern matching easier. -/// -/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for -/// instructions on constructing parent junctions. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Junctions { - /// The interpreting consensus system. - Here, - /// A relative path comprising 1 junction. - X1(Junction), - /// A relative path comprising 2 junctions. - X2(Junction, Junction), - /// A relative path comprising 3 junctions. - X3(Junction, Junction, Junction), - /// A relative path comprising 4 junctions. - X4(Junction, Junction, Junction, Junction), - /// A relative path comprising 5 junctions. - X5(Junction, Junction, Junction, Junction, Junction), - /// A relative path comprising 6 junctions. - X6(Junction, Junction, Junction, Junction, Junction, Junction), - /// A relative path comprising 7 junctions. - X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction), - /// A relative path comprising 8 junctions. - X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction), -} - -pub struct JunctionsIterator(Junctions); -impl Iterator for JunctionsIterator { - type Item = Junction; - fn next(&mut self) -> Option { - self.0.take_first() - } -} - -impl DoubleEndedIterator for JunctionsIterator { - fn next_back(&mut self) -> Option { - self.0.take_last() - } -} - -pub struct JunctionsRefIterator<'a> { - junctions: &'a Junctions, - next: usize, - back: usize, -} - -impl<'a> Iterator for JunctionsRefIterator<'a> { - type Item = &'a Junction; - fn next(&mut self) -> Option<&'a Junction> { - if self.next.saturating_add(self.back) >= self.junctions.len() { - return None - } - - let result = self.junctions.at(self.next); - self.next += 1; - result - } -} - -impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> { - fn next_back(&mut self) -> Option<&'a Junction> { - let next_back = self.back.saturating_add(1); - // checked_sub here, because if the result is less than 0, we end iteration - let index = self.junctions.len().checked_sub(next_back)?; - if self.next > index { - return None - } - self.back = next_back; - - self.junctions.at(index) - } -} - -impl<'a> IntoIterator for &'a Junctions { - type Item = &'a Junction; - type IntoIter = JunctionsRefIterator<'a>; - fn into_iter(self) -> Self::IntoIter { - JunctionsRefIterator { junctions: self, next: 0, back: 0 } - } -} - -impl IntoIterator for Junctions { - type Item = Junction; - type IntoIter = JunctionsIterator; - fn into_iter(self) -> Self::IntoIter { - JunctionsIterator(self) - } -} - -impl Junctions { - /// Convert `self` into a `MultiLocation` containing 0 parents. - /// - /// Similar to `Into::into`, except that this method can be used in a const evaluation context. - pub const fn into(self) -> MultiLocation { - MultiLocation { parents: 0, interior: self } - } - - /// Convert `self` into a `MultiLocation` containing `n` parents. - /// - /// Similar to `Self::into`, with the added ability to specify the number of parent junctions. - pub const fn into_exterior(self, n: u8) -> MultiLocation { - MultiLocation { parents: n, interior: self } - } - - /// Returns first junction, or `None` if the location is empty. - pub fn first(&self) -> Option<&Junction> { - match &self { - Junctions::Here => None, - Junctions::X1(ref a) => Some(a), - Junctions::X2(ref a, ..) => Some(a), - Junctions::X3(ref a, ..) => Some(a), - Junctions::X4(ref a, ..) => Some(a), - Junctions::X5(ref a, ..) => Some(a), - Junctions::X6(ref a, ..) => Some(a), - Junctions::X7(ref a, ..) => Some(a), - Junctions::X8(ref a, ..) => Some(a), - } - } - - /// Returns last junction, or `None` if the location is empty. - pub fn last(&self) -> Option<&Junction> { - match &self { - Junctions::Here => None, - Junctions::X1(ref a) => Some(a), - Junctions::X2(.., ref a) => Some(a), - Junctions::X3(.., ref a) => Some(a), - Junctions::X4(.., ref a) => Some(a), - Junctions::X5(.., ref a) => Some(a), - Junctions::X6(.., ref a) => Some(a), - Junctions::X7(.., ref a) => Some(a), - Junctions::X8(.., ref a) => Some(a), - } - } - - /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the - /// first element (second item in tuple) or `None` if it was empty. - pub fn split_first(self) -> (Junctions, Option) { - match self { - Junctions::Here => (Junctions::Here, None), - Junctions::X1(a) => (Junctions::Here, Some(a)), - Junctions::X2(a, b) => (Junctions::X1(b), Some(a)), - Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)), - Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)), - Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)), - Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)), - Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)), - Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)), - } - } - - /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the - /// last element (second item in tuple) or `None` if it was empty. - pub fn split_last(self) -> (Junctions, Option) { - match self { - Junctions::Here => (Junctions::Here, None), - Junctions::X1(a) => (Junctions::Here, Some(a)), - Junctions::X2(a, b) => (Junctions::X1(a), Some(b)), - Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)), - Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)), - Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)), - Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)), - Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)), - Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)), - } - } - - /// Removes the first element from `self`, returning it (or `None` if it was empty). - pub fn take_first(&mut self) -> Option { - let mut d = Junctions::Here; - mem::swap(&mut *self, &mut d); - let (tail, head) = d.split_first(); - *self = tail; - head - } - - /// Removes the last element from `self`, returning it (or `None` if it was empty). - pub fn take_last(&mut self) -> Option { - let mut d = Junctions::Here; - mem::swap(&mut *self, &mut d); - let (head, tail) = d.split_last(); - *self = head; - tail - } - - /// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow. - pub fn push(&mut self, new: Junction) -> result::Result<(), Junction> { - let mut dummy = Junctions::Here; - mem::swap(self, &mut dummy); - match dummy.pushed_with(new) { - Ok(s) => { - *self = s; - Ok(()) - }, - Err((s, j)) => { - *self = s; - Err(j) - }, - } - } - - /// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow. - pub fn push_front(&mut self, new: Junction) -> result::Result<(), Junction> { - let mut dummy = Junctions::Here; - mem::swap(self, &mut dummy); - match dummy.pushed_front_with(new) { - Ok(s) => { - *self = s; - Ok(()) - }, - Err((s, j)) => { - *self = s; - Err(j) - }, - } - } - - /// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the - /// original value of `self` and `new` in case of overflow. - pub fn pushed_with(self, new: Junction) -> result::Result { - Ok(match self { - Junctions::Here => Junctions::X1(new), - Junctions::X1(a) => Junctions::X2(a, new), - Junctions::X2(a, b) => Junctions::X3(a, b, new), - Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new), - Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new), - Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new), - Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new), - Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new), - s => Err((s, new))?, - }) - } - - /// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the - /// original value of `self` and `new` in case of overflow. - pub fn pushed_front_with(self, new: Junction) -> result::Result { - Ok(match self { - Junctions::Here => Junctions::X1(new), - Junctions::X1(a) => Junctions::X2(new, a), - Junctions::X2(a, b) => Junctions::X3(new, a, b), - Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c), - Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d), - Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e), - Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f), - Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g), - s => Err((s, new))?, - }) - } - - /// Returns the number of junctions in `self`. - pub const fn len(&self) -> usize { - match &self { - Junctions::Here => 0, - Junctions::X1(..) => 1, - Junctions::X2(..) => 2, - Junctions::X3(..) => 3, - Junctions::X4(..) => 4, - Junctions::X5(..) => 5, - Junctions::X6(..) => 6, - Junctions::X7(..) => 7, - Junctions::X8(..) => 8, - } - } - - /// Returns the junction at index `i`, or `None` if the location doesn't contain that many - /// elements. - pub fn at(&self, i: usize) -> Option<&Junction> { - Some(match (i, self) { - (0, Junctions::X1(ref a)) => a, - (0, Junctions::X2(ref a, ..)) => a, - (0, Junctions::X3(ref a, ..)) => a, - (0, Junctions::X4(ref a, ..)) => a, - (0, Junctions::X5(ref a, ..)) => a, - (0, Junctions::X6(ref a, ..)) => a, - (0, Junctions::X7(ref a, ..)) => a, - (0, Junctions::X8(ref a, ..)) => a, - (1, Junctions::X2(_, ref a)) => a, - (1, Junctions::X3(_, ref a, ..)) => a, - (1, Junctions::X4(_, ref a, ..)) => a, - (1, Junctions::X5(_, ref a, ..)) => a, - (1, Junctions::X6(_, ref a, ..)) => a, - (1, Junctions::X7(_, ref a, ..)) => a, - (1, Junctions::X8(_, ref a, ..)) => a, - (2, Junctions::X3(_, _, ref a)) => a, - (2, Junctions::X4(_, _, ref a, ..)) => a, - (2, Junctions::X5(_, _, ref a, ..)) => a, - (2, Junctions::X6(_, _, ref a, ..)) => a, - (2, Junctions::X7(_, _, ref a, ..)) => a, - (2, Junctions::X8(_, _, ref a, ..)) => a, - (3, Junctions::X4(_, _, _, ref a)) => a, - (3, Junctions::X5(_, _, _, ref a, ..)) => a, - (3, Junctions::X6(_, _, _, ref a, ..)) => a, - (3, Junctions::X7(_, _, _, ref a, ..)) => a, - (3, Junctions::X8(_, _, _, ref a, ..)) => a, - (4, Junctions::X5(_, _, _, _, ref a)) => a, - (4, Junctions::X6(_, _, _, _, ref a, ..)) => a, - (4, Junctions::X7(_, _, _, _, ref a, ..)) => a, - (4, Junctions::X8(_, _, _, _, ref a, ..)) => a, - (5, Junctions::X6(_, _, _, _, _, ref a)) => a, - (5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a, - (5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a, - (6, Junctions::X7(_, _, _, _, _, _, ref a)) => a, - (6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a, - (7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a, - _ => return None, - }) - } - - /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't - /// contain that many elements. - pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { - Some(match (i, self) { - (0, Junctions::X1(ref mut a)) => a, - (0, Junctions::X2(ref mut a, ..)) => a, - (0, Junctions::X3(ref mut a, ..)) => a, - (0, Junctions::X4(ref mut a, ..)) => a, - (0, Junctions::X5(ref mut a, ..)) => a, - (0, Junctions::X6(ref mut a, ..)) => a, - (0, Junctions::X7(ref mut a, ..)) => a, - (0, Junctions::X8(ref mut a, ..)) => a, - (1, Junctions::X2(_, ref mut a)) => a, - (1, Junctions::X3(_, ref mut a, ..)) => a, - (1, Junctions::X4(_, ref mut a, ..)) => a, - (1, Junctions::X5(_, ref mut a, ..)) => a, - (1, Junctions::X6(_, ref mut a, ..)) => a, - (1, Junctions::X7(_, ref mut a, ..)) => a, - (1, Junctions::X8(_, ref mut a, ..)) => a, - (2, Junctions::X3(_, _, ref mut a)) => a, - (2, Junctions::X4(_, _, ref mut a, ..)) => a, - (2, Junctions::X5(_, _, ref mut a, ..)) => a, - (2, Junctions::X6(_, _, ref mut a, ..)) => a, - (2, Junctions::X7(_, _, ref mut a, ..)) => a, - (2, Junctions::X8(_, _, ref mut a, ..)) => a, - (3, Junctions::X4(_, _, _, ref mut a)) => a, - (3, Junctions::X5(_, _, _, ref mut a, ..)) => a, - (3, Junctions::X6(_, _, _, ref mut a, ..)) => a, - (3, Junctions::X7(_, _, _, ref mut a, ..)) => a, - (3, Junctions::X8(_, _, _, ref mut a, ..)) => a, - (4, Junctions::X5(_, _, _, _, ref mut a)) => a, - (4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a, - (4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a, - (4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a, - (5, Junctions::X6(_, _, _, _, _, ref mut a)) => a, - (5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a, - (5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a, - (6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a, - (6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a, - (7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a, - _ => return None, - }) - } - - /// Returns a reference iterator over the junctions. - pub fn iter(&self) -> JunctionsRefIterator { - JunctionsRefIterator { junctions: self, next: 0, back: 0 } - } - - /// Returns a reference iterator over the junctions in reverse. - #[deprecated(note = "Please use iter().rev()")] - pub fn iter_rev(&self) -> impl Iterator + '_ { - self.iter().rev() - } - - /// Consumes `self` and returns an iterator over the junctions in reverse. - #[deprecated(note = "Please use into_iter().rev()")] - pub fn into_iter_rev(self) -> impl Iterator { - self.into_iter().rev() - } - - /// Ensures that self begins with `prefix` and that it has a single `Junction` item following. - /// If so, returns a reference to this `Junction` item. - /// - /// # Example - /// ```rust - /// # use staging_xcm::v2::{Junctions::*, Junction::*}; - /// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild); - /// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild)); - /// assert_eq!(m.match_and_split(&X1(Parachain(2))), None); - /// ``` - pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> { - if prefix.len() + 1 != self.len() || !self.starts_with(prefix) { - return None - } - self.at(prefix.len()) - } - - /// Returns whether `self` begins with or is equal to `prefix`. - /// - /// # Example - /// ```rust - /// # use staging_xcm::v2::{Junctions::*, Junction::*}; - /// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild); - /// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3)))); - /// assert!(j.starts_with(&j)); - /// assert!(j.starts_with(&X1(Parachain(2)))); - /// assert!(!j.starts_with(&X1(Parachain(999)))); - /// assert!(!j.starts_with(&X4(Parachain(2), PalletInstance(3), OnlyChild, OnlyChild))); - /// ``` - pub fn starts_with(&self, prefix: &Junctions) -> bool { - if self.len() < prefix.len() { - return false - } - prefix.iter().zip(self.iter()).all(|(l, r)| l == r) - } -} - -impl TryFrom for Junctions { - type Error = (); - fn try_from(x: MultiLocation) -> result::Result { - if x.parents > 0 { - Err(()) - } else { - Ok(x.interior) - } - } -} - -#[cfg(test)] -mod tests { - use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen}; - use crate::opaque::v2::{Junction::*, NetworkId::*}; - use codec::{Decode, Encode}; - - #[test] - fn inverted_works() { - let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42)).into(); - let target = (Parent, PalletInstance(69)).into(); - let expected = (Parent, PalletInstance(42)).into(); - let inverted = ancestry.inverted(&target).unwrap(); - assert_eq!(inverted, expected); - - let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into(); - let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into(); - let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into(); - let inverted = ancestry.inverted(&target).unwrap(); - assert_eq!(inverted, expected); - } - - #[test] - fn simplify_basic_works() { - let mut location: MultiLocation = - (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); - let context = X2(Parachain(1000), PalletInstance(42)); - let expected = GeneralIndex(69).into(); - location.simplify(&context); - assert_eq!(location, expected); - - let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into(); - let context = X1(PalletInstance(42)); - let expected = GeneralIndex(69).into(); - location.simplify(&context); - assert_eq!(location, expected); - - let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into(); - let context = X2(Parachain(1000), PalletInstance(42)); - let expected = GeneralIndex(69).into(); - location.simplify(&context); - assert_eq!(location, expected); - - let mut location: MultiLocation = - (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); - let context = X3(OnlyChild, Parachain(1000), PalletInstance(42)); - let expected = GeneralIndex(69).into(); - location.simplify(&context); - assert_eq!(location, expected); - } - - #[test] - fn simplify_incompatible_location_fails() { - let mut location: MultiLocation = - (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); - let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42)); - let expected = - (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); - location.simplify(&context); - assert_eq!(location, expected); - - let mut location: MultiLocation = - (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); - let context = X1(Parachain(1000)); - let expected = - (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); - location.simplify(&context); - assert_eq!(location, expected); - } - - #[test] - fn reanchor_works() { - let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into(); - let ancestry = Parachain(2000).into(); - let target = (Parent, Parachain(1000)).into(); - let expected = GeneralIndex(42).into(); - id.reanchor(&target, &ancestry).unwrap(); - assert_eq!(id, expected); - } - - #[test] - fn encode_and_decode_works() { - let m = MultiLocation { - parents: 1, - interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), - }; - let encoded = m.encode(); - assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec()); - let decoded = MultiLocation::decode(&mut &encoded[..]); - assert_eq!(decoded, Ok(m)); - } - - #[test] - fn match_and_split_works() { - let m = MultiLocation { - parents: 1, - interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), - }; - assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None); - assert_eq!( - m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }), - Some(&AccountIndex64 { network: Any, index: 23 }) - ); - assert_eq!(m.match_and_split(&m), None); - } - - #[test] - fn starts_with_works() { - let full: MultiLocation = - (Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into(); - let identity: MultiLocation = full.clone(); - let prefix: MultiLocation = (Parent, Parachain(1000)).into(); - let wrong_parachain: MultiLocation = (Parent, Parachain(1001)).into(); - let wrong_account: MultiLocation = - (Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into(); - let no_parents: MultiLocation = (Parachain(1000)).into(); - let too_many_parents: MultiLocation = (Parent, Parent, Parachain(1000)).into(); - - assert!(full.starts_with(&identity)); - assert!(full.starts_with(&prefix)); - assert!(!full.starts_with(&wrong_parachain)); - assert!(!full.starts_with(&wrong_account)); - assert!(!full.starts_with(&no_parents)); - assert!(!full.starts_with(&too_many_parents)); - } - - #[test] - fn append_with_works() { - let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) }; - assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(())); - assert_eq!( - m, - MultiLocation { - parents: 1, - interior: X3(Parachain(42), PalletInstance(3), acc.clone()) - } - ); - - // cannot append to create overly long multilocation - let acc = AccountIndex64 { network: Any, index: 23 }; - let m = MultiLocation { - parents: 254, - interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild), - }; - let suffix = X4(PalletInstance(3), acc.clone(), OnlyChild, OnlyChild); - assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix)); - } - - #[test] - fn prepend_with_works() { - let mut m = MultiLocation { - parents: 1, - interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), - }; - assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(())); - assert_eq!( - m, - MultiLocation { - parents: 1, - interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) - } - ); - - // cannot prepend to create overly long multilocation - let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) }; - let prefix = MultiLocation { parents: 2, interior: Here }; - assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); - - let prefix = MultiLocation { parents: 1, interior: Here }; - assert_eq!(m.prepend_with(prefix), Ok(())); - assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) }); - } - - #[test] - fn double_ended_ref_iteration_works() { - let m = X3(Parachain(1000), Parachain(3), PalletInstance(5)); - let mut iter = m.iter(); - - let first = iter.next().unwrap(); - assert_eq!(first, &Parachain(1000)); - let third = iter.next_back().unwrap(); - assert_eq!(third, &PalletInstance(5)); - let second = iter.next_back().unwrap(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(second, &Parachain(3)); - - let res = Here - .pushed_with(first.clone()) - .unwrap() - .pushed_with(second.clone()) - .unwrap() - .pushed_with(third.clone()) - .unwrap(); - assert_eq!(m, res); - - // make sure there's no funny business with the 0 indexing - let m = Here; - let mut iter = m.iter(); - - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - } - - #[test] - fn conversion_from_other_types_works() { - fn takes_multilocation>(_arg: Arg) {} - - takes_multilocation(Parent); - takes_multilocation(Here); - takes_multilocation(X1(Parachain(42))); - takes_multilocation((255, PalletInstance(8))); - takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3))); - takes_multilocation((Ancestor(2), Here)); - takes_multilocation(AncestorThen( - 3, - X2(Parachain(43), AccountIndex64 { network: Any, index: 155 }), - )); - takes_multilocation((Parent, AccountId32 { network: Any, id: [0; 32] })); - takes_multilocation((Parent, Here)); - takes_multilocation(ParentThen(X1(Parachain(75)))); - takes_multilocation([Parachain(100), PalletInstance(3)]); - } -} diff --git a/polkadot/xcm/src/v2/traits.rs b/polkadot/xcm/src/v2/traits.rs deleted file mode 100644 index 815495b81271..000000000000 --- a/polkadot/xcm/src/v2/traits.rs +++ /dev/null @@ -1,363 +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 . - -//! Cross-Consensus Message format data structures. - -use crate::v3::Error as NewError; -use codec::{Decode, Encode}; -use core::result; -use scale_info::TypeInfo; - -use super::*; - -// A simple trait to get the weight of some object. -pub trait GetWeight { - fn weight(&self) -> sp_weights::Weight; -} - -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Error { - // Errors that happen due to instructions being executed. These alone are defined in the - // XCM specification. - /// An arithmetic overflow happened. - #[codec(index = 0)] - Overflow, - /// The instruction is intentionally unsupported. - #[codec(index = 1)] - Unimplemented, - /// Origin Register does not contain a value value for a reserve transfer notification. - #[codec(index = 2)] - UntrustedReserveLocation, - /// Origin Register does not contain a value value for a teleport notification. - #[codec(index = 3)] - UntrustedTeleportLocation, - /// `MultiLocation` value too large to descend further. - #[codec(index = 4)] - MultiLocationFull, - /// `MultiLocation` value ascend more parents than known ancestors of local location. - #[codec(index = 5)] - MultiLocationNotInvertible, - /// The Origin Register does not contain a valid value for instruction. - #[codec(index = 6)] - BadOrigin, - /// The location parameter is not a valid value for the instruction. - #[codec(index = 7)] - InvalidLocation, - /// The given asset is not handled. - #[codec(index = 8)] - AssetNotFound, - /// An asset transaction (like withdraw or deposit) failed (typically due to type conversions). - #[codec(index = 9)] - FailedToTransactAsset(#[codec(skip)] &'static str), - /// An asset cannot be withdrawn, potentially due to lack of ownership, availability or rights. - #[codec(index = 10)] - NotWithdrawable, - /// An asset cannot be deposited under the ownership of a particular location. - #[codec(index = 11)] - LocationCannotHold, - /// Attempt to send a message greater than the maximum supported by the transport protocol. - #[codec(index = 12)] - ExceedsMaxMessageSize, - /// The given message cannot be translated into a format supported by the destination. - #[codec(index = 13)] - DestinationUnsupported, - /// Destination is routable, but there is some issue with the transport mechanism. - #[codec(index = 14)] - Transport(#[codec(skip)] &'static str), - /// Destination is known to be unroutable. - #[codec(index = 15)] - Unroutable, - /// Used by `ClaimAsset` when the given claim could not be recognized/found. - #[codec(index = 16)] - UnknownClaim, - /// Used by `Transact` when the functor cannot be decoded. - #[codec(index = 17)] - FailedToDecode, - /// Used by `Transact` to indicate that the given weight limit could be breached by the - /// functor. - #[codec(index = 18)] - MaxWeightInvalid, - /// Used by `BuyExecution` when the Holding Register does not contain payable fees. - #[codec(index = 19)] - NotHoldingFees, - /// Used by `BuyExecution` when the fees declared to purchase weight are insufficient. - #[codec(index = 20)] - TooExpensive, - /// Used by the `Trap` instruction to force an error intentionally. Its code is included. - #[codec(index = 21)] - Trap(u64), - - // Errors that happen prior to instructions being executed. These fall outside of the XCM - // spec. - /// XCM version not able to be handled. - UnhandledXcmVersion, - /// Execution of the XCM would potentially result in a greater weight used than weight limit. - WeightLimitReached(Weight), - /// The XCM did not pass the barrier condition for execution. - /// - /// The barrier condition differs on different chains and in different circumstances, but - /// generally it means that the conditions surrounding the message were not such that the chain - /// considers the message worth spending time executing. Since most chains lift the barrier to - /// execution on appropriate payment, presentation of an NFT voucher, or based on the message - /// origin, it means that none of those were the case. - Barrier, - /// The weight of an XCM message is not computable ahead of execution. - WeightNotComputable, -} - -impl TryFrom for Error { - type Error = (); - fn try_from(new_error: NewError) -> result::Result { - use NewError::*; - Ok(match new_error { - Overflow => Self::Overflow, - Unimplemented => Self::Unimplemented, - UntrustedReserveLocation => Self::UntrustedReserveLocation, - UntrustedTeleportLocation => Self::UntrustedTeleportLocation, - LocationFull => Self::MultiLocationFull, - LocationNotInvertible => Self::MultiLocationNotInvertible, - BadOrigin => Self::BadOrigin, - InvalidLocation => Self::InvalidLocation, - AssetNotFound => Self::AssetNotFound, - FailedToTransactAsset(s) => Self::FailedToTransactAsset(s), - NotWithdrawable => Self::NotWithdrawable, - LocationCannotHold => Self::LocationCannotHold, - ExceedsMaxMessageSize => Self::ExceedsMaxMessageSize, - DestinationUnsupported => Self::DestinationUnsupported, - Transport(s) => Self::Transport(s), - Unroutable => Self::Unroutable, - UnknownClaim => Self::UnknownClaim, - FailedToDecode => Self::FailedToDecode, - MaxWeightInvalid => Self::MaxWeightInvalid, - NotHoldingFees => Self::NotHoldingFees, - TooExpensive => Self::TooExpensive, - Trap(i) => Self::Trap(i), - _ => return Err(()), - }) - } -} - -impl From for Error { - fn from(e: SendError) -> Self { - match e { - SendError::NotApplicable(..) | SendError::Unroutable => Error::Unroutable, - SendError::Transport(s) => Error::Transport(s), - SendError::DestinationUnsupported => Error::DestinationUnsupported, - SendError::ExceedsMaxMessageSize => Error::ExceedsMaxMessageSize, - } - } -} - -pub type Result = result::Result<(), Error>; - -/// Outcome of an XCM execution. -#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum Outcome { - /// Execution completed successfully; given weight was used. - Complete(Weight), - /// Execution started, but did not complete successfully due to the given error; given weight - /// was used. - Incomplete(Weight, Error), - /// Execution did not start due to the given error. - Error(Error), -} - -impl Outcome { - pub fn ensure_complete(self) -> Result { - match self { - Outcome::Complete(_) => Ok(()), - Outcome::Incomplete(_, e) => Err(e), - Outcome::Error(e) => Err(e), - } - } - pub fn ensure_execution(self) -> result::Result { - match self { - Outcome::Complete(w) => Ok(w), - Outcome::Incomplete(w, _) => Ok(w), - Outcome::Error(e) => Err(e), - } - } - /// How much weight was used by the XCM execution attempt. - pub fn weight_used(&self) -> Weight { - match self { - Outcome::Complete(w) => *w, - Outcome::Incomplete(w, _) => *w, - Outcome::Error(_) => 0, - } - } -} - -/// Type of XCM message executor. -pub trait ExecuteXcm { - /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The - /// weight limit is a basic hard-limit and the implementation may place further restrictions or - /// requirements on weight and other aspects. - fn execute_xcm( - origin: impl Into, - message: Xcm, - weight_limit: Weight, - ) -> Outcome { - let origin = origin.into(); - log::debug!( - target: "xcm::execute_xcm", - "origin: {:?}, message: {:?}, weight_limit: {:?}", - origin, - message, - weight_limit, - ); - Self::execute_xcm_in_credit(origin, message, weight_limit, 0) - } - - /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. - /// - /// Some amount of `weight_credit` may be provided which, depending on the implementation, may - /// allow execution without associated payment. - fn execute_xcm_in_credit( - origin: impl Into, - message: Xcm, - weight_limit: Weight, - weight_credit: Weight, - ) -> Outcome; -} - -impl ExecuteXcm for () { - fn execute_xcm_in_credit( - _origin: impl Into, - _message: Xcm, - _weight_limit: Weight, - _weight_credit: Weight, - ) -> Outcome { - Outcome::Error(Error::Unimplemented) - } -} - -/// Error result value when attempting to send an XCM message. -#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, scale_info::TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -pub enum SendError { - /// The message and destination combination was not recognized as being reachable. - /// - /// This is not considered fatal: if there are alternative transport routes available, then - /// they may be attempted. For this reason, the destination and message are contained. - NotApplicable(MultiLocation, Xcm<()>), - /// Destination is routable, but there is some issue with the transport mechanism. This is - /// considered fatal. - /// A human-readable explanation of the specific issue is provided. - Transport(#[codec(skip)] &'static str), - /// Destination is known to be unroutable. This is considered fatal. - Unroutable, - /// The given message cannot be translated into a format that the destination can be expected - /// to interpret. - DestinationUnsupported, - /// Message could not be sent due to its size exceeding the maximum allowed by the transport - /// layer. - ExceedsMaxMessageSize, -} - -/// Result value when attempting to send an XCM message. -pub type SendResult = result::Result<(), SendError>; - -/// Utility for sending an XCM message. -/// -/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each -/// router might return `NotApplicable` to pass the execution to the next sender item. Note that -/// each `NotApplicable` might alter the destination and the XCM message for to the next router. -/// -/// -/// # Example -/// ```rust -/// # use staging_xcm::v2::prelude::*; -/// # use codec::Encode; -/// -/// /// A sender that only passes the message through and does nothing. -/// struct Sender1; -/// impl SendXcm for Sender1 { -/// fn send_xcm(destination: impl Into, message: Xcm<()>) -> SendResult { -/// return Err(SendError::NotApplicable(destination.into(), message)) -/// } -/// } -/// -/// /// A sender that accepts a message that has two junctions, otherwise stops the routing. -/// struct Sender2; -/// impl SendXcm for Sender2 { -/// fn send_xcm(destination: impl Into, message: Xcm<()>) -> SendResult { -/// let destination = destination.into(); -/// if destination.parents == 0 && destination.interior.len() == 2 { -/// Ok(()) -/// } else { -/// Err(SendError::Unroutable) -/// } -/// } -/// } -/// -/// /// A sender that accepts a message from a parent, passing through otherwise. -/// struct Sender3; -/// impl SendXcm for Sender3 { -/// fn send_xcm(destination: impl Into, message: Xcm<()>) -> SendResult { -/// let destination = destination.into(); -/// match destination { -/// MultiLocation { parents: 1, interior: Here } => Ok(()), -/// _ => Err(SendError::NotApplicable(destination, message)), -/// } -/// } -/// } -/// -/// // A call to send via XCM. We don't really care about this. -/// # fn main() { -/// let call: Vec = ().encode(); -/// let message = Xcm(vec![Instruction::Transact { -/// origin_type: OriginKind::Superuser, -/// require_weight_at_most: 0, -/// call: call.into(), -/// }]); -/// -/// assert!( -/// // Sender2 will block this. -/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(Parent, message.clone()) -/// .is_err() -/// ); -/// -/// assert!( -/// // Sender3 will catch this. -/// <(Sender1, Sender3) as SendXcm>::send_xcm(Parent, message.clone()) -/// .is_ok() -/// ); -/// # } -/// ``` -pub trait SendXcm { - /// Send an XCM `message` to a given `destination`. - /// - /// If it is not a destination which can be reached with this type but possibly could by others, - /// then it *MUST* return `NotApplicable`. Any other error will cause the tuple implementation - /// to exit early without trying other type fields. - fn send_xcm(destination: impl Into, message: Xcm<()>) -> SendResult; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl SendXcm for Tuple { - fn send_xcm(destination: impl Into, message: Xcm<()>) -> SendResult { - for_tuples!( #( - // we shadow `destination` and `message` in each expansion for the next one. - let (destination, message) = match Tuple::send_xcm(destination, message) { - Err(SendError::NotApplicable(d, m)) => (d, m), - o @ _ => return o, - }; - )* ); - Err(SendError::NotApplicable(destination.into(), message)) - } -} diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index 24348bf2e672..24e9c16bf699 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -18,10 +18,6 @@ use super::{Junctions, MultiLocation}; use crate::{ - v2::{ - BodyId as OldBodyId, BodyPart as OldBodyPart, Junction as OldJunction, - NetworkId as OldNetworkId, - }, v4::{Junction as NewJunction, NetworkId as NewNetworkId}, VersionedLocation, }; @@ -80,30 +76,6 @@ pub enum NetworkId { PolkadotBulletin, } -impl From for Option { - fn from(old: OldNetworkId) -> Option { - use OldNetworkId::*; - match old { - Any => None, - Named(_) => None, - Polkadot => Some(NetworkId::Polkadot), - Kusama => Some(NetworkId::Kusama), - } - } -} - -impl TryFrom for NetworkId { - type Error = (); - fn try_from(old: OldNetworkId) -> Result { - use OldNetworkId::*; - match old { - Any | Named(_) => Err(()), - Polkadot => Ok(NetworkId::Polkadot), - Kusama => Ok(NetworkId::Kusama), - } - } -} - impl From for Option { fn from(new: NewNetworkId) -> Self { Some(NetworkId::from(new)) @@ -175,32 +147,6 @@ pub enum BodyId { Treasury, } -impl TryFrom for BodyId { - type Error = (); - fn try_from(value: OldBodyId) -> Result { - use OldBodyId::*; - Ok(match value { - Unit => Self::Unit, - Named(n) => - if n.len() == 4 { - let mut r = [0u8; 4]; - r.copy_from_slice(&n[..]); - Self::Moniker(r) - } else { - return Err(()) - }, - Index(n) => Self::Index(n), - Executive => Self::Executive, - Technical => Self::Technical, - Legislative => Self::Legislative, - Judicial => Self::Judicial, - Defense => Self::Defense, - Administration => Self::Administration, - Treasury => Self::Treasury, - }) - } -} - /// A part of a pluralistic body. #[derive( Copy, @@ -262,20 +208,6 @@ impl BodyPart { } } -impl TryFrom for BodyPart { - type Error = (); - fn try_from(value: OldBodyPart) -> Result { - use OldBodyPart::*; - Ok(match value { - Voice => Self::Voice, - Members { count } => Self::Members { count }, - Fraction { nom, denom } => Self::Fraction { nom, denom }, - AtLeastProportion { nom, denom } => Self::AtLeastProportion { nom, denom }, - MoreThanProportion { nom, denom } => Self::MoreThanProportion { nom, denom }, - }) - } -} - /// A single item in a path to describe the relative location of a consensus system. /// /// Each item assumes a pre-existing location as its context and is defined in terms of it. @@ -409,36 +341,6 @@ impl From for Junction { } } -impl TryFrom for Junction { - type Error = (); - fn try_from(value: OldJunction) -> Result { - use OldJunction::*; - Ok(match value { - Parachain(id) => Self::Parachain(id), - AccountId32 { network, id } => Self::AccountId32 { network: network.into(), id }, - AccountIndex64 { network, index } => - Self::AccountIndex64 { network: network.into(), index }, - AccountKey20 { network, key } => Self::AccountKey20 { network: network.into(), key }, - PalletInstance(index) => Self::PalletInstance(index), - GeneralIndex(id) => Self::GeneralIndex(id), - GeneralKey(key) => match key.len() { - len @ 0..=32 => Self::GeneralKey { - length: len as u8, - data: { - let mut data = [0u8; 32]; - data[..len].copy_from_slice(&key[..]); - data - }, - }, - _ => return Err(()), - }, - OnlyChild => Self::OnlyChild, - Plurality { id, part } => - Self::Plurality { id: id.try_into()?, part: part.try_into()? }, - }) - } -} - impl TryFrom for Junction { type Error = (); @@ -496,30 +398,3 @@ impl Junction { } } } - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn junction_round_trip_works() { - let j = Junction::GeneralKey { length: 32, data: [1u8; 32] }; - let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap(); - assert_eq!(j, k); - - let j = OldJunction::GeneralKey(vec![1u8; 32].try_into().unwrap()); - let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap(); - assert_eq!(j, k); - - let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap()); - let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap(); - assert_eq!(j, k); - let s: BoundedSlice<_, _> = (&k).try_into().unwrap(); - assert_eq!(s, &[1u8, 2, 3, 4][..]); - - let j = OldJunction::GeneralKey(vec![1u8, 2, 3, 4].try_into().unwrap()); - let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap(); - assert_eq!(j, k); - } -} diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index ff64c98e15b3..b60209a440c6 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -16,11 +16,6 @@ //! Version 3 of the Cross-Consensus Message format data structures. -#[allow(deprecated)] -use super::v2::{ - Instruction as OldInstruction, OriginKind as OldOriginKind, Response as OldResponse, - WeightLimit as OldWeightLimit, Xcm as OldXcm, -}; use super::v4::{ Instruction as NewInstruction, PalletInfo as NewPalletInfo, QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm, @@ -56,43 +51,6 @@ pub use traits::{ SendError, SendResult, SendXcm, Weight, XcmHash, }; -/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] -#[scale_info(replace_segment("staging_xcm", "xcm"))] -#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] -pub enum OriginKind { - /// Origin should just be the native dispatch origin representation for the sender in the - /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin - /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a - /// primary/native dispatch origin form. - Native, - - /// Origin should just be the standard account-based origin with the sovereign account of - /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. - SovereignAccount, - - /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. - /// This will not usually be an available option. - Superuser, - - /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be - /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be - /// the `pallet_xcm::Origin::Xcm` type. - Xcm, -} - -impl From for OriginKind { - fn from(old: OldOriginKind) -> Self { - use OldOriginKind::*; - match old { - Native => Self::Native, - SovereignAccount => Self::SovereignAccount, - Superuser => Self::Superuser, - Xcm => Self::Xcm, - } - } -} - /// This module's XCM version. pub const VERSION: super::Version = 3; @@ -456,14 +414,29 @@ impl From for Option { } } -impl From for WeightLimit { - fn from(x: OldWeightLimit) -> Self { - use OldWeightLimit::*; - match x { - Limited(w) => Self::Limited(Weight::from_parts(w, DEFAULT_PROOF_SIZE)), - Unlimited => Self::Unlimited, - } - } +/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] +pub enum OriginKind { + /// Origin should just be the native dispatch origin representation for the sender in the + /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin + /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a + /// primary/native dispatch origin form. + Native, + + /// Origin should just be the standard account-based origin with the sovereign account of + /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. + SovereignAccount, + + /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. + /// This will not usually be an available option. + Superuser, + + /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be + /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be + /// the `pallet_xcm::Origin::Xcm` type. + Xcm, } /// Contextual data pertaining to a specific list of XCM instructions. @@ -819,6 +792,7 @@ pub enum Instruction { /// Kind: *Command* /// /// Errors: + #[builder(pays_fees)] BuyExecution { fees: MultiAsset, weight_limit: WeightLimit }, /// Refund any surplus weight previously bought with `BuyExecution`. @@ -1327,31 +1301,6 @@ pub mod opaque { pub type Instruction = super::Instruction<()>; } -// Convert from a v2 response to a v3 response. -impl TryFrom for Response { - type Error = (); - fn try_from(old_response: OldResponse) -> result::Result { - match old_response { - OldResponse::Assets(assets) => Ok(Self::Assets(assets.try_into()?)), - OldResponse::Version(version) => Ok(Self::Version(version)), - OldResponse::ExecutionResult(error) => Ok(Self::ExecutionResult(match error { - Some((i, e)) => Some((i, e.try_into()?)), - None => None, - })), - OldResponse::Null => Ok(Self::Null), - } - } -} - -// Convert from a v2 XCM to a v3 XCM. -#[allow(deprecated)] -impl TryFrom> for Xcm { - type Error = (); - fn try_from(old_xcm: OldXcm) -> result::Result { - Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::>()?)) - } -} - // Convert from a v4 XCM to a v3 XCM. impl TryFrom> for Xcm { type Error = (); @@ -1501,109 +1450,6 @@ impl TryFrom> for Instruction { } } -/// Default value for the proof size weight component when converting from V2. Set at 64 KB. -/// NOTE: Make sure this is removed after we properly account for PoV weights. -const DEFAULT_PROOF_SIZE: u64 = 64 * 1024; - -// Convert from a v2 instruction to a v3 instruction. -impl TryFrom> for Instruction { - type Error = (); - fn try_from(old_instruction: OldInstruction) -> result::Result { - use OldInstruction::*; - Ok(match old_instruction { - WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?), - ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?), - ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?), - QueryResponse { query_id, response, max_weight } => Self::QueryResponse { - query_id, - response: response.try_into()?, - max_weight: Weight::from_parts(max_weight, DEFAULT_PROOF_SIZE), - querier: None, - }, - TransferAsset { assets, beneficiary } => Self::TransferAsset { - assets: assets.try_into()?, - beneficiary: beneficiary.try_into()?, - }, - TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset { - assets: assets.try_into()?, - dest: dest.try_into()?, - xcm: xcm.try_into()?, - }, - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => - Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, - HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient }, - HrmpChannelClosing { initiator, sender, recipient } => - Self::HrmpChannelClosing { initiator, sender, recipient }, - Transact { origin_type, require_weight_at_most, call } => Self::Transact { - origin_kind: origin_type.into(), - require_weight_at_most: Weight::from_parts( - require_weight_at_most, - DEFAULT_PROOF_SIZE, - ), - call: call.into(), - }, - ReportError { query_id, dest, max_response_weight } => { - let response_info = QueryResponseInfo { - destination: dest.try_into()?, - query_id, - max_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE), - }; - Self::ReportError(response_info) - }, - DepositAsset { assets, max_assets, beneficiary } => Self::DepositAsset { - assets: (assets, max_assets).try_into()?, - beneficiary: beneficiary.try_into()?, - }, - DepositReserveAsset { assets, max_assets, dest, xcm } => { - let assets = (assets, max_assets).try_into()?; - Self::DepositReserveAsset { assets, dest: dest.try_into()?, xcm: xcm.try_into()? } - }, - ExchangeAsset { give, receive } => { - let give = give.try_into()?; - let want = receive.try_into()?; - Self::ExchangeAsset { give, want, maximal: true } - }, - InitiateReserveWithdraw { assets, reserve, xcm } => Self::InitiateReserveWithdraw { - assets: assets.try_into()?, - reserve: reserve.try_into()?, - xcm: xcm.try_into()?, - }, - InitiateTeleport { assets, dest, xcm } => Self::InitiateTeleport { - assets: assets.try_into()?, - dest: dest.try_into()?, - xcm: xcm.try_into()?, - }, - QueryHolding { query_id, dest, assets, max_response_weight } => { - let response_info = QueryResponseInfo { - destination: dest.try_into()?, - query_id, - max_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE), - }; - Self::ReportHolding { response_info, assets: assets.try_into()? } - }, - BuyExecution { fees, weight_limit } => - Self::BuyExecution { fees: fees.try_into()?, weight_limit: weight_limit.into() }, - ClearOrigin => Self::ClearOrigin, - DescendOrigin(who) => Self::DescendOrigin(who.try_into()?), - RefundSurplus => Self::RefundSurplus, - SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?), - SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?), - ClearError => Self::ClearError, - ClaimAsset { assets, ticket } => { - let assets = assets.try_into()?; - let ticket = ticket.try_into()?; - Self::ClaimAsset { assets, ticket } - }, - Trap(code) => Self::Trap(code), - SubscribeVersion { query_id, max_response_weight } => Self::SubscribeVersion { - query_id, - max_response_weight: Weight::from_parts(max_response_weight, DEFAULT_PROOF_SIZE), - }, - UnsubscribeVersion => Self::UnsubscribeVersion, - }) - } -} - #[cfg(test)] mod tests { use super::{prelude::*, *}; diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 56b46b1d921e..e8bd3e167f61 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -27,18 +27,10 @@ //! filtering an XCM holding account. use super::{InteriorMultiLocation, MultiLocation}; -use crate::{ - v2::{ - AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility, - MultiAsset as OldMultiAsset, MultiAssetFilter as OldMultiAssetFilter, - MultiAssets as OldMultiAssets, WildFungibility as OldWildFungibility, - WildMultiAsset as OldWildMultiAsset, - }, - v4::{ - Asset as NewMultiAsset, AssetFilter as NewMultiAssetFilter, AssetId as NewAssetId, - AssetInstance as NewAssetInstance, Assets as NewMultiAssets, Fungibility as NewFungibility, - WildAsset as NewWildMultiAsset, WildFungibility as NewWildFungibility, - }, +use crate::v4::{ + Asset as NewMultiAsset, AssetFilter as NewMultiAssetFilter, AssetId as NewAssetId, + AssetInstance as NewAssetInstance, Assets as NewMultiAssets, Fungibility as NewFungibility, + WildAsset as NewWildMultiAsset, WildFungibility as NewWildFungibility, }; use alloc::{vec, vec::Vec}; use bounded_collections::{BoundedVec, ConstU32}; @@ -85,22 +77,6 @@ pub enum AssetInstance { Array32([u8; 32]), } -impl TryFrom for AssetInstance { - type Error = (); - fn try_from(value: OldAssetInstance) -> Result { - use OldAssetInstance::*; - Ok(match value { - Undefined => Self::Undefined, - Index(n) => Self::Index(n), - Array4(n) => Self::Array4(n), - Array8(n) => Self::Array8(n), - Array16(n) => Self::Array16(n), - Array32(n) => Self::Array32(n), - Blob(_) => return Err(()), - }) - } -} - impl TryFrom for AssetInstance { type Error = (); fn try_from(value: NewAssetInstance) -> Result { @@ -340,17 +316,6 @@ impl> From for Fungibility { } } -impl TryFrom for Fungibility { - type Error = (); - fn try_from(value: OldFungibility) -> Result { - use OldFungibility::*; - Ok(match value { - Fungible(n) => Self::Fungible(n), - NonFungible(i) => Self::NonFungible(i.try_into()?), - }) - } -} - impl TryFrom for Fungibility { type Error = (); fn try_from(value: NewFungibility) -> Result { @@ -387,17 +352,6 @@ pub enum WildFungibility { NonFungible, } -impl TryFrom for WildFungibility { - type Error = (); - fn try_from(value: OldWildFungibility) -> Result { - use OldWildFungibility::*; - Ok(match value { - Fungible => Self::Fungible, - NonFungible => Self::NonFungible, - }) - } -} - impl TryFrom for WildFungibility { type Error = (); fn try_from(value: NewWildFungibility) -> Result { @@ -447,22 +401,6 @@ impl From<[u8; 32]> for AssetId { } } -impl TryFrom for AssetId { - type Error = (); - fn try_from(old: OldAssetId) -> Result { - use OldAssetId::*; - Ok(match old { - Concrete(l) => Self::Concrete(l.try_into()?), - Abstract(v) if v.len() <= 32 => { - let mut r = [0u8; 32]; - r[..v.len()].copy_from_slice(&v[..]); - Self::Abstract(r) - }, - _ => return Err(()), - }) - } -} - impl TryFrom for AssetId { type Error = (); fn try_from(new: NewAssetId) -> Result { @@ -601,13 +539,6 @@ impl MultiAsset { } } -impl TryFrom for MultiAsset { - type Error = (); - fn try_from(old: OldMultiAsset) -> Result { - Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? }) - } -} - impl TryFrom for MultiAsset { type Error = (); fn try_from(new: NewMultiAsset) -> Result { @@ -657,18 +588,6 @@ impl Decode for MultiAssets { } } -impl TryFrom for MultiAssets { - type Error = (); - fn try_from(old: OldMultiAssets) -> Result { - let v = old - .drain() - .into_iter() - .map(MultiAsset::try_from) - .collect::, ()>>()?; - Ok(MultiAssets(v)) - } -} - impl TryFrom for MultiAssets { type Error = (); fn try_from(new: NewMultiAssets) -> Result { @@ -882,17 +801,6 @@ pub enum WildMultiAsset { }, } -impl TryFrom for WildMultiAsset { - type Error = (); - fn try_from(old: OldWildMultiAsset) -> Result { - use OldWildMultiAsset::*; - Ok(match old { - AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? }, - All => Self::All, - }) - } -} - impl TryFrom for WildMultiAsset { type Error = (); fn try_from(new: NewWildMultiAsset) -> Result { @@ -907,19 +815,6 @@ impl TryFrom for WildMultiAsset { } } -impl TryFrom<(OldWildMultiAsset, u32)> for WildMultiAsset { - type Error = (); - fn try_from(old: (OldWildMultiAsset, u32)) -> Result { - use OldWildMultiAsset::*; - let count = old.1; - Ok(match old.0 { - AllOf { id, fun } => - Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }, - All => Self::AllCounted(count), - }) - } -} - impl WildMultiAsset { /// Returns true if `self` is a super-set of the given `inner` asset. pub fn contains(&self, inner: &MultiAsset) -> bool { @@ -1079,16 +974,6 @@ impl MultiAssetFilter { } } -impl TryFrom for MultiAssetFilter { - type Error = (); - fn try_from(old: OldMultiAssetFilter) -> Result { - Ok(match old { - OldMultiAssetFilter::Definite(x) => Self::Definite(x.try_into()?), - OldMultiAssetFilter::Wild(x) => Self::Wild(x.try_into()?), - }) - } -} - impl TryFrom for MultiAssetFilter { type Error = (); fn try_from(new: NewMultiAssetFilter) -> Result { @@ -1100,19 +985,6 @@ impl TryFrom for MultiAssetFilter { } } -impl TryFrom<(OldMultiAssetFilter, u32)> for MultiAssetFilter { - type Error = (); - fn try_from(old: (OldMultiAssetFilter, u32)) -> Result { - let count = old.1; - Ok(match old.0 { - OldMultiAssetFilter::Definite(x) if count >= x.len() as u32 => - Self::Definite(x.try_into()?), - OldMultiAssetFilter::Wild(x) => Self::Wild((x, count).try_into()?), - _ => return Err(()), - }) - } -} - #[cfg(test)] mod tests { use super::super::prelude::*; diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index e51981204d96..8f18312046f8 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -17,9 +17,7 @@ //! XCM `MultiLocation` datatype. use super::{Junction, Junctions}; -use crate::{ - v2::MultiLocation as OldMultiLocation, v4::Location as NewMultiLocation, VersionedLocation, -}; +use crate::{v4::Location as NewMultiLocation, VersionedLocation}; use codec::{Decode, Encode, MaxEncodedLen}; use core::result; use scale_info::TypeInfo; @@ -464,13 +462,6 @@ impl MultiLocation { } } -impl TryFrom for MultiLocation { - type Error = (); - fn try_from(x: OldMultiLocation) -> result::Result { - Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? }) - } -} - impl TryFrom for Option { type Error = (); fn try_from(new: NewMultiLocation) -> result::Result { @@ -759,37 +750,4 @@ mod tests { let expected = MultiLocation::new(2, (GlobalConsensus(Kusama), Parachain(42))); assert_eq!(para_to_remote_para.chain_location(), expected); } - - #[test] - fn conversion_from_other_types_works() { - use crate::v2; - - fn takes_multilocation>(_arg: Arg) {} - - takes_multilocation(Parent); - takes_multilocation(Here); - takes_multilocation(X1(Parachain(42))); - takes_multilocation((Ancestor(255), PalletInstance(8))); - takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3))); - takes_multilocation((Ancestor(2), Here)); - takes_multilocation(AncestorThen( - 3, - X2(Parachain(43), AccountIndex64 { network: None, index: 155 }), - )); - takes_multilocation((Parent, AccountId32 { network: None, id: [0; 32] })); - takes_multilocation((Parent, Here)); - takes_multilocation(ParentThen(X1(Parachain(75)))); - takes_multilocation([Parachain(100), PalletInstance(3)]); - - assert_eq!( - v2::MultiLocation::from(v2::Junctions::Here).try_into(), - Ok(MultiLocation::here()) - ); - assert_eq!(v2::MultiLocation::from(v2::Parent).try_into(), Ok(MultiLocation::parent())); - assert_eq!( - v2::MultiLocation::from((v2::Parent, v2::Parent, v2::Junction::GeneralIndex(42u128),)) - .try_into(), - Ok(MultiLocation { parents: 2, interior: X1(GeneralIndex(42u128)) }), - ); - } } diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs index 34c46453b9a8..cbf85b454cc6 100644 --- a/polkadot/xcm/src/v3/traits.rs +++ b/polkadot/xcm/src/v3/traits.rs @@ -16,20 +16,19 @@ //! Cross-Consensus Message format data structures. -use crate::v2::Error as OldError; -use codec::{Decode, Encode, MaxEncodedLen}; +use crate::v5::Error as NewError; use core::result; use scale_info::TypeInfo; pub use sp_weights::Weight; -use super::*; - // A simple trait to get the weight of some object. pub trait GetWeight { fn weight(&self) -> sp_weights::Weight; } +use super::*; + /// Error codes used in XCM. The first errors codes have explicit indices and are part of the XCM /// format. Those trailing are merely part of the XCM implementation; there is no expectation that /// they will retain the same index over time. @@ -166,25 +165,17 @@ pub enum Error { ExceedsStackLimit, } -impl MaxEncodedLen for Error { - fn max_encoded_len() -> usize { - // TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields - // marked `codec(skip)`. We can hard-code it with the right answer for now. - 1 - } -} - -impl TryFrom for Error { +impl TryFrom for Error { type Error = (); - fn try_from(old_error: OldError) -> result::Result { - use OldError::*; - Ok(match old_error { + fn try_from(new_error: NewError) -> result::Result { + use NewError::*; + Ok(match new_error { Overflow => Self::Overflow, Unimplemented => Self::Unimplemented, UntrustedReserveLocation => Self::UntrustedReserveLocation, UntrustedTeleportLocation => Self::UntrustedTeleportLocation, - MultiLocationFull => Self::LocationFull, - MultiLocationNotInvertible => Self::LocationNotInvertible, + LocationFull => Self::LocationFull, + LocationNotInvertible => Self::LocationNotInvertible, BadOrigin => Self::BadOrigin, InvalidLocation => Self::InvalidLocation, AssetNotFound => Self::AssetNotFound, @@ -201,11 +192,32 @@ impl TryFrom for Error { NotHoldingFees => Self::NotHoldingFees, TooExpensive => Self::TooExpensive, Trap(i) => Self::Trap(i), + ExpectationFalse => Self::ExpectationFalse, + PalletNotFound => Self::PalletNotFound, + NameMismatch => Self::NameMismatch, + VersionIncompatible => Self::VersionIncompatible, + HoldingWouldOverflow => Self::HoldingWouldOverflow, + ExportError => Self::ExportError, + ReanchorFailed => Self::ReanchorFailed, + NoDeal => Self::NoDeal, + FeesNotMet => Self::FeesNotMet, + LockError => Self::LockError, + NoPermission => Self::NoPermission, + Unanchored => Self::Unanchored, + NotDepositable => Self::NotDepositable, _ => return Err(()), }) } } +impl MaxEncodedLen for Error { + fn max_encoded_len() -> usize { + // TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields + // marked `codec(skip)`. We can hard-code it with the right answer for now. + 1 + } +} + impl From for Error { fn from(e: SendError) -> Self { match e { @@ -535,13 +547,13 @@ impl SendXcm for Tuple { } /// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps -/// both in `Some` before passing them as as mutable references into `T::send_xcm`. +/// both in `Some` before passing them as mutable references into `T::send_xcm`. pub fn validate_send(dest: MultiLocation, msg: Xcm<()>) -> SendResult { T::validate(&mut Some(dest), &mut Some(msg)) } /// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps -/// both in `Some` before passing them as as mutable references into `T::send_xcm`. +/// both in `Some` before passing them as mutable references into `T::send_xcm`. /// /// Returns either `Ok` with the price of the delivery, or `Err` with the reason why the message /// could not be sent. diff --git a/polkadot/xcm/src/v4/asset.rs b/polkadot/xcm/src/v4/asset.rs index 41f1f82f828c..d7a9297d6932 100644 --- a/polkadot/xcm/src/v4/asset.rs +++ b/polkadot/xcm/src/v4/asset.rs @@ -27,10 +27,17 @@ //! holding account. use super::{InteriorLocation, Location, Reanchorable}; -use crate::v3::{ - AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility, - MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets, - WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset, +use crate::{ + v3::{ + AssetId as OldAssetId, AssetInstance as OldAssetInstance, Fungibility as OldFungibility, + MultiAsset as OldAsset, MultiAssetFilter as OldAssetFilter, MultiAssets as OldAssets, + WildFungibility as OldWildFungibility, WildMultiAsset as OldWildAsset, + }, + v5::{ + Asset as NewAsset, AssetFilter as NewAssetFilter, AssetId as NewAssetId, + AssetInstance as NewAssetInstance, Assets as NewAssets, Fungibility as NewFungibility, + WildAsset as NewWildAsset, WildFungibility as NewWildFungibility, + }, }; use alloc::{vec, vec::Vec}; use bounded_collections::{BoundedVec, ConstU32}; @@ -90,6 +97,21 @@ impl TryFrom for AssetInstance { } } +impl TryFrom for AssetInstance { + type Error = (); + fn try_from(value: NewAssetInstance) -> Result { + use NewAssetInstance::*; + Ok(match value { + Undefined => Self::Undefined, + Index(n) => Self::Index(n), + Array4(n) => Self::Array4(n), + Array8(n) => Self::Array8(n), + Array16(n) => Self::Array16(n), + Array32(n) => Self::Array32(n), + }) + } +} + impl From<()> for AssetInstance { fn from(_: ()) -> Self { Self::Undefined @@ -244,6 +266,17 @@ impl TryFrom for u128 { } } +impl TryFrom for Fungibility { + type Error = (); + fn try_from(value: NewFungibility) -> Result { + use NewFungibility::*; + Ok(match value { + Fungible(n) => Self::Fungible(n), + NonFungible(i) => Self::NonFungible(i.try_into()?), + }) + } +} + /// Classification of whether an asset is fungible or not, along with a mandatory amount or /// instance. #[derive( @@ -357,6 +390,17 @@ impl TryFrom for WildFungibility { } } +impl TryFrom for WildFungibility { + type Error = (); + fn try_from(value: NewWildFungibility) -> Result { + use NewWildFungibility::*; + Ok(match value { + Fungible => Self::Fungible, + NonFungible => Self::NonFungible, + }) + } +} + /// Location to identify an asset. #[derive( Clone, @@ -391,6 +435,13 @@ impl TryFrom for AssetId { } } +impl TryFrom for AssetId { + type Error = (); + fn try_from(new: NewAssetId) -> Result { + Ok(Self(new.0.try_into()?)) + } +} + impl AssetId { /// Prepend a `Location` to an asset id, giving it a new root location. pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> { @@ -526,6 +577,13 @@ impl TryFrom for Asset { } } +impl TryFrom for Asset { + type Error = (); + fn try_from(new: NewAsset) -> Result { + Ok(Self { id: new.id.try_into()?, fun: new.fun.try_into()? }) + } +} + /// A `Vec` of `Asset`s. /// /// There are a number of invariants which the construction and mutation functions must ensure are @@ -579,6 +637,18 @@ impl TryFrom for Assets { } } +impl TryFrom for Assets { + type Error = (); + fn try_from(new: NewAssets) -> Result { + let v = new + .into_inner() + .into_iter() + .map(Asset::try_from) + .collect::, ()>>()?; + Ok(Assets(v)) + } +} + impl From> for Assets { fn from(mut assets: Vec) -> Self { let mut res = Vec::with_capacity(assets.len()); @@ -795,6 +865,20 @@ impl TryFrom for WildAsset { } } +impl TryFrom for WildAsset { + type Error = (); + fn try_from(new: NewWildAsset) -> Result { + use NewWildAsset::*; + Ok(match new { + AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? }, + AllOfCounted { id, fun, count } => + Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }, + All => Self::All, + AllCounted(count) => Self::AllCounted(count), + }) + } +} + impl WildAsset { /// Returns true if `self` is a super-set of the given `inner` asset. pub fn contains(&self, inner: &Asset) -> bool { @@ -944,6 +1028,17 @@ impl AssetFilter { } } +impl TryFrom for AssetFilter { + type Error = (); + fn try_from(new: NewAssetFilter) -> Result { + use NewAssetFilter::*; + Ok(match new { + Definite(x) => Self::Definite(x.try_into()?), + Wild(x) => Self::Wild(x.try_into()?), + }) + } +} + impl TryFrom for AssetFilter { type Error = (); fn try_from(old: OldAssetFilter) -> Result { diff --git a/polkadot/xcm/src/v4/junction.rs b/polkadot/xcm/src/v4/junction.rs index 36fb616d2dc5..c6e83214328e 100644 --- a/polkadot/xcm/src/v4/junction.rs +++ b/polkadot/xcm/src/v4/junction.rs @@ -20,6 +20,7 @@ use super::Location; pub use crate::v3::{BodyId, BodyPart}; use crate::{ v3::{Junction as OldJunction, NetworkId as OldNetworkId}, + v5::{Junction as NewJunction, NetworkId as NewNetworkId}, VersionedLocation, }; use bounded_collections::{BoundedSlice, BoundedVec, ConstU32}; @@ -72,7 +73,6 @@ pub enum Junction { /// An instanced, indexed pallet that forms a constituent part of the context. /// /// Generally used when the context is a Frame-based chain. - // TODO XCMv4 inner should be `Compact`. PalletInstance(u8), /// A non-descript index within the context location. /// @@ -103,6 +103,28 @@ pub enum Junction { GlobalConsensus(NetworkId), } +impl From for Option { + fn from(new: NewNetworkId) -> Self { + Some(NetworkId::from(new)) + } +} + +impl From for NetworkId { + fn from(new: NewNetworkId) -> Self { + use NewNetworkId::*; + match new { + ByGenesis(hash) => Self::ByGenesis(hash), + ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash }, + Polkadot => Self::Polkadot, + Kusama => Self::Kusama, + Ethereum { chain_id } => Self::Ethereum { chain_id }, + BitcoinCore => Self::BitcoinCore, + BitcoinCash => Self::BitcoinCash, + PolkadotBulletin => Self::PolkadotBulletin, + } + } +} + /// A global identifier of a data structure existing within consensus. /// /// Maintenance note: Networks with global consensus and which are practically bridgeable within the @@ -253,6 +275,29 @@ impl TryFrom for Junction { } } +impl TryFrom for Junction { + type Error = (); + + fn try_from(value: NewJunction) -> Result { + use NewJunction::*; + Ok(match value { + Parachain(id) => Self::Parachain(id), + AccountId32 { network: maybe_network, id } => + Self::AccountId32 { network: maybe_network.map(|network| network.into()), id }, + AccountIndex64 { network: maybe_network, index } => + Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index }, + AccountKey20 { network: maybe_network, key } => + Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key }, + PalletInstance(index) => Self::PalletInstance(index), + GeneralIndex(id) => Self::GeneralIndex(id), + GeneralKey { length, data } => Self::GeneralKey { length, data }, + OnlyChild => Self::OnlyChild, + Plurality { id, part } => Self::Plurality { id, part }, + GlobalConsensus(network) => Self::GlobalConsensus(network.into()), + }) + } +} + impl Junction { /// Convert `self` into a `Location` containing 0 parents. /// diff --git a/polkadot/xcm/src/v4/location.rs b/polkadot/xcm/src/v4/location.rs index f2c302495c73..3a44b0696be4 100644 --- a/polkadot/xcm/src/v4/location.rs +++ b/polkadot/xcm/src/v4/location.rs @@ -17,7 +17,7 @@ //! XCM `Location` datatype. use super::{traits::Reanchorable, Junction, Junctions}; -use crate::{v3::MultiLocation as OldLocation, VersionedLocation}; +use crate::{v3::MultiLocation as OldLocation, v5::Location as NewLocation, VersionedLocation}; use codec::{Decode, Encode, MaxEncodedLen}; use core::result; use scale_info::TypeInfo; @@ -489,6 +489,20 @@ impl TryFrom for Location { } } +impl TryFrom for Option { + type Error = (); + fn try_from(new: NewLocation) -> result::Result { + Ok(Some(Location::try_from(new)?)) + } +} + +impl TryFrom for Location { + type Error = (); + fn try_from(new: NewLocation) -> result::Result { + Ok(Location { parents: new.parent_count(), interior: new.interior().clone().try_into()? }) + } +} + /// A unit struct which can be converted into a `Location` of `parents` value 1. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Parent; diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs index a2b12dcc54ce..a0ce551b7608 100644 --- a/polkadot/xcm/src/v4/mod.rs +++ b/polkadot/xcm/src/v4/mod.rs @@ -17,9 +17,15 @@ //! Version 4 of the Cross-Consensus Message format data structures. pub use super::v3::GetWeight; -use super::v3::{ - Instruction as OldInstruction, PalletInfo as OldPalletInfo, - QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm, +use super::{ + v3::{ + Instruction as OldInstruction, PalletInfo as OldPalletInfo, + QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm, + }, + v5::{ + Instruction as NewInstruction, PalletInfo as NewPalletInfo, + QueryResponseInfo as NewQueryResponseInfo, Response as NewResponse, Xcm as NewXcm, + }, }; use crate::DoubleEncoded; use alloc::{vec, vec::Vec}; @@ -30,6 +36,7 @@ use codec::{ }; use core::{fmt::Debug, result}; use derivative::Derivative; +use frame_support::dispatch::GetDispatchInfo; use scale_info::TypeInfo; mod asset; @@ -50,7 +57,7 @@ pub use traits::{ SendError, SendResult, SendXcm, Weight, XcmHash, }; // These parts of XCM v3 are unchanged in XCM v4, and are re-imported here. -pub use super::v3::{MaybeErrorCode, OriginKind, WeightLimit}; +pub use super::v3::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit}; /// This module's XCM version. pub const VERSION: super::Version = 4; @@ -222,9 +229,6 @@ pub mod prelude { parameter_types! { pub MaxPalletNameLen: u32 = 48; - /// Maximum size of the encoded error code coming from a `Dispatch` result, used for - /// `MaybeErrorCode`. This is not (yet) enforced, so it's just an indication of expectation. - pub MaxDispatchErrorLen: u32 = 128; pub MaxPalletsInfo: u32 = 64; } @@ -258,6 +262,22 @@ impl TryInto for PalletInfo { } } +impl TryInto for PalletInfo { + type Error = (); + + fn try_into(self) -> result::Result { + NewPalletInfo::new( + self.index, + self.name.into_inner(), + self.module_name.into_inner(), + self.major, + self.minor, + self.patch, + ) + .map_err(|_| ()) + } +} + impl PalletInfo { pub fn new( index: u32, @@ -322,6 +342,36 @@ impl TryFrom for Response { } } +impl TryFrom for Response { + type Error = (); + + fn try_from(new: NewResponse) -> result::Result { + use NewResponse::*; + Ok(match new { + Null => Self::Null, + Assets(assets) => Self::Assets(assets.try_into()?), + ExecutionResult(result) => Self::ExecutionResult( + result + .map(|(num, new_error)| (num, new_error.try_into())) + .map(|(num, result)| result.map(|inner| (num, inner))) + .transpose()?, + ), + Version(version) => Self::Version(version), + PalletsInfo(pallet_info) => { + let inner = pallet_info + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?; + Self::PalletsInfo( + BoundedVec::::try_from(inner).map_err(|_| ())?, + ) + }, + DispatchResult(maybe_error) => + Self::DispatchResult(maybe_error.try_into().map_err(|_| ())?), + }) + } +} + /// Information regarding the composition of a query response. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] pub struct QueryResponseInfo { @@ -334,6 +384,18 @@ pub struct QueryResponseInfo { pub max_weight: Weight, } +impl TryFrom for QueryResponseInfo { + type Error = (); + + fn try_from(new: NewQueryResponseInfo) -> result::Result { + Ok(Self { + destination: new.destination.try_into()?, + query_id: new.query_id, + max_weight: new.max_weight, + }) + } +} + impl TryFrom for QueryResponseInfo { type Error = (); @@ -690,6 +752,7 @@ pub enum Instruction { /// Kind: *Command* /// /// Errors: + #[builder(pays_fees)] BuyExecution { fees: Asset, weight_limit: WeightLimit }, /// Refund any surplus weight previously bought with `BuyExecution`. @@ -1206,6 +1269,183 @@ impl TryFrom> for Xcm { } } +// Convert from a v5 XCM to a v4 XCM. +impl TryFrom> for Xcm { + type Error = (); + fn try_from(new_xcm: NewXcm) -> result::Result { + Ok(Xcm(new_xcm.0.into_iter().map(TryInto::try_into).collect::>()?)) + } +} + +// Convert from a v5 instruction to a v4 instruction. +impl TryFrom> for Instruction { + type Error = (); + fn try_from(new_instruction: NewInstruction) -> result::Result { + use NewInstruction::*; + Ok(match new_instruction { + WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?), + ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?), + ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?), + QueryResponse { query_id, response, max_weight, querier: Some(querier) } => + Self::QueryResponse { + query_id, + querier: querier.try_into()?, + response: response.try_into()?, + max_weight, + }, + QueryResponse { query_id, response, max_weight, querier: None } => + Self::QueryResponse { + query_id, + querier: None, + response: response.try_into()?, + max_weight, + }, + TransferAsset { assets, beneficiary } => Self::TransferAsset { + assets: assets.try_into()?, + beneficiary: beneficiary.try_into()?, + }, + TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset { + assets: assets.try_into()?, + dest: dest.try_into()?, + xcm: xcm.try_into()?, + }, + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient }, + HrmpChannelClosing { initiator, sender, recipient } => + Self::HrmpChannelClosing { initiator, sender, recipient }, + Transact { origin_kind, mut call, fallback_max_weight } => { + // We first try to decode the call, if we can't, we use the fallback weight, + // if there's no fallback, we just return `Weight::MAX`. + let require_weight_at_most = match call.take_decoded() { + Ok(decoded) => decoded.get_dispatch_info().call_weight, + Err(error) => { + let fallback_weight = fallback_max_weight.unwrap_or(Weight::MAX); + log::debug!( + target: "xcm::versions::v5Tov4", + "Couldn't decode call in Transact: {:?}, using fallback weight: {:?}", + error, + fallback_weight, + ); + fallback_weight + }, + }; + Self::Transact { origin_kind, require_weight_at_most, call: call.into() } + }, + ReportError(response_info) => Self::ReportError(QueryResponseInfo { + query_id: response_info.query_id, + destination: response_info.destination.try_into().map_err(|_| ())?, + max_weight: response_info.max_weight, + }), + DepositAsset { assets, beneficiary } => { + let beneficiary = beneficiary.try_into()?; + let assets = assets.try_into()?; + Self::DepositAsset { assets, beneficiary } + }, + DepositReserveAsset { assets, dest, xcm } => { + let dest = dest.try_into()?; + let xcm = xcm.try_into()?; + let assets = assets.try_into()?; + Self::DepositReserveAsset { assets, dest, xcm } + }, + ExchangeAsset { give, want, maximal } => { + let give = give.try_into()?; + let want = want.try_into()?; + Self::ExchangeAsset { give, want, maximal } + }, + InitiateReserveWithdraw { assets, reserve, xcm } => { + // No `max_assets` here, so if there's a connt, then we cannot translate. + let assets = assets.try_into()?; + let reserve = reserve.try_into()?; + let xcm = xcm.try_into()?; + Self::InitiateReserveWithdraw { assets, reserve, xcm } + }, + InitiateTeleport { assets, dest, xcm } => { + // No `max_assets` here, so if there's a connt, then we cannot translate. + let assets = assets.try_into()?; + let dest = dest.try_into()?; + let xcm = xcm.try_into()?; + Self::InitiateTeleport { assets, dest, xcm } + }, + ReportHolding { response_info, assets } => { + let response_info = QueryResponseInfo { + destination: response_info.destination.try_into().map_err(|_| ())?, + query_id: response_info.query_id, + max_weight: response_info.max_weight, + }; + Self::ReportHolding { response_info, assets: assets.try_into()? } + }, + BuyExecution { fees, weight_limit } => { + let fees = fees.try_into()?; + let weight_limit = weight_limit.into(); + Self::BuyExecution { fees, weight_limit } + }, + ClearOrigin => Self::ClearOrigin, + DescendOrigin(who) => Self::DescendOrigin(who.try_into()?), + RefundSurplus => Self::RefundSurplus, + SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?), + SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?), + ClearError => Self::ClearError, + ClaimAsset { assets, ticket } => { + let assets = assets.try_into()?; + let ticket = ticket.try_into()?; + Self::ClaimAsset { assets, ticket } + }, + Trap(code) => Self::Trap(code), + SubscribeVersion { query_id, max_response_weight } => + Self::SubscribeVersion { query_id, max_response_weight }, + UnsubscribeVersion => Self::UnsubscribeVersion, + BurnAsset(assets) => Self::BurnAsset(assets.try_into()?), + ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?), + ExpectOrigin(maybe_origin) => + Self::ExpectOrigin(maybe_origin.map(|origin| origin.try_into()).transpose()?), + ExpectError(maybe_error) => Self::ExpectError( + maybe_error + .map(|(num, new_error)| (num, new_error.try_into())) + .map(|(num, result)| result.map(|inner| (num, inner))) + .transpose()?, + ), + ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code), + QueryPallet { module_name, response_info } => + Self::QueryPallet { module_name, response_info: response_info.try_into()? }, + ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => + Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }, + ReportTransactStatus(response_info) => + Self::ReportTransactStatus(response_info.try_into()?), + ClearTransactStatus => Self::ClearTransactStatus, + UniversalOrigin(junction) => Self::UniversalOrigin(junction.try_into()?), + ExportMessage { network, destination, xcm } => Self::ExportMessage { + network: network.into(), + destination: destination.try_into()?, + xcm: xcm.try_into()?, + }, + LockAsset { asset, unlocker } => + Self::LockAsset { asset: asset.try_into()?, unlocker: unlocker.try_into()? }, + UnlockAsset { asset, target } => + Self::UnlockAsset { asset: asset.try_into()?, target: target.try_into()? }, + NoteUnlockable { asset, owner } => + Self::NoteUnlockable { asset: asset.try_into()?, owner: owner.try_into()? }, + RequestUnlock { asset, locker } => + Self::RequestUnlock { asset: asset.try_into()?, locker: locker.try_into()? }, + SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw }, + SetTopic(topic) => Self::SetTopic(topic), + ClearTopic => Self::ClearTopic, + AliasOrigin(location) => Self::AliasOrigin(location.try_into()?), + UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution { + weight_limit, + check_origin: check_origin.map(|origin| origin.try_into()).transpose()?, + }, + InitiateTransfer { .. } | + PayFees { .. } | + SetHints { .. } | + ExecuteWithOrigin { .. } => { + log::debug!(target: "xcm::versions::v5tov4", "`{new_instruction:?}` not supported by v4"); + return Err(()); + }, + }) + } +} + // Convert from a v3 instruction to a v4 instruction impl TryFrom> for Instruction { type Error = (); diff --git a/polkadot/xcm/src/v4/traits.rs b/polkadot/xcm/src/v4/traits.rs index f32b26fb163d..178093d27177 100644 --- a/polkadot/xcm/src/v4/traits.rs +++ b/polkadot/xcm/src/v4/traits.rs @@ -289,13 +289,13 @@ impl SendXcm for Tuple { } /// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps -/// both in `Some` before passing them as as mutable references into `T::send_xcm`. +/// both in `Some` before passing them as mutable references into `T::send_xcm`. pub fn validate_send(dest: Location, msg: Xcm<()>) -> SendResult { T::validate(&mut Some(dest), &mut Some(msg)) } /// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps -/// both in `Some` before passing them as as mutable references into `T::send_xcm`. +/// both in `Some` before passing them as mutable references into `T::send_xcm`. /// /// Returns either `Ok` with the price of the delivery, or `Err` with the reason why the message /// could not be sent. diff --git a/polkadot/xcm/src/v5/asset.rs b/polkadot/xcm/src/v5/asset.rs new file mode 100644 index 000000000000..d0d9a7cedff0 --- /dev/null +++ b/polkadot/xcm/src/v5/asset.rs @@ -0,0 +1,1155 @@ +// 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 . + +//! Cross-Consensus Message format asset data structures. +//! +//! This encompasses four types for representing assets: +//! - `Asset`: A description of a single asset, either an instance of a non-fungible or some amount +//! of a fungible. +//! - `Assets`: A collection of `Asset`s. These are stored in a `Vec` and sorted with fungibles +//! first. +//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific +//! kind. +//! - `AssetFilter`: A combination of `Wild` and `Assets` designed for efficiently filtering an XCM +//! holding account. + +use super::{InteriorLocation, Location, Reanchorable}; +use crate::v4::{ + Asset as OldAsset, AssetFilter as OldAssetFilter, AssetId as OldAssetId, + AssetInstance as OldAssetInstance, Assets as OldAssets, Fungibility as OldFungibility, + WildAsset as OldWildAsset, WildFungibility as OldWildFungibility, +}; +use alloc::{vec, vec::Vec}; +use bounded_collections::{BoundedVec, ConstU32}; +use codec::{self as codec, Decode, Encode, MaxEncodedLen}; +use core::cmp::Ordering; +use scale_info::TypeInfo; + +/// A general identifier for an instance of a non-fungible asset class. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum AssetInstance { + /// Undefined - used if the non-fungible asset class has only one instance. + Undefined, + + /// A compact index. Technically this could be greater than `u128`, but this implementation + /// supports only values up to `2**128 - 1`. + Index(#[codec(compact)] u128), + + /// A 4-byte fixed-length datum. + Array4([u8; 4]), + + /// An 8-byte fixed-length datum. + Array8([u8; 8]), + + /// A 16-byte fixed-length datum. + Array16([u8; 16]), + + /// A 32-byte fixed-length datum. + Array32([u8; 32]), +} + +impl TryFrom for AssetInstance { + type Error = (); + fn try_from(value: OldAssetInstance) -> Result { + use OldAssetInstance::*; + Ok(match value { + Undefined => Self::Undefined, + Index(n) => Self::Index(n), + Array4(n) => Self::Array4(n), + Array8(n) => Self::Array8(n), + Array16(n) => Self::Array16(n), + Array32(n) => Self::Array32(n), + }) + } +} + +impl From<()> for AssetInstance { + fn from(_: ()) -> Self { + Self::Undefined + } +} + +impl From<[u8; 4]> for AssetInstance { + fn from(x: [u8; 4]) -> Self { + Self::Array4(x) + } +} + +impl From<[u8; 8]> for AssetInstance { + fn from(x: [u8; 8]) -> Self { + Self::Array8(x) + } +} + +impl From<[u8; 16]> for AssetInstance { + fn from(x: [u8; 16]) -> Self { + Self::Array16(x) + } +} + +impl From<[u8; 32]> for AssetInstance { + fn from(x: [u8; 32]) -> Self { + Self::Array32(x) + } +} + +impl From for AssetInstance { + fn from(x: u8) -> Self { + Self::Index(x as u128) + } +} + +impl From for AssetInstance { + fn from(x: u16) -> Self { + Self::Index(x as u128) + } +} + +impl From for AssetInstance { + fn from(x: u32) -> Self { + Self::Index(x as u128) + } +} + +impl From for AssetInstance { + fn from(x: u64) -> Self { + Self::Index(x as u128) + } +} + +impl TryFrom for () { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Undefined => Ok(()), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 4] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array4(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 8] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array8(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 16] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array16(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for [u8; 32] { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Array32(x) => Ok(x), + _ => Err(()), + } + } +} + +impl TryFrom for u8 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u16 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u32 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u64 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => x.try_into().map_err(|_| ()), + _ => Err(()), + } + } +} + +impl TryFrom for u128 { + type Error = (); + fn try_from(x: AssetInstance) -> Result { + match x { + AssetInstance::Index(x) => Ok(x), + _ => Err(()), + } + } +} + +/// Classification of whether an asset is fungible or not, along with a mandatory amount or +/// instance. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum Fungibility { + /// A fungible asset; we record a number of units, as a `u128` in the inner item. + Fungible(#[codec(compact)] u128), + /// A non-fungible asset. We record the instance identifier in the inner item. Only one asset + /// of each instance identifier may ever be in existence at once. + NonFungible(AssetInstance), +} + +#[derive(Decode)] +enum UncheckedFungibility { + Fungible(#[codec(compact)] u128), + NonFungible(AssetInstance), +} + +impl Decode for Fungibility { + fn decode(input: &mut I) -> Result { + match UncheckedFungibility::decode(input)? { + UncheckedFungibility::Fungible(a) if a != 0 => Ok(Self::Fungible(a)), + UncheckedFungibility::NonFungible(i) => Ok(Self::NonFungible(i)), + UncheckedFungibility::Fungible(_) => + Err("Fungible asset of zero amount is not allowed".into()), + } + } +} + +impl Fungibility { + pub fn is_kind(&self, w: WildFungibility) -> bool { + use Fungibility::*; + use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}; + matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible)) + } +} + +impl From for Fungibility { + fn from(amount: i32) -> Fungibility { + debug_assert_ne!(amount, 0); + Fungibility::Fungible(amount as u128) + } +} + +impl From for Fungibility { + fn from(amount: u128) -> Fungibility { + debug_assert_ne!(amount, 0); + Fungibility::Fungible(amount) + } +} + +impl> From for Fungibility { + fn from(instance: T) -> Fungibility { + Fungibility::NonFungible(instance.into()) + } +} + +impl TryFrom for Fungibility { + type Error = (); + fn try_from(value: OldFungibility) -> Result { + use OldFungibility::*; + Ok(match value { + Fungible(n) => Self::Fungible(n), + NonFungible(i) => Self::NonFungible(i.try_into()?), + }) + } +} + +/// Classification of whether an asset is fungible or not. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum WildFungibility { + /// The asset is fungible. + Fungible, + /// The asset is not fungible. + NonFungible, +} + +impl TryFrom for WildFungibility { + type Error = (); + fn try_from(value: OldWildFungibility) -> Result { + use OldWildFungibility::*; + Ok(match value { + Fungible => Self::Fungible, + NonFungible => Self::NonFungible, + }) + } +} + +/// Location to identify an asset. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub struct AssetId(pub Location); + +impl> From for AssetId { + fn from(x: T) -> Self { + Self(x.into()) + } +} + +impl TryFrom for AssetId { + type Error = (); + fn try_from(old: OldAssetId) -> Result { + Ok(Self(old.0.try_into()?)) + } +} + +impl AssetId { + /// Prepend a `Location` to an asset id, giving it a new root location. + pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> { + self.0.prepend_with(prepend.clone()).map_err(|_| ())?; + Ok(()) + } + + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding + /// `Asset` value. + pub fn into_asset(self, fun: Fungibility) -> Asset { + Asset { fun, id: self } + } + + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding + /// `WildAsset` wildcard (`AllOf`) value. + pub fn into_wild(self, fun: WildFungibility) -> WildAsset { + WildAsset::AllOf { fun, id: self } + } +} + +impl Reanchorable for AssetId { + type Error = (); + + /// Mutate the asset to represent the same value from the perspective of a new `target` + /// location. The local chain's location is provided in `context`. + fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> { + self.0.reanchor(target, context)?; + Ok(()) + } + + fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result { + match self.reanchor(target, context) { + Ok(()) => Ok(self), + Err(()) => Err(()), + } + } +} + +/// Either an amount of a single fungible asset, or a single well-identified non-fungible asset. +#[derive( + Clone, + Eq, + PartialEq, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub struct Asset { + /// The overall asset identity (aka *class*, in the case of a non-fungible). + pub id: AssetId, + /// The fungibility of the asset, which contains either the amount (in the case of a fungible + /// asset) or the *instance ID*, the secondary asset identifier. + pub fun: Fungibility, +} + +impl PartialOrd for Asset { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Asset { + fn cmp(&self, other: &Self) -> Ordering { + match (&self.fun, &other.fun) { + (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less, + (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater, + _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)), + } + } +} + +impl, B: Into> From<(A, B)> for Asset { + fn from((id, fun): (A, B)) -> Asset { + Asset { fun: fun.into(), id: id.into() } + } +} + +impl Asset { + pub fn is_fungible(&self, maybe_id: Option) -> bool { + use Fungibility::*; + matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id) + } + + pub fn is_non_fungible(&self, maybe_id: Option) -> bool { + use Fungibility::*; + matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id) + } + + /// Prepend a `Location` to a concrete asset, giving it a new root location. + pub fn prepend_with(&mut self, prepend: &Location) -> Result<(), ()> { + self.id.prepend_with(prepend) + } + + /// Returns true if `self` is a super-set of the given `inner` asset. + pub fn contains(&self, inner: &Asset) -> bool { + use Fungibility::*; + if self.id == inner.id { + match (&self.fun, &inner.fun) { + (Fungible(a), Fungible(i)) if a >= i => return true, + (NonFungible(a), NonFungible(i)) if a == i => return true, + _ => (), + } + } + false + } +} + +impl Reanchorable for Asset { + type Error = (); + + /// Mutate the location of the asset identifier if concrete, giving it the same location + /// relative to a `target` context. The local context is provided as `context`. + fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> { + self.id.reanchor(target, context) + } + + /// Mutate the location of the asset identifier if concrete, giving it the same location + /// relative to a `target` context. The local context is provided as `context`. + fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result { + self.id.reanchor(target, context)?; + Ok(self) + } +} + +impl TryFrom for Asset { + type Error = (); + fn try_from(old: OldAsset) -> Result { + Ok(Self { id: old.id.try_into()?, fun: old.fun.try_into()? }) + } +} + +/// A `Vec` of `Asset`s. +/// +/// There are a number of invariants which the construction and mutation functions must ensure are +/// maintained: +/// - It may contain no items of duplicate asset class; +/// - All items must be ordered; +/// - The number of items should grow no larger than `MAX_ITEMS_IN_ASSETS`. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + TypeInfo, + Default, + serde::Serialize, + serde::Deserialize, +)] +pub struct Assets(Vec); + +/// Maximum number of items we expect in a single `Assets` value. Note this is not (yet) +/// enforced, and just serves to provide a sensible `max_encoded_len` for `Assets`. +pub const MAX_ITEMS_IN_ASSETS: usize = 20; + +impl MaxEncodedLen for Assets { + fn max_encoded_len() -> usize { + Asset::max_encoded_len() * MAX_ITEMS_IN_ASSETS + } +} + +impl Decode for Assets { + fn decode(input: &mut I) -> Result { + let bounded_instructions = + BoundedVec::>::decode(input)?; + Self::from_sorted_and_deduplicated(bounded_instructions.into_inner()) + .map_err(|()| "Out of order".into()) + } +} + +impl TryFrom for Assets { + type Error = (); + fn try_from(old: OldAssets) -> Result { + let v = old + .into_inner() + .into_iter() + .map(Asset::try_from) + .collect::, ()>>()?; + Ok(Assets(v)) + } +} + +impl From> for Assets { + fn from(mut assets: Vec) -> Self { + let mut res = Vec::with_capacity(assets.len()); + if !assets.is_empty() { + assets.sort(); + let mut iter = assets.into_iter(); + if let Some(first) = iter.next() { + let last = iter.fold(first, |a, b| -> Asset { + match (a, b) { + ( + Asset { fun: Fungibility::Fungible(a_amount), id: a_id }, + Asset { fun: Fungibility::Fungible(b_amount), id: b_id }, + ) if a_id == b_id => Asset { + id: a_id, + fun: Fungibility::Fungible(a_amount.saturating_add(b_amount)), + }, + ( + Asset { fun: Fungibility::NonFungible(a_instance), id: a_id }, + Asset { fun: Fungibility::NonFungible(b_instance), id: b_id }, + ) if a_id == b_id && a_instance == b_instance => + Asset { fun: Fungibility::NonFungible(a_instance), id: a_id }, + (to_push, to_remember) => { + res.push(to_push); + to_remember + }, + } + }); + res.push(last); + } + } + Self(res) + } +} + +impl> From for Assets { + fn from(x: T) -> Self { + Self(vec![x.into()]) + } +} + +impl Assets { + /// A new (empty) value. + pub fn new() -> Self { + Self(Vec::new()) + } + + /// Create a new instance of `Assets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. + /// + /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. + /// If you can't guarantee that `r` is sorted and deduplicated, then use + /// `From::>::from` which is infallible. + pub fn from_sorted_and_deduplicated(r: Vec) -> Result { + if r.is_empty() { + return Ok(Self(Vec::new())) + } + r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&Asset, ()> { + if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { + Ok(b) + } else { + Err(()) + } + })?; + Ok(Self(r)) + } + + /// Create a new instance of `Assets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. + /// + /// In release mode, this skips any checks to ensure that `r` is correct, making it a + /// negligible-cost operation. Generally though you should avoid using it unless you have a + /// strict proof that `r` is valid. + #[cfg(test)] + pub fn from_sorted_and_deduplicated_skip_checks(r: Vec) -> Self { + Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped") + } + /// Create a new instance of `Assets` from a `Vec` whose contents are sorted + /// and which contain no duplicates. + /// + /// In release mode, this skips any checks to ensure that `r` is correct, making it a + /// negligible-cost operation. Generally though you should avoid using it unless you have a + /// strict proof that `r` is valid. + /// + /// In test mode, this checks anyway and panics on fail. + #[cfg(not(test))] + pub fn from_sorted_and_deduplicated_skip_checks(r: Vec) -> Self { + Self(r) + } + + /// Add some asset onto the list, saturating. This is quite a laborious operation since it + /// maintains the ordering. + pub fn push(&mut self, a: Asset) { + for asset in self.0.iter_mut().filter(|x| x.id == a.id) { + match (&a.fun, &mut asset.fun) { + (Fungibility::Fungible(amount), Fungibility::Fungible(balance)) => { + *balance = balance.saturating_add(*amount); + return + }, + (Fungibility::NonFungible(inst1), Fungibility::NonFungible(inst2)) + if inst1 == inst2 => + return, + _ => (), + } + } + self.0.push(a); + self.0.sort(); + } + + /// Returns `true` if this definitely represents no asset. + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + + /// Returns true if `self` is a super-set of the given `inner` asset. + pub fn contains(&self, inner: &Asset) -> bool { + self.0.iter().any(|i| i.contains(inner)) + } + + /// Consume `self` and return the inner vec. + #[deprecated = "Use `into_inner()` instead"] + pub fn drain(self) -> Vec { + self.0 + } + + /// Consume `self` and return the inner vec. + pub fn into_inner(self) -> Vec { + self.0 + } + + /// Return a reference to the inner vec. + pub fn inner(&self) -> &Vec { + &self.0 + } + + /// Return the number of distinct asset instances contained. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Prepend a `Location` to any concrete asset items, giving it a new root location. + pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> { + self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?; + self.0.sort(); + Ok(()) + } + + /// Return a reference to an item at a specific index or `None` if it doesn't exist. + pub fn get(&self, index: usize) -> Option<&Asset> { + self.0.get(index) + } +} + +impl Reanchorable for Assets { + type Error = (); + + fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> { + self.0.iter_mut().try_for_each(|i| i.reanchor(target, context))?; + self.0.sort(); + Ok(()) + } + + fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result { + match self.reanchor(target, context) { + Ok(()) => Ok(self), + Err(()) => Err(()), + } + } +} + +/// A wildcard representing a set of assets. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum WildAsset { + /// All assets in Holding. + All, + /// All assets in Holding of a given fungibility and ID. + AllOf { id: AssetId, fun: WildFungibility }, + /// All assets in Holding, up to `u32` individual assets (different instances of non-fungibles + /// are separate assets). + AllCounted(#[codec(compact)] u32), + /// All assets in Holding of a given fungibility and ID up to `count` individual assets + /// (different instances of non-fungibles are separate assets). + AllOfCounted { + id: AssetId, + fun: WildFungibility, + #[codec(compact)] + count: u32, + }, +} + +impl TryFrom for WildAsset { + type Error = (); + fn try_from(old: OldWildAsset) -> Result { + use OldWildAsset::*; + Ok(match old { + AllOf { id, fun } => Self::AllOf { id: id.try_into()?, fun: fun.try_into()? }, + All => Self::All, + AllOfCounted { id, fun, count } => + Self::AllOfCounted { id: id.try_into()?, fun: fun.try_into()?, count }, + AllCounted(count) => Self::AllCounted(count), + }) + } +} + +impl WildAsset { + /// Returns true if `self` is a super-set of the given `inner` asset. + pub fn contains(&self, inner: &Asset) -> bool { + use WildAsset::*; + match self { + AllOfCounted { count: 0, .. } | AllCounted(0) => false, + AllOf { fun, id } | AllOfCounted { id, fun, .. } => + inner.fun.is_kind(*fun) && &inner.id == id, + All | AllCounted(_) => true, + } + } + + /// Returns true if the wild element of `self` matches `inner`. + /// + /// Note that for `Counted` variants of wildcards, then it will disregard the count except for + /// always returning `false` when equal to 0. + #[deprecated = "Use `contains` instead"] + pub fn matches(&self, inner: &Asset) -> bool { + self.contains(inner) + } + + /// Mutate the asset to represent the same value from the perspective of a new `target` + /// location. The local chain's location is provided in `context`. + pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> { + use WildAsset::*; + match self { + AllOf { ref mut id, .. } | AllOfCounted { ref mut id, .. } => + id.reanchor(target, context), + All | AllCounted(_) => Ok(()), + } + } + + /// Maximum count of assets allowed to match, if any. + pub fn count(&self) -> Option { + use WildAsset::*; + match self { + AllOfCounted { count, .. } | AllCounted(count) => Some(*count), + All | AllOf { .. } => None, + } + } + + /// Explicit limit on number of assets allowed to match, if any. + pub fn limit(&self) -> Option { + self.count() + } + + /// Consume self and return the equivalent version but counted and with the `count` set to the + /// given parameter. + pub fn counted(self, count: u32) -> Self { + use WildAsset::*; + match self { + AllOfCounted { fun, id, .. } | AllOf { fun, id } => AllOfCounted { fun, id, count }, + All | AllCounted(_) => AllCounted(count), + } + } +} + +impl, B: Into> From<(A, B)> for WildAsset { + fn from((id, fun): (A, B)) -> WildAsset { + WildAsset::AllOf { fun: fun.into(), id: id.into() } + } +} + +/// `Asset` collection, defined either by a number of `Assets` or a single wildcard. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum AssetFilter { + /// Specify the filter as being everything contained by the given `Assets` inner. + Definite(Assets), + /// Specify the filter as the given `WildAsset` wildcard. + Wild(WildAsset), +} + +impl> From for AssetFilter { + fn from(x: T) -> Self { + Self::Wild(x.into()) + } +} + +impl From for AssetFilter { + fn from(x: Asset) -> Self { + Self::Definite(vec![x].into()) + } +} + +impl From> for AssetFilter { + fn from(x: Vec) -> Self { + Self::Definite(x.into()) + } +} + +impl From for AssetFilter { + fn from(x: Assets) -> Self { + Self::Definite(x) + } +} + +impl AssetFilter { + /// Returns true if `inner` would be matched by `self`. + /// + /// Note that for `Counted` variants of wildcards, then it will disregard the count except for + /// always returning `false` when equal to 0. + pub fn matches(&self, inner: &Asset) -> bool { + match self { + AssetFilter::Definite(ref assets) => assets.contains(inner), + AssetFilter::Wild(ref wild) => wild.contains(inner), + } + } + + /// Mutate the location of the asset identifier if concrete, giving it the same location + /// relative to a `target` context. The local context is provided as `context`. + pub fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> { + match self { + AssetFilter::Definite(ref mut assets) => assets.reanchor(target, context), + AssetFilter::Wild(ref mut wild) => wild.reanchor(target, context), + } + } + + /// Maximum count of assets it is possible to match, if known. + pub fn count(&self) -> Option { + use AssetFilter::*; + match self { + Definite(x) => Some(x.len() as u32), + Wild(x) => x.count(), + } + } + + /// Explicit limit placed on the number of items, if any. + pub fn limit(&self) -> Option { + use AssetFilter::*; + match self { + Definite(_) => None, + Wild(x) => x.limit(), + } + } +} + +impl TryFrom for AssetFilter { + type Error = (); + fn try_from(old: OldAssetFilter) -> Result { + Ok(match old { + OldAssetFilter::Definite(x) => Self::Definite(x.try_into()?), + OldAssetFilter::Wild(x) => Self::Wild(x.try_into()?), + }) + } +} + +/// Matches assets based on inner `AssetFilter` and tags them for a specific type of asset transfer. +/// Please note: the transfer type is specific to each particular `(asset, source, dest)` +/// combination, so it should always be built in the context of `source` after knowing `dest`. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum AssetTransferFilter { + /// teleport assets matching `AssetFilter` to a specific destination + Teleport(AssetFilter), + /// reserve-transfer assets matching `AssetFilter` to a specific destination, using the local + /// chain as reserve + ReserveDeposit(AssetFilter), + /// reserve-transfer assets matching `AssetFilter` to a specific destination, using the + /// destination as reserve + ReserveWithdraw(AssetFilter), +} + +impl AssetTransferFilter { + /// Returns reference to inner `AssetFilter` ignoring the transfer type. + pub fn inner(&self) -> &AssetFilter { + match self { + AssetTransferFilter::Teleport(inner) => inner, + AssetTransferFilter::ReserveDeposit(inner) => inner, + AssetTransferFilter::ReserveWithdraw(inner) => inner, + } + } +} + +#[cfg(test)] +mod tests { + use super::super::prelude::*; + + #[test] + fn conversion_works() { + let _: Assets = (Here, 1u128).into(); + } + + #[test] + fn from_sorted_and_deduplicated_works() { + use super::*; + use alloc::vec; + + let empty = vec![]; + let r = Assets::from_sorted_and_deduplicated(empty); + assert_eq!(r, Ok(Assets(vec![]))); + + let dup_fun = vec![(Here, 100).into(), (Here, 10).into()]; + let r = Assets::from_sorted_and_deduplicated(dup_fun); + assert!(r.is_err()); + + let dup_nft = vec![(Here, *b"notgood!").into(), (Here, *b"notgood!").into()]; + let r = Assets::from_sorted_and_deduplicated(dup_nft); + assert!(r.is_err()); + + let good_fun = vec![(Here, 10).into(), (Parent, 10).into()]; + let r = Assets::from_sorted_and_deduplicated(good_fun.clone()); + assert_eq!(r, Ok(Assets(good_fun))); + + let bad_fun = vec![(Parent, 10).into(), (Here, 10).into()]; + let r = Assets::from_sorted_and_deduplicated(bad_fun); + assert!(r.is_err()); + + let good_nft = vec![(Here, ()).into(), (Here, *b"good").into()]; + let r = Assets::from_sorted_and_deduplicated(good_nft.clone()); + assert_eq!(r, Ok(Assets(good_nft))); + + let bad_nft = vec![(Here, *b"bad!").into(), (Here, ()).into()]; + let r = Assets::from_sorted_and_deduplicated(bad_nft); + assert!(r.is_err()); + + let mixed_good = vec![(Here, 10).into(), (Here, *b"good").into()]; + let r = Assets::from_sorted_and_deduplicated(mixed_good.clone()); + assert_eq!(r, Ok(Assets(mixed_good))); + + let mixed_bad = vec![(Here, *b"bad!").into(), (Here, 10).into()]; + let r = Assets::from_sorted_and_deduplicated(mixed_bad); + assert!(r.is_err()); + } + + #[test] + fn reanchor_preserves_sorting() { + use super::*; + use alloc::vec; + + let reanchor_context: Junctions = Parachain(2000).into(); + let dest = Location::new(1, []); + + let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_1_reanchored = asset_1.clone(); + assert!(asset_1_reanchored.reanchor(&dest, &reanchor_context).is_ok()); + assert_eq!( + asset_1_reanchored, + (Location::new(0, [Parachain(2000), PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + let asset_2: Asset = (Location::new(1, []), 10).into(); + let mut asset_2_reanchored = asset_2.clone(); + assert!(asset_2_reanchored.reanchor(&dest, &reanchor_context).is_ok()); + assert_eq!(asset_2_reanchored, (Location::new(0, []), 10).into()); + + let asset_3: Asset = (Location::new(1, [Parachain(1000)]), 10).into(); + let mut asset_3_reanchored = asset_3.clone(); + assert!(asset_3_reanchored.reanchor(&dest, &reanchor_context).is_ok()); + assert_eq!(asset_3_reanchored, (Location::new(0, [Parachain(1000)]), 10).into()); + + let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into(); + assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into()); + + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + + assert!(assets.reanchor(&dest, &reanchor_context).is_ok()); + assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]); + + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + } + + #[test] + fn prepend_preserves_sorting() { + use super::*; + use alloc::vec; + + let prefix = Location::new(0, [Parachain(1000)]); + + let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_1_prepended = asset_1.clone(); + assert!(asset_1_prepended.prepend_with(&prefix).is_ok()); + // changes interior X2->X3 + assert_eq!( + asset_1_prepended, + (Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_2_prepended = asset_2.clone(); + assert!(asset_2_prepended.prepend_with(&prefix).is_ok()); + // changes parent + assert_eq!( + asset_2_prepended, + (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_3_prepended = asset_3.clone(); + assert!(asset_3_prepended.prepend_with(&prefix).is_ok()); + // changes parent + assert_eq!( + asset_3_prepended, + (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + // `From` impl does sorting. + let mut assets: Assets = vec![asset_1, asset_2, asset_3].into(); + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + + // let's do `prepend_with` + assert!(assets.prepend_with(&prefix).is_ok()); + assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]); + + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + } + + #[test] + fn decoding_respects_limit() { + use super::*; + + // Having lots of one asset will work since they are deduplicated + let lots_of_one_asset: Assets = + vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_ASSETS + 1].into(); + let encoded = lots_of_one_asset.encode(); + assert!(Assets::decode(&mut &encoded[..]).is_ok()); + + // Fewer assets than the limit works + let mut few_assets: Assets = Vec::new().into(); + for i in 0..MAX_ITEMS_IN_ASSETS { + few_assets.push((GeneralIndex(i as u128), 1u128).into()); + } + let encoded = few_assets.encode(); + assert!(Assets::decode(&mut &encoded[..]).is_ok()); + + // Having lots of different assets will not work + let mut too_many_different_assets: Assets = Vec::new().into(); + for i in 0..MAX_ITEMS_IN_ASSETS + 1 { + too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into()); + } + let encoded = too_many_different_assets.encode(); + assert!(Assets::decode(&mut &encoded[..]).is_err()); + } +} diff --git a/polkadot/xcm/src/v5/junction.rs b/polkadot/xcm/src/v5/junction.rs new file mode 100644 index 000000000000..d86a762fcf44 --- /dev/null +++ b/polkadot/xcm/src/v5/junction.rs @@ -0,0 +1,325 @@ +// 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 . + +//! Support data structures for `Location`, primarily the `Junction` datatype. + +use super::Location; +pub use crate::v4::{BodyId, BodyPart}; +use crate::{ + v4::{Junction as OldJunction, NetworkId as OldNetworkId}, + VersionedLocation, +}; +use bounded_collections::{BoundedSlice, BoundedVec, ConstU32}; +use codec::{self, Decode, Encode, MaxEncodedLen}; +use hex_literal::hex; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; + +/// A single item in a path to describe the relative location of a consensus system. +/// +/// Each item assumes a pre-existing location as its context and is defined in terms of it. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub enum Junction { + /// An indexed parachain belonging to and operated by the context. + /// + /// Generally used when the context is a Polkadot Relay-chain. + Parachain(#[codec(compact)] u32), + /// A 32-byte identifier for an account of a specific network that is respected as a sovereign + /// endpoint within the context. + /// + /// Generally used when the context is a Substrate-based chain. + AccountId32 { network: Option, id: [u8; 32] }, + /// An 8-byte index for an account of a specific network that is respected as a sovereign + /// endpoint within the context. + /// + /// May be used when the context is a Frame-based chain and includes e.g. an indices pallet. + AccountIndex64 { + network: Option, + #[codec(compact)] + index: u64, + }, + /// A 20-byte identifier for an account of a specific network that is respected as a sovereign + /// endpoint within the context. + /// + /// May be used when the context is an Ethereum or Bitcoin chain or smart-contract. + AccountKey20 { network: Option, key: [u8; 20] }, + /// An instanced, indexed pallet that forms a constituent part of the context. + /// + /// Generally used when the context is a Frame-based chain. + PalletInstance(u8), + /// A non-descript index within the context location. + /// + /// Usage will vary widely owing to its generality. + /// + /// NOTE: Try to avoid using this and instead use a more specific item. + GeneralIndex(#[codec(compact)] u128), + /// A nondescript array datum, 32 bytes, acting as a key within the context + /// location. + /// + /// Usage will vary widely owing to its generality. + /// + /// NOTE: Try to avoid using this and instead use a more specific item. + // Note this is implemented as an array with a length rather than using `BoundedVec` owing to + // the bound for `Copy`. + GeneralKey { length: u8, data: [u8; 32] }, + /// The unambiguous child. + /// + /// Not currently used except as a fallback when deriving context. + OnlyChild, + /// A pluralistic body existing within consensus. + /// + /// Typical to be used to represent a governance origin of a chain, but could in principle be + /// used to represent things such as multisigs also. + Plurality { id: BodyId, part: BodyPart }, + /// A global network capable of externalizing its own consensus. This is not generally + /// meaningful outside of the universal level. + GlobalConsensus(NetworkId), +} + +/// The genesis hash of the Westend testnet. Used to identify it. +pub const WESTEND_GENESIS_HASH: [u8; 32] = + hex!["e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e"]; + +/// The genesis hash of the Rococo testnet. Used to identify it. +pub const ROCOCO_GENESIS_HASH: [u8; 32] = + hex!["6408de7737c59c238890533af25896a2c20608d8b380bb01029acb392781063e"]; + +/// Dummy genesis hash used instead of defunct networks like Wococo (and soon Rococo). +pub const DUMMY_GENESIS_HASH: [u8; 32] = [0; 32]; + +/// A global identifier of a data structure existing within consensus. +/// +/// Maintenance note: Networks with global consensus and which are practically bridgeable within the +/// Polkadot ecosystem are given preference over explicit naming in this enumeration. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub enum NetworkId { + /// Network specified by the first 32 bytes of its genesis block. + ByGenesis([u8; 32]), + /// Network defined by the first 32-bytes of the hash and number of some block it contains. + ByFork { block_number: u64, block_hash: [u8; 32] }, + /// The Polkadot mainnet Relay-chain. + Polkadot, + /// The Kusama canary-net Relay-chain. + Kusama, + /// An Ethereum network specified by its chain ID. + #[codec(index = 7)] + Ethereum { + /// The EIP-155 chain ID. + #[codec(compact)] + chain_id: u64, + }, + /// The Bitcoin network, including hard-forks supported by Bitcoin Core development team. + #[codec(index = 8)] + BitcoinCore, + /// The Bitcoin network, including hard-forks supported by Bitcoin Cash developers. + #[codec(index = 9)] + BitcoinCash, + /// The Polkadot Bulletin chain. + #[codec(index = 10)] + PolkadotBulletin, +} + +impl From for Option { + fn from(old: OldNetworkId) -> Self { + Some(NetworkId::from(old)) + } +} + +impl From for NetworkId { + fn from(old: OldNetworkId) -> Self { + use OldNetworkId::*; + match old { + ByGenesis(hash) => Self::ByGenesis(hash), + ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash }, + Polkadot => Self::Polkadot, + Kusama => Self::Kusama, + Westend => Self::ByGenesis(WESTEND_GENESIS_HASH), + Rococo => Self::ByGenesis(ROCOCO_GENESIS_HASH), + Wococo => Self::ByGenesis(DUMMY_GENESIS_HASH), + Ethereum { chain_id } => Self::Ethereum { chain_id }, + BitcoinCore => Self::BitcoinCore, + BitcoinCash => Self::BitcoinCash, + PolkadotBulletin => Self::PolkadotBulletin, + } + } +} + +impl From for Junction { + fn from(n: NetworkId) -> Self { + Self::GlobalConsensus(n) + } +} + +impl From<[u8; 32]> for Junction { + fn from(id: [u8; 32]) -> Self { + Self::AccountId32 { network: None, id } + } +} + +impl From>> for Junction { + fn from(key: BoundedVec>) -> Self { + key.as_bounded_slice().into() + } +} + +impl<'a> From>> for Junction { + fn from(key: BoundedSlice<'a, u8, ConstU32<32>>) -> Self { + let mut data = [0u8; 32]; + data[..key.len()].copy_from_slice(&key[..]); + Self::GeneralKey { length: key.len() as u8, data } + } +} + +impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> { + type Error = (); + fn try_from(key: &'a Junction) -> Result { + match key { + Junction::GeneralKey { length, data } => + BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()), + _ => Err(()), + } + } +} + +impl From<[u8; 20]> for Junction { + fn from(key: [u8; 20]) -> Self { + Self::AccountKey20 { network: None, key } + } +} + +impl From for Junction { + fn from(index: u64) -> Self { + Self::AccountIndex64 { network: None, index } + } +} + +impl From for Junction { + fn from(id: u128) -> Self { + Self::GeneralIndex(id) + } +} + +impl TryFrom for Junction { + type Error = (); + fn try_from(value: OldJunction) -> Result { + use OldJunction::*; + Ok(match value { + Parachain(id) => Self::Parachain(id), + AccountId32 { network: maybe_network, id } => + Self::AccountId32 { network: maybe_network.map(|network| network.into()), id }, + AccountIndex64 { network: maybe_network, index } => + Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index }, + AccountKey20 { network: maybe_network, key } => + Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key }, + PalletInstance(index) => Self::PalletInstance(index), + GeneralIndex(id) => Self::GeneralIndex(id), + GeneralKey { length, data } => Self::GeneralKey { length, data }, + OnlyChild => Self::OnlyChild, + Plurality { id, part } => Self::Plurality { id, part }, + GlobalConsensus(network) => Self::GlobalConsensus(network.into()), + }) + } +} + +impl Junction { + /// Convert `self` into a `Location` containing 0 parents. + /// + /// Similar to `Into::into`, except that this method can be used in a const evaluation context. + pub fn into_location(self) -> Location { + Location::new(0, [self]) + } + + /// Convert `self` into a `Location` containing `n` parents. + /// + /// Similar to `Self::into_location`, with the added ability to specify the number of parent + /// junctions. + pub fn into_exterior(self, n: u8) -> Location { + Location::new(n, [self]) + } + + /// Convert `self` into a `VersionedLocation` containing 0 parents. + /// + /// Similar to `Into::into`, except that this method can be used in a const evaluation context. + pub fn into_versioned(self) -> VersionedLocation { + self.into_location().into_versioned() + } + + /// Remove the `NetworkId` value. + pub fn remove_network_id(&mut self) { + use Junction::*; + match self { + AccountId32 { ref mut network, .. } | + AccountIndex64 { ref mut network, .. } | + AccountKey20 { ref mut network, .. } => *network = None, + _ => {}, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn junction_round_trip_works() { + let j = Junction::GeneralKey { length: 32, data: [1u8; 32] }; + let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap(); + assert_eq!(j, k); + + let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] }; + let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap(); + assert_eq!(j, k); + + let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap()); + let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap(); + assert_eq!(j, k); + let s: BoundedSlice<_, _> = (&k).try_into().unwrap(); + assert_eq!(s, &[1u8, 2, 3, 4][..]); + + let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] }; + let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap(); + assert_eq!(j, k); + } +} diff --git a/polkadot/xcm/src/v5/junctions.rs b/polkadot/xcm/src/v5/junctions.rs new file mode 100644 index 000000000000..dc93c541d19d --- /dev/null +++ b/polkadot/xcm/src/v5/junctions.rs @@ -0,0 +1,723 @@ +// 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 . + +//! XCM `Junctions`/`InteriorLocation` datatype. + +use super::{Junction, Location, NetworkId}; +use alloc::sync::Arc; +use codec::{Decode, Encode, MaxEncodedLen}; +use core::{mem, ops::Range, result}; +use scale_info::TypeInfo; + +/// Maximum number of `Junction`s that a `Junctions` can contain. +pub(crate) const MAX_JUNCTIONS: usize = 8; + +/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions` +/// implementation uses a Rust `enum` in order to make pattern matching easier. +/// +/// Parent junctions cannot be constructed with this type. Refer to `Location` for +/// instructions on constructing parent junctions. +#[derive( + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub enum Junctions { + /// The interpreting consensus system. + Here, + /// A relative path comprising 1 junction. + X1(Arc<[Junction; 1]>), + /// A relative path comprising 2 junctions. + X2(Arc<[Junction; 2]>), + /// A relative path comprising 3 junctions. + X3(Arc<[Junction; 3]>), + /// A relative path comprising 4 junctions. + X4(Arc<[Junction; 4]>), + /// A relative path comprising 5 junctions. + X5(Arc<[Junction; 5]>), + /// A relative path comprising 6 junctions. + X6(Arc<[Junction; 6]>), + /// A relative path comprising 7 junctions. + X7(Arc<[Junction; 7]>), + /// A relative path comprising 8 junctions. + X8(Arc<[Junction; 8]>), +} + +macro_rules! impl_junctions { + ($count:expr, $variant:ident) => { + impl From<[Junction; $count]> for Junctions { + fn from(junctions: [Junction; $count]) -> Self { + Self::$variant(Arc::new(junctions)) + } + } + impl PartialEq<[Junction; $count]> for Junctions { + fn eq(&self, rhs: &[Junction; $count]) -> bool { + self.as_slice() == rhs + } + } + }; +} + +impl_junctions!(1, X1); +impl_junctions!(2, X2); +impl_junctions!(3, X3); +impl_junctions!(4, X4); +impl_junctions!(5, X5); +impl_junctions!(6, X6); +impl_junctions!(7, X7); +impl_junctions!(8, X8); + +pub struct JunctionsIterator { + junctions: Junctions, + range: Range, +} + +impl Iterator for JunctionsIterator { + type Item = Junction; + fn next(&mut self) -> Option { + self.junctions.at(self.range.next()?).cloned() + } +} + +impl DoubleEndedIterator for JunctionsIterator { + fn next_back(&mut self) -> Option { + self.junctions.at(self.range.next_back()?).cloned() + } +} + +pub struct JunctionsRefIterator<'a> { + junctions: &'a Junctions, + range: Range, +} + +impl<'a> Iterator for JunctionsRefIterator<'a> { + type Item = &'a Junction; + fn next(&mut self) -> Option<&'a Junction> { + self.junctions.at(self.range.next()?) + } +} + +impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> { + fn next_back(&mut self) -> Option<&'a Junction> { + self.junctions.at(self.range.next_back()?) + } +} +impl<'a> IntoIterator for &'a Junctions { + type Item = &'a Junction; + type IntoIter = JunctionsRefIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + JunctionsRefIterator { junctions: self, range: 0..self.len() } + } +} + +impl IntoIterator for Junctions { + type Item = Junction; + type IntoIter = JunctionsIterator; + fn into_iter(self) -> Self::IntoIter { + JunctionsIterator { range: 0..self.len(), junctions: self } + } +} + +impl Junctions { + /// Convert `self` into a `Location` containing 0 parents. + /// + /// Similar to `Into::into`, except that this method can be used in a const evaluation context. + pub const fn into_location(self) -> Location { + Location { parents: 0, interior: self } + } + + /// Convert `self` into a `Location` containing `n` parents. + /// + /// Similar to `Self::into_location`, with the added ability to specify the number of parent + /// junctions. + pub const fn into_exterior(self, n: u8) -> Location { + Location { parents: n, interior: self } + } + + /// Casts `self` into a slice containing `Junction`s. + pub fn as_slice(&self) -> &[Junction] { + match self { + Junctions::Here => &[], + Junctions::X1(ref a) => &a[..], + Junctions::X2(ref a) => &a[..], + Junctions::X3(ref a) => &a[..], + Junctions::X4(ref a) => &a[..], + Junctions::X5(ref a) => &a[..], + Junctions::X6(ref a) => &a[..], + Junctions::X7(ref a) => &a[..], + Junctions::X8(ref a) => &a[..], + } + } + + /// Casts `self` into a mutable slice containing `Junction`s. + pub fn as_slice_mut(&mut self) -> &mut [Junction] { + match self { + Junctions::Here => &mut [], + Junctions::X1(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X2(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X3(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X4(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X5(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X6(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X7(ref mut a) => &mut Arc::make_mut(a)[..], + Junctions::X8(ref mut a) => &mut Arc::make_mut(a)[..], + } + } + + /// Remove the `NetworkId` value in any `Junction`s. + pub fn remove_network_id(&mut self) { + self.for_each_mut(Junction::remove_network_id); + } + + /// Treating `self` as the universal context, return the location of the local consensus system + /// from the point of view of the given `target`. + pub fn invert_target(&self, target: &Location) -> Result { + let mut itself = self.clone(); + let mut junctions = Self::Here; + for _ in 0..target.parent_count() { + junctions = junctions + .pushed_front_with(itself.take_last().unwrap_or(Junction::OnlyChild)) + .map_err(|_| ())?; + } + let parents = target.interior().len() as u8; + Ok(Location::new(parents, junctions)) + } + + /// Execute a function `f` on every junction. We use this since we cannot implement a mutable + /// `Iterator` without unsafe code. + pub fn for_each_mut(&mut self, x: impl FnMut(&mut Junction)) { + self.as_slice_mut().iter_mut().for_each(x) + } + + /// Extract the network ID treating this value as a universal location. + /// + /// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate + /// that this value is not a universal location. + pub fn global_consensus(&self) -> Result { + if let Some(Junction::GlobalConsensus(network)) = self.first() { + Ok(*network) + } else { + Err(()) + } + } + + /// Extract the network ID and the interior consensus location, treating this value as a + /// universal location. + /// + /// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate + /// that this value is not a universal location. + pub fn split_global(self) -> Result<(NetworkId, Junctions), ()> { + match self.split_first() { + (location, Some(Junction::GlobalConsensus(network))) => Ok((network, location)), + _ => return Err(()), + } + } + + /// Treat `self` as a universal location and the context of `relative`, returning the universal + /// location of relative. + /// + /// This will return an error if `relative` has as many (or more) parents than there are + /// junctions in `self`, implying that relative refers into a different global consensus. + pub fn within_global(mut self, relative: Location) -> Result { + if self.len() <= relative.parent_count() as usize { + return Err(()) + } + for _ in 0..relative.parent_count() { + self.take_last(); + } + for j in relative.interior() { + self.push(*j).map_err(|_| ())?; + } + Ok(self) + } + + /// Consumes `self` and returns how `viewer` would address it locally. + pub fn relative_to(mut self, viewer: &Junctions) -> Location { + let mut i = 0; + while match (self.first(), viewer.at(i)) { + (Some(x), Some(y)) => x == y, + _ => false, + } { + self = self.split_first().0; + // NOTE: Cannot overflow as loop can only iterate at most `MAX_JUNCTIONS` times. + i += 1; + } + // AUDIT NOTES: + // - above loop ensures that `i <= viewer.len()`. + // - `viewer.len()` is at most `MAX_JUNCTIONS`, so won't overflow a `u8`. + Location::new((viewer.len() - i) as u8, self) + } + + /// Returns first junction, or `None` if the location is empty. + pub fn first(&self) -> Option<&Junction> { + self.as_slice().first() + } + + /// Returns last junction, or `None` if the location is empty. + pub fn last(&self) -> Option<&Junction> { + self.as_slice().last() + } + + /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the + /// first element (second item in tuple) or `None` if it was empty. + pub fn split_first(self) -> (Junctions, Option) { + match self { + Junctions::Here => (Junctions::Here, None), + Junctions::X1(xs) => { + let [a] = *xs; + (Junctions::Here, Some(a)) + }, + Junctions::X2(xs) => { + let [a, b] = *xs; + ([b].into(), Some(a)) + }, + Junctions::X3(xs) => { + let [a, b, c] = *xs; + ([b, c].into(), Some(a)) + }, + Junctions::X4(xs) => { + let [a, b, c, d] = *xs; + ([b, c, d].into(), Some(a)) + }, + Junctions::X5(xs) => { + let [a, b, c, d, e] = *xs; + ([b, c, d, e].into(), Some(a)) + }, + Junctions::X6(xs) => { + let [a, b, c, d, e, f] = *xs; + ([b, c, d, e, f].into(), Some(a)) + }, + Junctions::X7(xs) => { + let [a, b, c, d, e, f, g] = *xs; + ([b, c, d, e, f, g].into(), Some(a)) + }, + Junctions::X8(xs) => { + let [a, b, c, d, e, f, g, h] = *xs; + ([b, c, d, e, f, g, h].into(), Some(a)) + }, + } + } + + /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the + /// last element (second item in tuple) or `None` if it was empty. + pub fn split_last(self) -> (Junctions, Option) { + match self { + Junctions::Here => (Junctions::Here, None), + Junctions::X1(xs) => { + let [a] = *xs; + (Junctions::Here, Some(a)) + }, + Junctions::X2(xs) => { + let [a, b] = *xs; + ([a].into(), Some(b)) + }, + Junctions::X3(xs) => { + let [a, b, c] = *xs; + ([a, b].into(), Some(c)) + }, + Junctions::X4(xs) => { + let [a, b, c, d] = *xs; + ([a, b, c].into(), Some(d)) + }, + Junctions::X5(xs) => { + let [a, b, c, d, e] = *xs; + ([a, b, c, d].into(), Some(e)) + }, + Junctions::X6(xs) => { + let [a, b, c, d, e, f] = *xs; + ([a, b, c, d, e].into(), Some(f)) + }, + Junctions::X7(xs) => { + let [a, b, c, d, e, f, g] = *xs; + ([a, b, c, d, e, f].into(), Some(g)) + }, + Junctions::X8(xs) => { + let [a, b, c, d, e, f, g, h] = *xs; + ([a, b, c, d, e, f, g].into(), Some(h)) + }, + } + } + + /// Removes the first element from `self`, returning it (or `None` if it was empty). + pub fn take_first(&mut self) -> Option { + let mut d = Junctions::Here; + mem::swap(&mut *self, &mut d); + let (tail, head) = d.split_first(); + *self = tail; + head + } + + /// Removes the last element from `self`, returning it (or `None` if it was empty). + pub fn take_last(&mut self) -> Option { + let mut d = Junctions::Here; + mem::swap(&mut *self, &mut d); + let (head, tail) = d.split_last(); + *self = head; + tail + } + + /// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow. + pub fn push(&mut self, new: impl Into) -> result::Result<(), Junction> { + let new = new.into(); + let mut dummy = Junctions::Here; + mem::swap(self, &mut dummy); + match dummy.pushed_with(new) { + Ok(s) => { + *self = s; + Ok(()) + }, + Err((s, j)) => { + *self = s; + Err(j) + }, + } + } + + /// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow. + pub fn push_front(&mut self, new: impl Into) -> result::Result<(), Junction> { + let new = new.into(); + let mut dummy = Junctions::Here; + mem::swap(self, &mut dummy); + match dummy.pushed_front_with(new) { + Ok(s) => { + *self = s; + Ok(()) + }, + Err((s, j)) => { + *self = s; + Err(j) + }, + } + } + + /// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the + /// original value of `self` and `new` in case of overflow. + pub fn pushed_with(self, new: impl Into) -> result::Result { + let new = new.into(); + Ok(match self { + Junctions::Here => [new].into(), + Junctions::X1(xs) => { + let [a] = *xs; + [a, new].into() + }, + Junctions::X2(xs) => { + let [a, b] = *xs; + [a, b, new].into() + }, + Junctions::X3(xs) => { + let [a, b, c] = *xs; + [a, b, c, new].into() + }, + Junctions::X4(xs) => { + let [a, b, c, d] = *xs; + [a, b, c, d, new].into() + }, + Junctions::X5(xs) => { + let [a, b, c, d, e] = *xs; + [a, b, c, d, e, new].into() + }, + Junctions::X6(xs) => { + let [a, b, c, d, e, f] = *xs; + [a, b, c, d, e, f, new].into() + }, + Junctions::X7(xs) => { + let [a, b, c, d, e, f, g] = *xs; + [a, b, c, d, e, f, g, new].into() + }, + s => Err((s, new))?, + }) + } + + /// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the + /// original value of `self` and `new` in case of overflow. + pub fn pushed_front_with( + self, + new: impl Into, + ) -> result::Result { + let new = new.into(); + Ok(match self { + Junctions::Here => [new].into(), + Junctions::X1(xs) => { + let [a] = *xs; + [new, a].into() + }, + Junctions::X2(xs) => { + let [a, b] = *xs; + [new, a, b].into() + }, + Junctions::X3(xs) => { + let [a, b, c] = *xs; + [new, a, b, c].into() + }, + Junctions::X4(xs) => { + let [a, b, c, d] = *xs; + [new, a, b, c, d].into() + }, + Junctions::X5(xs) => { + let [a, b, c, d, e] = *xs; + [new, a, b, c, d, e].into() + }, + Junctions::X6(xs) => { + let [a, b, c, d, e, f] = *xs; + [new, a, b, c, d, e, f].into() + }, + Junctions::X7(xs) => { + let [a, b, c, d, e, f, g] = *xs; + [new, a, b, c, d, e, f, g].into() + }, + s => Err((s, new))?, + }) + } + + /// Mutate `self` so that it is suffixed with `suffix`. + /// + /// Does not modify `self` and returns `Err` with `suffix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions, Junction::*, Location}; + /// # fn main() { + /// let mut m = Junctions::from([Parachain(21)]); + /// assert_eq!(m.append_with([PalletInstance(3)]), Ok(())); + /// assert_eq!(m, [Parachain(21), PalletInstance(3)]); + /// # } + /// ``` + pub fn append_with(&mut self, suffix: impl Into) -> Result<(), Junctions> { + let suffix = suffix.into(); + if self.len().saturating_add(suffix.len()) > MAX_JUNCTIONS { + return Err(suffix) + } + for j in suffix.into_iter() { + self.push(j).expect("Already checked the sum of the len()s; qed") + } + Ok(()) + } + + /// Returns the number of junctions in `self`. + pub fn len(&self) -> usize { + self.as_slice().len() + } + + /// Returns the junction at index `i`, or `None` if the location doesn't contain that many + /// elements. + pub fn at(&self, i: usize) -> Option<&Junction> { + self.as_slice().get(i) + } + + /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't + /// contain that many elements. + pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { + self.as_slice_mut().get_mut(i) + } + + /// Returns a reference iterator over the junctions. + pub fn iter(&self) -> JunctionsRefIterator { + JunctionsRefIterator { junctions: self, range: 0..self.len() } + } + + /// Ensures that self begins with `prefix` and that it has a single `Junction` item following. + /// If so, returns a reference to this `Junction` item. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions, Junction::*}; + /// # fn main() { + /// let mut m = Junctions::from([Parachain(2), PalletInstance(3), OnlyChild]); + /// assert_eq!(m.match_and_split(&[Parachain(2), PalletInstance(3)].into()), Some(&OnlyChild)); + /// assert_eq!(m.match_and_split(&[Parachain(2)].into()), None); + /// # } + /// ``` + pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> { + if prefix.len() + 1 != self.len() { + return None + } + for i in 0..prefix.len() { + if prefix.at(i) != self.at(i) { + return None + } + } + return self.at(prefix.len()) + } + + pub fn starts_with(&self, prefix: &Junctions) -> bool { + prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y) + } +} + +impl TryFrom for Junctions { + type Error = Location; + fn try_from(x: Location) -> result::Result { + if x.parent_count() > 0 { + Err(x) + } else { + Ok(x.interior().clone()) + } + } +} + +impl> From for Junctions { + fn from(x: T) -> Self { + [x.into()].into() + } +} + +impl From<[Junction; 0]> for Junctions { + fn from(_: [Junction; 0]) -> Self { + Self::Here + } +} + +impl From<()> for Junctions { + fn from(_: ()) -> Self { + Self::Here + } +} + +xcm_procedural::impl_conversion_functions_for_junctions_v5!(); + +#[cfg(test)] +mod tests { + use super::{super::prelude::*, *}; + + #[test] + fn inverting_works() { + let context: InteriorLocation = (Parachain(1000), PalletInstance(42)).into(); + let target = (Parent, PalletInstance(69)).into(); + let expected = (Parent, PalletInstance(42)).into(); + let inverted = context.invert_target(&target).unwrap(); + assert_eq!(inverted, expected); + + let context: InteriorLocation = + (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into(); + let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into(); + let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into(); + let inverted = context.invert_target(&target).unwrap(); + assert_eq!(inverted, expected); + } + + #[test] + fn relative_to_works() { + use NetworkId::*; + assert_eq!( + Junctions::from([Polkadot.into()]).relative_to(&Junctions::from([Kusama.into()])), + (Parent, Polkadot).into() + ); + let base = Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1)]); + + // Ancestors. + assert_eq!(Here.relative_to(&base), (Parent, Parent, Parent).into()); + assert_eq!(Junctions::from([Kusama.into()]).relative_to(&base), (Parent, Parent).into()); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(1)]).relative_to(&base), + (Parent,).into() + ); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1)]).relative_to(&base), + Here.into() + ); + + // Ancestors with one child. + assert_eq!( + Junctions::from([Polkadot.into()]).relative_to(&base), + (Parent, Parent, Parent, Polkadot).into() + ); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(2)]).relative_to(&base), + (Parent, Parent, Parachain(2)).into() + ); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(1), PalletInstance(2)]).relative_to(&base), + (Parent, PalletInstance(2)).into() + ); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into()]) + .relative_to(&base), + ([1u8; 32],).into() + ); + + // Ancestors with grandchildren. + assert_eq!( + Junctions::from([Polkadot.into(), Parachain(1)]).relative_to(&base), + (Parent, Parent, Parent, Polkadot, Parachain(1)).into() + ); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(2), PalletInstance(1)]).relative_to(&base), + (Parent, Parent, Parachain(2), PalletInstance(1)).into() + ); + assert_eq!( + Junctions::from([Kusama.into(), Parachain(1), PalletInstance(2), [1u8; 32].into()]) + .relative_to(&base), + (Parent, PalletInstance(2), [1u8; 32]).into() + ); + assert_eq!( + Junctions::from([ + Kusama.into(), + Parachain(1), + PalletInstance(1), + [1u8; 32].into(), + 1u128.into() + ]) + .relative_to(&base), + ([1u8; 32], 1u128).into() + ); + } + + #[test] + fn global_consensus_works() { + use NetworkId::*; + assert_eq!(Junctions::from([Polkadot.into()]).global_consensus(), Ok(Polkadot)); + assert_eq!(Junctions::from([Kusama.into(), 1u64.into()]).global_consensus(), Ok(Kusama)); + assert_eq!(Here.global_consensus(), Err(())); + assert_eq!(Junctions::from([1u64.into()]).global_consensus(), Err(())); + assert_eq!(Junctions::from([1u64.into(), Kusama.into()]).global_consensus(), Err(())); + } + + #[test] + fn test_conversion() { + use super::{Junction::*, NetworkId::*}; + let x: Junctions = GlobalConsensus(Polkadot).into(); + assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot)])); + let x: Junctions = Polkadot.into(); + assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot)])); + let x: Junctions = (Polkadot, Kusama).into(); + assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot), GlobalConsensus(Kusama)])); + } + + #[test] + fn encode_decode_junctions_works() { + let original = Junctions::from([ + Polkadot.into(), + Kusama.into(), + 1u64.into(), + GlobalConsensus(Polkadot), + Parachain(123), + PalletInstance(45), + ]); + let encoded = original.encode(); + assert_eq!(encoded, &[6, 9, 2, 9, 3, 2, 0, 4, 9, 2, 0, 237, 1, 4, 45]); + let decoded = Junctions::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, original); + } +} diff --git a/polkadot/xcm/src/v5/location.rs b/polkadot/xcm/src/v5/location.rs new file mode 100644 index 000000000000..38e8ecdd15ca --- /dev/null +++ b/polkadot/xcm/src/v5/location.rs @@ -0,0 +1,755 @@ +// 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 . + +//! XCM `Location` datatype. + +use super::{traits::Reanchorable, Junction, Junctions}; +use crate::{v4::Location as OldLocation, VersionedLocation}; +use codec::{Decode, Encode, MaxEncodedLen}; +use core::result; +use scale_info::TypeInfo; + +/// A relative path between state-bearing consensus systems. +/// +/// A location in a consensus system is defined as an *isolatable state machine* held within global +/// consensus. The location in question need not have a sophisticated consensus algorithm of its +/// own; a single account within Ethereum, for example, could be considered a location. +/// +/// A very-much non-exhaustive list of types of location include: +/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain. +/// - A layer-0 super-chain, e.g. the Polkadot Relay chain. +/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum. +/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based +/// Substrate chain. +/// - An account. +/// +/// A `Location` is a *relative identifier*, meaning that it can only be used to define the +/// relative path between two locations, and cannot generally be used to refer to a location +/// universally. It is comprised of an integer number of parents specifying the number of times to +/// "escape" upwards into the containing consensus system and then a number of *junctions*, each +/// diving down and specifying some interior portion of state (which may be considered a +/// "sub-consensus" system). +/// +/// This specific `Location` implementation uses a `Junctions` datatype which is a Rust `enum` +/// in order to make pattern matching easier. There are occasions where it is important to ensure +/// that a value is strictly an interior location, in those cases, `Junctions` may be used. +/// +/// The `Location` value of `Null` simply refers to the interpreting consensus system. +#[derive( + Clone, + Decode, + Encode, + Eq, + PartialEq, + Ord, + PartialOrd, + Debug, + TypeInfo, + MaxEncodedLen, + serde::Serialize, + serde::Deserialize, +)] +pub struct Location { + /// The number of parent junctions at the beginning of this `Location`. + pub parents: u8, + /// The interior (i.e. non-parent) junctions that this `Location` contains. + pub interior: Junctions, +} + +impl Default for Location { + fn default() -> Self { + Self::here() + } +} + +/// A relative location which is constrained to be an interior location of the context. +/// +/// See also `Location`. +pub type InteriorLocation = Junctions; + +impl Location { + /// Creates a new `Location` with the given number of parents and interior junctions. + pub fn new(parents: u8, interior: impl Into) -> Location { + Location { parents, interior: interior.into() } + } + + /// Consume `self` and return the equivalent `VersionedLocation` value. + pub const fn into_versioned(self) -> VersionedLocation { + VersionedLocation::V5(self) + } + + /// Creates a new `Location` with 0 parents and a `Here` interior. + /// + /// The resulting `Location` can be interpreted as the "current consensus system". + pub const fn here() -> Location { + Location { parents: 0, interior: Junctions::Here } + } + + /// Creates a new `Location` which evaluates to the parent context. + pub const fn parent() -> Location { + Location { parents: 1, interior: Junctions::Here } + } + + /// Creates a new `Location` with `parents` and an empty (`Here`) interior. + pub const fn ancestor(parents: u8) -> Location { + Location { parents, interior: Junctions::Here } + } + + /// Whether the `Location` has no parents and has a `Here` interior. + pub fn is_here(&self) -> bool { + self.parents == 0 && self.interior.len() == 0 + } + + /// Remove the `NetworkId` value in any interior `Junction`s. + pub fn remove_network_id(&mut self) { + self.interior.remove_network_id(); + } + + /// Return a reference to the interior field. + pub fn interior(&self) -> &Junctions { + &self.interior + } + + /// Return a mutable reference to the interior field. + pub fn interior_mut(&mut self) -> &mut Junctions { + &mut self.interior + } + + /// Returns the number of `Parent` junctions at the beginning of `self`. + pub const fn parent_count(&self) -> u8 { + self.parents + } + + /// Returns the parent count and the interior [`Junctions`] as a tuple. + /// + /// To be used when pattern matching, for example: + /// + /// ```rust + /// # use staging_xcm::v5::{Junctions::*, Junction::*, Location}; + /// fn get_parachain_id(loc: &Location) -> Option { + /// match loc.unpack() { + /// (0, [Parachain(id)]) => Some(*id), + /// _ => None + /// } + /// } + /// ``` + pub fn unpack(&self) -> (u8, &[Junction]) { + (self.parents, self.interior.as_slice()) + } + + /// Returns boolean indicating whether `self` contains only the specified amount of + /// parents and no interior junctions. + pub const fn contains_parents_only(&self, count: u8) -> bool { + matches!(self.interior, Junctions::Here) && self.parents == count + } + + /// Returns the number of parents and junctions in `self`. + pub fn len(&self) -> usize { + self.parent_count() as usize + self.interior.len() + } + + /// Returns the first interior junction, or `None` if the location is empty or contains only + /// parents. + pub fn first_interior(&self) -> Option<&Junction> { + self.interior.first() + } + + /// Returns last junction, or `None` if the location is empty or contains only parents. + pub fn last(&self) -> Option<&Junction> { + self.interior.last() + } + + /// Splits off the first interior junction, returning the remaining suffix (first item in tuple) + /// and the first element (second item in tuple) or `None` if it was empty. + pub fn split_first_interior(self) -> (Location, Option) { + let Location { parents, interior: junctions } = self; + let (suffix, first) = junctions.split_first(); + let location = Location { parents, interior: suffix }; + (location, first) + } + + /// Splits off the last interior junction, returning the remaining prefix (first item in tuple) + /// and the last element (second item in tuple) or `None` if it was empty or if `self` only + /// contains parents. + pub fn split_last_interior(self) -> (Location, Option) { + let Location { parents, interior: junctions } = self; + let (prefix, last) = junctions.split_last(); + let location = Location { parents, interior: prefix }; + (location, last) + } + + /// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in + /// case of overflow. + pub fn push_interior(&mut self, new: impl Into) -> result::Result<(), Junction> { + self.interior.push(new) + } + + /// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in + /// case of overflow. + pub fn push_front_interior( + &mut self, + new: impl Into, + ) -> result::Result<(), Junction> { + self.interior.push_front(new) + } + + /// Consumes `self` and returns a `Location` suffixed with `new`, or an `Err` with + /// the original value of `self` in case of overflow. + pub fn pushed_with_interior( + self, + new: impl Into, + ) -> result::Result { + match self.interior.pushed_with(new) { + Ok(i) => Ok(Location { interior: i, parents: self.parents }), + Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)), + } + } + + /// Consumes `self` and returns a `Location` prefixed with `new`, or an `Err` with the + /// original value of `self` in case of overflow. + pub fn pushed_front_with_interior( + self, + new: impl Into, + ) -> result::Result { + match self.interior.pushed_front_with(new) { + Ok(i) => Ok(Location { interior: i, parents: self.parents }), + Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)), + } + } + + /// Returns the junction at index `i`, or `None` if the location is a parent or if the location + /// does not contain that many elements. + pub fn at(&self, i: usize) -> Option<&Junction> { + let num_parents = self.parents as usize; + if i < num_parents { + return None + } + self.interior.at(i - num_parents) + } + + /// Returns a mutable reference to the junction at index `i`, or `None` if the location is a + /// parent or if it doesn't contain that many elements. + pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { + let num_parents = self.parents as usize; + if i < num_parents { + return None + } + self.interior.at_mut(i - num_parents) + } + + /// Decrements the parent count by 1. + pub fn dec_parent(&mut self) { + self.parents = self.parents.saturating_sub(1); + } + + /// Removes the first interior junction from `self`, returning it + /// (or `None` if it was empty or if `self` contains only parents). + pub fn take_first_interior(&mut self) -> Option { + self.interior.take_first() + } + + /// Removes the last element from `interior`, returning it (or `None` if it was empty or if + /// `self` only contains parents). + pub fn take_last(&mut self) -> Option { + self.interior.take_last() + } + + /// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with + /// the junctions of `prefix` and that it has a single `Junction` item following. + /// If so, returns a reference to this `Junction` item. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions::*, Junction::*, Location}; + /// # fn main() { + /// let mut m = Location::new(1, [PalletInstance(3), OnlyChild]); + /// assert_eq!( + /// m.match_and_split(&Location::new(1, [PalletInstance(3)])), + /// Some(&OnlyChild), + /// ); + /// assert_eq!(m.match_and_split(&Location::new(1, Here)), None); + /// # } + /// ``` + pub fn match_and_split(&self, prefix: &Location) -> Option<&Junction> { + if self.parents != prefix.parents { + return None + } + self.interior.match_and_split(&prefix.interior) + } + + pub fn starts_with(&self, prefix: &Location) -> bool { + self.parents == prefix.parents && self.interior.starts_with(&prefix.interior) + } + + /// Mutate `self` so that it is suffixed with `suffix`. + /// + /// Does not modify `self` and returns `Err` with `suffix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent}; + /// # fn main() { + /// let mut m: Location = (Parent, Parachain(21), 69u64).into(); + /// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(())); + /// assert_eq!(m, Location::new(1, [Parachain(21), PalletInstance(3)])); + /// # } + /// ``` + pub fn append_with(&mut self, suffix: impl Into) -> Result<(), Self> { + let prefix = core::mem::replace(self, suffix.into()); + match self.prepend_with(prefix) { + Ok(()) => Ok(()), + Err(prefix) => Err(core::mem::replace(self, prefix)), + } + } + + /// Consume `self` and return its value suffixed with `suffix`. + /// + /// Returns `Err` with the original value of `self` and `suffix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent}; + /// # fn main() { + /// let mut m: Location = (Parent, Parachain(21), 69u64).into(); + /// let r = m.appended_with((Parent, PalletInstance(3))).unwrap(); + /// assert_eq!(r, Location::new(1, [Parachain(21), PalletInstance(3)])); + /// # } + /// ``` + pub fn appended_with(mut self, suffix: impl Into) -> Result { + match self.append_with(suffix) { + Ok(()) => Ok(self), + Err(suffix) => Err((self, suffix)), + } + } + + /// Mutate `self` so that it is prefixed with `prefix`. + /// + /// Does not modify `self` and returns `Err` with `prefix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent}; + /// # fn main() { + /// let mut m: Location = (Parent, Parent, PalletInstance(3)).into(); + /// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(())); + /// assert_eq!(m, Location::new(1, [PalletInstance(3)])); + /// # } + /// ``` + pub fn prepend_with(&mut self, prefix: impl Into) -> Result<(), Self> { + // prefix self (suffix) + // P .. P I .. I p .. p i .. i + let mut prefix = prefix.into(); + let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize); + let final_interior = self.interior.len().saturating_add(prepend_interior); + if final_interior > super::junctions::MAX_JUNCTIONS { + return Err(prefix) + } + let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len()); + let final_parents = (prefix.parents as usize).saturating_add(suffix_parents); + if final_parents > 255 { + return Err(prefix) + } + + // cancel out the final item on the prefix interior for one of the suffix's parents. + while self.parents > 0 && prefix.take_last().is_some() { + self.dec_parent(); + } + + // now we have either removed all suffix's parents or prefix interior. + // this means we can combine the prefix's and suffix's remaining parents/interior since + // we know that with at least one empty, the overall order will be respected: + // prefix self (suffix) + // P .. P (I) p .. p i .. i => P + p .. (no I) i + // -- or -- + // P .. P I .. I (p) i .. i => P (no p) .. I + i + + self.parents = self.parents.saturating_add(prefix.parents); + for j in prefix.interior.into_iter().rev() { + self.push_front_interior(j) + .expect("final_interior no greater than MAX_JUNCTIONS; qed"); + } + Ok(()) + } + + /// Consume `self` and return its value prefixed with `prefix`. + /// + /// Returns `Err` with the original value of `self` and `prefix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use staging_xcm::v5::{Junctions::*, Junction::*, Location, Parent}; + /// # fn main() { + /// let m: Location = (Parent, Parent, PalletInstance(3)).into(); + /// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap(); + /// assert_eq!(r, Location::new(1, [PalletInstance(3)])); + /// # } + /// ``` + pub fn prepended_with(mut self, prefix: impl Into) -> Result { + match self.prepend_with(prefix) { + Ok(()) => Ok(self), + Err(prefix) => Err((self, prefix)), + } + } + + /// Remove any unneeded parents/junctions in `self` based on the given context it will be + /// interpreted in. + pub fn simplify(&mut self, context: &Junctions) { + if context.len() < self.parents as usize { + // Not enough context + return + } + while self.parents > 0 { + let maybe = context.at(context.len() - (self.parents as usize)); + match (self.interior.first(), maybe) { + (Some(i), Some(j)) if i == j => { + self.interior.take_first(); + self.parents -= 1; + }, + _ => break, + } + } + } + + /// Return the Location subsection identifying the chain that `self` points to. + pub fn chain_location(&self) -> Location { + let mut clone = self.clone(); + // start popping junctions until we reach chain identifier + while let Some(j) = clone.last() { + if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) { + // return chain subsection + return clone + } else { + (clone, _) = clone.split_last_interior(); + } + } + Location::new(clone.parents, Junctions::Here) + } +} + +impl Reanchorable for Location { + type Error = Self; + + /// Mutate `self` so that it represents the same location from the point of view of `target`. + /// The context of `self` is provided as `context`. + /// + /// Does not modify `self` in case of overflow. + fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> { + // TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this. + + // 1. Use our `context` to figure out how the `target` would address us. + let inverted_target = context.invert_target(target)?; + + // 2. Prepend `inverted_target` to `self` to get self's location from the perspective of + // `target`. + self.prepend_with(inverted_target).map_err(|_| ())?; + + // 3. Given that we know some of `target` context, ensure that any parents in `self` are + // strictly needed. + self.simplify(target.interior()); + + Ok(()) + } + + /// Consume `self` and return a new value representing the same location from the point of view + /// of `target`. The context of `self` is provided as `context`. + /// + /// Returns the original `self` in case of overflow. + fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result { + match self.reanchor(target, context) { + Ok(()) => Ok(self), + Err(()) => Err(self), + } + } +} + +impl TryFrom for Option { + type Error = (); + fn try_from(value: OldLocation) -> result::Result { + Ok(Some(Location::try_from(value)?)) + } +} + +impl TryFrom for Location { + type Error = (); + fn try_from(x: OldLocation) -> result::Result { + Ok(Location { parents: x.parents, interior: x.interior.try_into()? }) + } +} + +/// A unit struct which can be converted into a `Location` of `parents` value 1. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Parent; +impl From for Location { + fn from(_: Parent) -> Self { + Location { parents: 1, interior: Junctions::Here } + } +} + +/// A tuple struct which can be converted into a `Location` of `parents` value 1 with the inner +/// interior. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct ParentThen(pub Junctions); +impl From for Location { + fn from(ParentThen(interior): ParentThen) -> Self { + Location { parents: 1, interior } + } +} + +/// A unit struct which can be converted into a `Location` of the inner `parents` value. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Ancestor(pub u8); +impl From for Location { + fn from(Ancestor(parents): Ancestor) -> Self { + Location { parents, interior: Junctions::Here } + } +} + +/// A unit struct which can be converted into a `Location` of the inner `parents` value and the +/// inner interior. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct AncestorThen(pub u8, pub Interior); +impl> From> for Location { + fn from(AncestorThen(parents, interior): AncestorThen) -> Self { + Location { parents, interior: interior.into() } + } +} + +impl From<[u8; 32]> for Location { + fn from(bytes: [u8; 32]) -> Self { + let junction: Junction = bytes.into(); + junction.into() + } +} + +impl From for Location { + fn from(id: sp_runtime::AccountId32) -> Self { + Junction::AccountId32 { network: None, id: id.into() }.into() + } +} + +xcm_procedural::impl_conversion_functions_for_location_v5!(); + +#[cfg(test)] +mod tests { + use crate::v5::prelude::*; + use codec::{Decode, Encode}; + + #[test] + fn conversion_works() { + let x: Location = Parent.into(); + assert_eq!(x, Location { parents: 1, interior: Here }); + // let x: Location = (Parent,).into(); + // assert_eq!(x, Location { parents: 1, interior: Here }); + // let x: Location = (Parent, Parent).into(); + // assert_eq!(x, Location { parents: 2, interior: Here }); + let x: Location = (Parent, Parent, OnlyChild).into(); + assert_eq!(x, Location { parents: 2, interior: OnlyChild.into() }); + let x: Location = OnlyChild.into(); + assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() }); + let x: Location = (OnlyChild,).into(); + assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() }); + } + + #[test] + fn simplify_basic_works() { + let mut location: Location = + (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); + let context = [Parachain(1000), PalletInstance(42)].into(); + let expected = GeneralIndex(69).into(); + location.simplify(&context); + assert_eq!(location, expected); + + let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into(); + let context = [PalletInstance(42)].into(); + let expected = GeneralIndex(69).into(); + location.simplify(&context); + assert_eq!(location, expected); + + let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into(); + let context = [Parachain(1000), PalletInstance(42)].into(); + let expected = GeneralIndex(69).into(); + location.simplify(&context); + assert_eq!(location, expected); + + let mut location: Location = + (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); + let context = [OnlyChild, Parachain(1000), PalletInstance(42)].into(); + let expected = GeneralIndex(69).into(); + location.simplify(&context); + assert_eq!(location, expected); + } + + #[test] + fn simplify_incompatible_location_fails() { + let mut location: Location = + (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); + let context = [Parachain(1000), PalletInstance(42), GeneralIndex(42)].into(); + let expected = + (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); + location.simplify(&context); + assert_eq!(location, expected); + + let mut location: Location = + (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); + let context = [Parachain(1000)].into(); + let expected = + (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into(); + location.simplify(&context); + assert_eq!(location, expected); + } + + #[test] + fn reanchor_works() { + let mut id: Location = (Parent, Parachain(1000), GeneralIndex(42)).into(); + let context = Parachain(2000).into(); + let target = (Parent, Parachain(1000)).into(); + let expected = GeneralIndex(42).into(); + id.reanchor(&target, &context).unwrap(); + assert_eq!(id, expected); + } + + #[test] + fn encode_and_decode_works() { + let m = Location { + parents: 1, + interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(), + }; + let encoded = m.encode(); + assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec()); + let decoded = Location::decode(&mut &encoded[..]); + assert_eq!(decoded, Ok(m)); + } + + #[test] + fn match_and_split_works() { + let m = Location { + parents: 1, + interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(), + }; + assert_eq!(m.match_and_split(&Location { parents: 1, interior: Here }), None); + assert_eq!( + m.match_and_split(&Location { parents: 1, interior: [Parachain(42)].into() }), + Some(&AccountIndex64 { network: None, index: 23 }) + ); + assert_eq!(m.match_and_split(&m), None); + } + + #[test] + fn append_with_works() { + let acc = AccountIndex64 { network: None, index: 23 }; + let mut m = Location { parents: 1, interior: [Parachain(42)].into() }; + assert_eq!(m.append_with([PalletInstance(3), acc]), Ok(())); + assert_eq!( + m, + Location { parents: 1, interior: [Parachain(42), PalletInstance(3), acc].into() } + ); + + // cannot append to create overly long location + let acc = AccountIndex64 { network: None, index: 23 }; + let m = Location { + parents: 254, + interior: [Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild].into(), + }; + let suffix: Location = (PalletInstance(3), acc, OnlyChild, OnlyChild).into(); + assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix)); + } + + #[test] + fn prepend_with_works() { + let mut m = Location { + parents: 1, + interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(), + }; + assert_eq!(m.prepend_with(Location { parents: 1, interior: [OnlyChild].into() }), Ok(())); + assert_eq!( + m, + Location { + parents: 1, + interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into() + } + ); + + // cannot prepend to create overly long location + let mut m = Location { parents: 254, interior: [Parachain(42)].into() }; + let prefix = Location { parents: 2, interior: Here }; + assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); + + let prefix = Location { parents: 1, interior: Here }; + assert_eq!(m.prepend_with(prefix.clone()), Ok(())); + assert_eq!(m, Location { parents: 255, interior: [Parachain(42)].into() }); + } + + #[test] + fn double_ended_ref_iteration_works() { + let m: Junctions = [Parachain(1000), Parachain(3), PalletInstance(5)].into(); + let mut iter = m.iter(); + + let first = iter.next().unwrap(); + assert_eq!(first, &Parachain(1000)); + let third = iter.next_back().unwrap(); + assert_eq!(third, &PalletInstance(5)); + let second = iter.next_back().unwrap(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(second, &Parachain(3)); + + let res = Here + .pushed_with(*first) + .unwrap() + .pushed_with(*second) + .unwrap() + .pushed_with(*third) + .unwrap(); + assert_eq!(m, res); + + // make sure there's no funny business with the 0 indexing + let m = Here; + let mut iter = m.iter(); + + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + } + + #[test] + fn conversion_from_other_types_works() { + use crate::v4; + + fn takes_location>(_arg: Arg) {} + + takes_location(Parent); + takes_location(Here); + takes_location([Parachain(42)]); + takes_location((Ancestor(255), PalletInstance(8))); + takes_location((Ancestor(5), Parachain(1), PalletInstance(3))); + takes_location((Ancestor(2), Here)); + takes_location(AncestorThen( + 3, + [Parachain(43), AccountIndex64 { network: None, index: 155 }], + )); + takes_location((Parent, AccountId32 { network: None, id: [0; 32] })); + takes_location((Parent, Here)); + takes_location(ParentThen([Parachain(75)].into())); + takes_location([Parachain(100), PalletInstance(3)]); + + assert_eq!(v4::Location::from(v4::Junctions::Here).try_into(), Ok(Location::here())); + assert_eq!(v4::Location::from(v4::Parent).try_into(), Ok(Location::parent())); + assert_eq!( + v4::Location::from((v4::Parent, v4::Parent, v4::Junction::GeneralIndex(42u128),)) + .try_into(), + Ok(Location { parents: 2, interior: [GeneralIndex(42u128)].into() }), + ); + } +} diff --git a/polkadot/xcm/src/v5/mod.rs b/polkadot/xcm/src/v5/mod.rs new file mode 100644 index 000000000000..21845d07529e --- /dev/null +++ b/polkadot/xcm/src/v5/mod.rs @@ -0,0 +1,1686 @@ +// 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 . + +//! Version 5 of the Cross-Consensus Message format data structures. + +pub use super::v3::GetWeight; +use super::v4::{ + Instruction as OldInstruction, PalletInfo as OldPalletInfo, + QueryResponseInfo as OldQueryResponseInfo, Response as OldResponse, Xcm as OldXcm, +}; +use crate::DoubleEncoded; +use alloc::{vec, vec::Vec}; +use bounded_collections::{parameter_types, BoundedVec}; +use codec::{ + self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput, + MaxEncodedLen, +}; +use core::{fmt::Debug, result}; +use derivative::Derivative; +use scale_info::TypeInfo; + +mod asset; +mod junction; +pub(crate) mod junctions; +mod location; +mod traits; + +pub use asset::{ + Asset, AssetFilter, AssetId, AssetInstance, AssetTransferFilter, Assets, Fungibility, + WildAsset, WildFungibility, MAX_ITEMS_IN_ASSETS, +}; +pub use junction::{ + BodyId, BodyPart, Junction, NetworkId, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH, +}; +pub use junctions::Junctions; +pub use location::{Ancestor, AncestorThen, InteriorLocation, Location, Parent, ParentThen}; +pub use traits::{ + send_xcm, validate_send, Error, ExecuteXcm, Outcome, PreparedMessage, Reanchorable, Result, + SendError, SendResult, SendXcm, Weight, XcmHash, +}; +// These parts of XCM v4 are unchanged in XCM v5, and are re-imported here. +pub use super::v4::{MaxDispatchErrorLen, MaybeErrorCode, OriginKind, WeightLimit}; + +pub const VERSION: super::Version = 5; + +/// An identifier for a query. +pub type QueryId = u64; + +#[derive(Derivative, Default, Encode, TypeInfo)] +#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] +#[codec(encode_bound())] +#[codec(decode_bound())] +#[scale_info(bounds(), skip_type_params(Call))] +pub struct Xcm(pub Vec>); + +pub const MAX_INSTRUCTIONS_TO_DECODE: u8 = 100; + +environmental::environmental!(instructions_count: u8); + +impl Decode for Xcm { + fn decode(input: &mut I) -> core::result::Result { + instructions_count::using_once(&mut 0, || { + let number_of_instructions: u32 = >::decode(input)?.into(); + instructions_count::with(|count| { + *count = count.saturating_add(number_of_instructions as u8); + if *count > MAX_INSTRUCTIONS_TO_DECODE { + return Err(CodecError::from("Max instructions exceeded")) + } + Ok(()) + }) + .expect("Called in `using` context and thus can not return `None`; qed")?; + let decoded_instructions = decode_vec_with_len(input, number_of_instructions as usize)?; + Ok(Self(decoded_instructions)) + }) + } +} + +impl Xcm { + /// Create an empty instance. + pub fn new() -> Self { + Self(vec![]) + } + + /// Return `true` if no instructions are held in `self`. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Return the number of instructions held in `self`. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Return a reference to the inner value. + pub fn inner(&self) -> &[Instruction] { + &self.0 + } + + /// Return a mutable reference to the inner value. + pub fn inner_mut(&mut self) -> &mut Vec> { + &mut self.0 + } + + /// Consume and return the inner value. + pub fn into_inner(self) -> Vec> { + self.0 + } + + /// Return an iterator over references to the items. + pub fn iter(&self) -> impl Iterator> { + self.0.iter() + } + + /// Return an iterator over mutable references to the items. + pub fn iter_mut(&mut self) -> impl Iterator> { + self.0.iter_mut() + } + + /// Consume and return an iterator over the items. + pub fn into_iter(self) -> impl Iterator> { + self.0.into_iter() + } + + /// Consume and either return `self` if it contains some instructions, or if it's empty, then + /// instead return the result of `f`. + pub fn or_else(self, f: impl FnOnce() -> Self) -> Self { + if self.0.is_empty() { + f() + } else { + self + } + } + + /// Return the first instruction, if any. + pub fn first(&self) -> Option<&Instruction> { + self.0.first() + } + + /// Return the last instruction, if any. + pub fn last(&self) -> Option<&Instruction> { + self.0.last() + } + + /// Return the only instruction, contained in `Self`, iff only one exists (`None` otherwise). + pub fn only(&self) -> Option<&Instruction> { + if self.0.len() == 1 { + self.0.first() + } else { + None + } + } + + /// Return the only instruction, contained in `Self`, iff only one exists (returns `self` + /// otherwise). + pub fn into_only(mut self) -> core::result::Result, Self> { + if self.0.len() == 1 { + self.0.pop().ok_or(self) + } else { + Err(self) + } + } +} + +impl From>> for Xcm { + fn from(c: Vec>) -> Self { + Self(c) + } +} + +impl From> for Vec> { + fn from(c: Xcm) -> Self { + c.0 + } +} + +/// A prelude for importing all types typically used when interacting with XCM messages. +pub mod prelude { + mod contents { + pub use super::super::{ + send_xcm, validate_send, Ancestor, AncestorThen, Asset, + AssetFilter::{self, *}, + AssetId, + AssetInstance::{self, *}, + Assets, BodyId, BodyPart, Error as XcmError, ExecuteXcm, + Fungibility::{self, *}, + Hint::{self, *}, + HintNumVariants, + Instruction::*, + InteriorLocation, + Junction::{self, *}, + Junctions::{self, Here}, + Location, MaybeErrorCode, + NetworkId::{self, *}, + OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId, + QueryResponseInfo, Reanchorable, Response, Result as XcmResult, SendError, SendResult, + SendXcm, Weight, + WeightLimit::{self, *}, + WildAsset::{self, *}, + WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, + XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION, + }; + } + pub use super::{Instruction, Xcm}; + pub use contents::*; + pub mod opaque { + pub use super::{ + super::opaque::{Instruction, Xcm}, + contents::*, + }; + } +} + +parameter_types! { + pub MaxPalletNameLen: u32 = 48; + pub MaxPalletsInfo: u32 = 64; +} + +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +pub struct PalletInfo { + #[codec(compact)] + pub index: u32, + pub name: BoundedVec, + pub module_name: BoundedVec, + #[codec(compact)] + pub major: u32, + #[codec(compact)] + pub minor: u32, + #[codec(compact)] + pub patch: u32, +} + +impl TryInto for PalletInfo { + type Error = (); + + fn try_into(self) -> result::Result { + OldPalletInfo::new( + self.index, + self.name.into_inner(), + self.module_name.into_inner(), + self.major, + self.minor, + self.patch, + ) + .map_err(|_| ()) + } +} + +impl PalletInfo { + pub fn new( + index: u32, + name: Vec, + module_name: Vec, + major: u32, + minor: u32, + patch: u32, + ) -> result::Result { + let name = BoundedVec::try_from(name).map_err(|_| Error::Overflow)?; + let module_name = BoundedVec::try_from(module_name).map_err(|_| Error::Overflow)?; + + Ok(Self { index, name, module_name, major, minor, patch }) + } +} + +/// Response data to a query. +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +pub enum Response { + /// No response. Serves as a neutral default. + Null, + /// Some assets. + Assets(Assets), + /// The outcome of an XCM instruction. + ExecutionResult(Option<(u32, Error)>), + /// An XCM version. + Version(super::Version), + /// The index, instance name, pallet name and version of some pallets. + PalletsInfo(BoundedVec), + /// The status of a dispatch attempt using `Transact`. + DispatchResult(MaybeErrorCode), +} + +impl Default for Response { + fn default() -> Self { + Self::Null + } +} + +impl TryFrom for Response { + type Error = (); + + fn try_from(old: OldResponse) -> result::Result { + use OldResponse::*; + Ok(match old { + Null => Self::Null, + Assets(assets) => Self::Assets(assets.try_into()?), + ExecutionResult(result) => Self::ExecutionResult( + result + .map(|(num, old_error)| (num, old_error.try_into())) + .map(|(num, result)| result.map(|inner| (num, inner))) + .transpose()?, + ), + Version(version) => Self::Version(version), + PalletsInfo(pallet_info) => { + let inner = pallet_info + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?; + Self::PalletsInfo( + BoundedVec::::try_from(inner).map_err(|_| ())?, + ) + }, + DispatchResult(maybe_error) => Self::DispatchResult(maybe_error), + }) + } +} + +/// Information regarding the composition of a query response. +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] +pub struct QueryResponseInfo { + /// The destination to which the query response message should be send. + pub destination: Location, + /// The `query_id` field of the `QueryResponse` message. + #[codec(compact)] + pub query_id: QueryId, + /// The `max_weight` field of the `QueryResponse` message. + pub max_weight: Weight, +} + +impl TryFrom for QueryResponseInfo { + type Error = (); + + fn try_from(old: OldQueryResponseInfo) -> result::Result { + Ok(Self { + destination: old.destination.try_into()?, + query_id: old.query_id, + max_weight: old.max_weight, + }) + } +} + +/// Contextual data pertaining to a specific list of XCM instructions. +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub struct XcmContext { + /// The current value of the Origin register of the `XCVM`. + pub origin: Option, + /// The identity of the XCM; this may be a hash of its versioned encoding but could also be + /// a high-level identity set by an appropriate barrier. + pub message_id: XcmHash, + /// The current value of the Topic register of the `XCVM`. + pub topic: Option<[u8; 32]>, +} + +impl XcmContext { + /// Constructor which sets the message ID to the supplied parameter and leaves the origin and + /// topic unset. + pub fn with_message_id(message_id: XcmHash) -> XcmContext { + XcmContext { origin: None, message_id, topic: None } + } +} + +/// Cross-Consensus Message: A message from one consensus system to another. +/// +/// Consensus systems that may send and receive messages include blockchains and smart contracts. +/// +/// All messages are delivered from a known *origin*, expressed as a `Location`. +/// +/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the +/// outer XCM format, known as `VersionedXcm`. +#[derive( + Derivative, + Encode, + Decode, + TypeInfo, + xcm_procedural::XcmWeightInfoTrait, + xcm_procedural::Builder, +)] +#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] +#[codec(encode_bound())] +#[codec(decode_bound())] +#[scale_info(bounds(), skip_type_params(Call))] +pub enum Instruction { + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding + /// Register. + /// + /// - `assets`: The asset(s) to be withdrawn into holding. + /// + /// Kind: *Command*. + /// + /// Errors: + #[builder(loads_holding)] + WithdrawAsset(Assets), + + /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` + /// system and equivalent derivatives should be placed into the Holding Register. + /// + /// - `assets`: The asset(s) that are minted into holding. + /// + /// Safety: `origin` must be trusted to have received and be storing `assets` such that they + /// may later be withdrawn should this system send a corresponding message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + #[builder(loads_holding)] + ReserveAssetDeposited(Assets), + + /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should + /// be created and placed into the Holding Register. + /// + /// - `assets`: The asset(s) that are minted into the Holding Register. + /// + /// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets` + /// prior as a consequence of sending this message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + #[builder(loads_holding)] + ReceiveTeleportedAsset(Assets), + + /// Respond with information that the local system is expecting. + /// + /// - `query_id`: The identifier of the query that resulted in this message being sent. + /// - `response`: The message content. + /// - `max_weight`: The maximum weight that handling this response should take. + /// - `querier`: The location responsible for the initiation of the response, if there is one. + /// In general this will tend to be the same location as the receiver of this message. NOTE: + /// As usual, this is interpreted from the perspective of the receiving consensus system. + /// + /// Safety: Since this is information only, there are no immediate concerns. However, it should + /// be remembered that even if the Origin behaves reasonably, it can always be asked to make + /// a response to a third-party chain who may or may not be expecting the response. Therefore + /// the `querier` should be checked to match the expected value. + /// + /// Kind: *Information*. + /// + /// Errors: + QueryResponse { + #[codec(compact)] + query_id: QueryId, + response: Response, + max_weight: Weight, + querier: Option, + }, + + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets + /// under the ownership of `beneficiary`. + /// + /// - `assets`: The asset(s) to be withdrawn. + /// - `beneficiary`: The new owner for the assets. + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + /// Errors: + TransferAsset { assets: Assets, beneficiary: Location }, + + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets + /// under the ownership of `dest` within this consensus system (i.e. its sovereign account). + /// + /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given + /// `xcm`. + /// + /// - `assets`: The asset(s) to be withdrawn. + /// - `dest`: The location whose sovereign account will own the assets and thus the effective + /// beneficiary for the assets and the notification target for the reserve asset deposit + /// message. + /// - `xcm`: The instructions that should follow the `ReserveAssetDeposited` instruction, which + /// is sent onwards to `dest`. + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + /// Errors: + TransferReserveAsset { assets: Assets, dest: Location, xcm: Xcm<()> }, + + /// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed + /// by the kind of origin `origin_kind`. + /// + /// The Transact Status Register is set according to the result of dispatching the call. + /// + /// - `origin_kind`: The means of expressing the message origin as a dispatch origin. + /// - `call`: The encoded transaction to be applied. + /// - `fallback_max_weight`: Used for compatibility with previous versions. Corresponds to the + /// `require_weight_at_most` parameter in previous versions. If you don't care about + /// compatibility you can just put `None`. WARNING: If you do, your XCM might not work with + /// older versions. Make sure to dry-run and validate. + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + /// Errors: + Transact { + origin_kind: OriginKind, + fallback_max_weight: Option, + call: DoubleEncoded, + }, + + /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by + /// the relay-chain to a para. + /// + /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel + /// opening. + /// - `max_message_size`: The maximum size of a message proposed by the sender. + /// - `max_capacity`: The maximum number of messages that can be queued in the channel. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + HrmpNewChannelOpenRequest { + #[codec(compact)] + sender: u32, + #[codec(compact)] + max_message_size: u32, + #[codec(compact)] + max_capacity: u32, + }, + + /// A message to notify about that a previously sent open channel request has been accepted by + /// the recipient. That means that the channel will be opened during the next relay-chain + /// session change. This message is meant to be sent by the relay-chain to a para. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + /// + /// Errors: + HrmpChannelAccepted { + // NOTE: We keep this as a structured item to a) keep it consistent with the other Hrmp + // items; and b) because the field's meaning is not obvious/mentioned from the item name. + #[codec(compact)] + recipient: u32, + }, + + /// A message to notify that the other party in an open channel decided to close it. In + /// particular, `initiator` is going to close the channel opened from `sender` to the + /// `recipient`. The close will be enacted at the next relay-chain session change. This message + /// is meant to be sent by the relay-chain to a para. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + /// + /// Errors: + HrmpChannelClosing { + #[codec(compact)] + initiator: u32, + #[codec(compact)] + sender: u32, + #[codec(compact)] + recipient: u32, + }, + + /// Clear the origin. + /// + /// This may be used by the XCM author to ensure that later instructions cannot command the + /// authority of the origin (e.g. if they are being relayed from an untrusted source, as often + /// the case with `ReserveAssetDeposited`). + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + /// Errors: + ClearOrigin, + + /// Mutate the origin to some interior location. + /// + /// Kind: *Command* + /// + /// Errors: + DescendOrigin(InteriorLocation), + + /// Immediately report the contents of the Error Register to the given destination via XCM. + /// + /// A `QueryResponse` message of type `ExecutionOutcome` is sent to the described destination. + /// + /// - `response_info`: Information for making the response. + /// + /// Kind: *Command* + /// + /// Errors: + ReportError(QueryResponseInfo), + + /// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under + /// the ownership of `beneficiary` within this consensus system. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `beneficiary`: The new owner for the assets. + /// + /// Kind: *Command* + /// + /// Errors: + DepositAsset { assets: AssetFilter, beneficiary: Location }, + + /// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets under + /// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign + /// account). + /// + /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `dest`: The location whose sovereign account will own the assets and thus the effective + /// beneficiary for the assets and the notification target for the reserve asset deposit + /// message. + /// - `xcm`: The orders that should follow the `ReserveAssetDeposited` instruction which is + /// sent onwards to `dest`. + /// + /// Kind: *Command* + /// + /// Errors: + DepositReserveAsset { assets: AssetFilter, dest: Location, xcm: Xcm<()> }, + + /// Remove the asset(s) (`want`) from the Holding Register and replace them with alternative + /// assets. + /// + /// The minimum amount of assets to be received into the Holding Register for the order not to + /// fail may be stated. + /// + /// - `give`: The maximum amount of assets to remove from holding. + /// - `want`: The minimum amount of assets which `give` should be exchanged for. + /// - `maximal`: If `true`, then prefer to give as much as possible up to the limit of `give` + /// and receive accordingly more. If `false`, then prefer to give as little as possible in + /// order to receive as little as possible while receiving at least `want`. + /// + /// Kind: *Command* + /// + /// Errors: + ExchangeAsset { give: AssetFilter, want: Assets, maximal: bool }, + + /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a + /// reserve location. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The + /// sovereign account of this consensus system *on the reserve location* will have + /// appropriate assets withdrawn and `effects` will be executed on them. There will typically + /// be only one valid location on any given asset/chain combination. + /// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve + /// location*. + /// + /// Kind: *Command* + /// + /// Errors: + InitiateReserveWithdraw { assets: AssetFilter, reserve: Location, xcm: Xcm<()> }, + + /// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message + /// to a `dest` location. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `dest`: A valid location that respects teleports coming from this location. + /// - `xcm`: The instructions to execute on the assets once arrived *on the destination + /// location*. + /// + /// NOTE: The `dest` location *MUST* respect this origin as a valid teleportation origin for + /// all `assets`. If it does not, then the assets may be lost. + /// + /// Kind: *Command* + /// + /// Errors: + InitiateTeleport { assets: AssetFilter, dest: Location, xcm: Xcm<()> }, + + /// Report to a given destination the contents of the Holding Register. + /// + /// A `QueryResponse` message of type `Assets` is sent to the described destination. + /// + /// - `response_info`: Information for making the response. + /// - `assets`: A filter for the assets that should be reported back. The assets reported back + /// will be, asset-wise, *the lesser of this value and the holding register*. No wildcards + /// will be used when reporting assets back. + /// + /// Kind: *Command* + /// + /// Errors: + ReportHolding { response_info: QueryResponseInfo, assets: AssetFilter }, + + /// Pay for the execution of some XCM `xcm` and `orders` with up to `weight` + /// picoseconds of execution time, paying for this with up to `fees` from the Holding Register. + /// + /// - `fees`: The asset(s) to remove from the Holding Register to pay for fees. + /// - `weight_limit`: The maximum amount of weight to purchase; this must be at least the + /// expected maximum weight of the total XCM to be executed for the + /// `AllowTopLevelPaidExecutionFrom` barrier to allow the XCM be executed. + /// + /// Kind: *Command* + /// + /// Errors: + #[builder(pays_fees)] + BuyExecution { fees: Asset, weight_limit: WeightLimit }, + + /// Refund any surplus weight previously bought with `BuyExecution`. + /// + /// Kind: *Command* + /// + /// Errors: None. + RefundSurplus, + + /// Set the Error Handler Register. This is code that should be called in the case of an error + /// happening. + /// + /// An error occurring within execution of this code will _NOT_ result in the error register + /// being set, nor will an error handler be called due to it. The error handler and appendix + /// may each still be set. + /// + /// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing + /// weight however includes only the difference between the previous handler and the new + /// handler, which can reasonably be negative, which would result in a surplus. + /// + /// Kind: *Command* + /// + /// Errors: None. + SetErrorHandler(Xcm), + + /// Set the Appendix Register. This is code that should be called after code execution + /// (including the error handler if any) is finished. This will be called regardless of whether + /// an error occurred. + /// + /// Any error occurring due to execution of this code will result in the error register being + /// set, and the error handler (if set) firing. + /// + /// The apparent weight of this instruction is inclusive of the inner `Xcm`; the executing + /// weight however includes only the difference between the previous appendix and the new + /// appendix, which can reasonably be negative, which would result in a surplus. + /// + /// Kind: *Command* + /// + /// Errors: None. + SetAppendix(Xcm), + + /// Clear the Error Register. + /// + /// Kind: *Command* + /// + /// Errors: None. + ClearError, + + /// Create some assets which are being held on behalf of the origin. + /// + /// - `assets`: The assets which are to be claimed. This must match exactly with the assets + /// claimable by the origin of the ticket. + /// - `ticket`: The ticket of the asset; this is an abstract identifier to help locate the + /// asset. + /// + /// Kind: *Command* + /// + /// Errors: + #[builder(loads_holding)] + ClaimAsset { assets: Assets, ticket: Location }, + + /// Always throws an error of type `Trap`. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `Trap`: All circumstances, whose inner value is the same as this item's inner value. + Trap(#[codec(compact)] u64), + + /// Ask the destination system to respond with the most recent version of XCM that they + /// support in a `QueryResponse` instruction. Any changes to this should also elicit similar + /// responses when they happen. + /// + /// - `query_id`: An identifier that will be replicated into the returned XCM message. + /// - `max_response_weight`: The maximum amount of weight that the `QueryResponse` item which + /// is sent as a reply may take to execute. NOTE: If this is unexpectedly large then the + /// response may not execute at all. + /// + /// Kind: *Command* + /// + /// Errors: *Fallible* + SubscribeVersion { + #[codec(compact)] + query_id: QueryId, + max_response_weight: Weight, + }, + + /// Cancel the effect of a previous `SubscribeVersion` instruction. + /// + /// Kind: *Command* + /// + /// Errors: *Fallible* + UnsubscribeVersion, + + /// Reduce Holding by up to the given assets. + /// + /// Holding is reduced by as much as possible up to the assets in the parameter. It is not an + /// error if the Holding does not contain the assets (to make this an error, use `ExpectAsset` + /// prior). + /// + /// Kind: *Command* + /// + /// Errors: *Infallible* + BurnAsset(Assets), + + /// Throw an error if Holding does not contain at least the given assets. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `ExpectationFalse`: If Holding Register does not contain the assets in the parameter. + ExpectAsset(Assets), + + /// Ensure that the Origin Register equals some given value and throw an error if not. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `ExpectationFalse`: If Origin Register is not equal to the parameter. + ExpectOrigin(Option), + + /// Ensure that the Error Register equals some given value and throw an error if not. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `ExpectationFalse`: If the value of the Error Register is not equal to the parameter. + ExpectError(Option<(u32, Error)>), + + /// Ensure that the Transact Status Register equals some given value and throw an error if + /// not. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the + /// parameter. + ExpectTransactStatus(MaybeErrorCode), + + /// Query the existence of a particular pallet type. + /// + /// - `module_name`: The module name of the pallet to query. + /// - `response_info`: Information for making the response. + /// + /// Sends a `QueryResponse` to Origin whose data field `PalletsInfo` containing the information + /// of all pallets on the local chain whose name is equal to `name`. This is empty in the case + /// that the local chain is not based on Substrate Frame. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + /// + /// Errors: *Fallible*. + QueryPallet { module_name: Vec, response_info: QueryResponseInfo }, + + /// Ensure that a particular pallet with a particular version exists. + /// + /// - `index: Compact`: The index which identifies the pallet. An error if no pallet exists at + /// this index. + /// - `name: Vec`: Name which must be equal to the name of the pallet. + /// - `module_name: Vec`: Module name which must be equal to the name of the module in + /// which the pallet exists. + /// - `crate_major: Compact`: Version number which must be equal to the major version of the + /// crate which implements the pallet. + /// - `min_crate_minor: Compact`: Version number which must be at most the minor version of the + /// crate which implements the pallet. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `ExpectationFalse`: In case any of the expectations are broken. + ExpectPallet { + #[codec(compact)] + index: u32, + name: Vec, + module_name: Vec, + #[codec(compact)] + crate_major: u32, + #[codec(compact)] + min_crate_minor: u32, + }, + + /// Send a `QueryResponse` message containing the value of the Transact Status Register to some + /// destination. + /// + /// - `query_response_info`: The information needed for constructing and sending the + /// `QueryResponse` message. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + /// + /// Errors: *Fallible*. + ReportTransactStatus(QueryResponseInfo), + + /// Set the Transact Status Register to its default, cleared, value. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + /// + /// Errors: *Infallible*. + ClearTransactStatus, + + /// Set the Origin Register to be some child of the Universal Ancestor. + /// + /// Safety: Should only be usable if the Origin is trusted to represent the Universal Ancestor + /// child in general. In general, no Origin should be able to represent the Universal Ancestor + /// child which is the root of the local consensus system since it would by extension + /// allow it to act as any location within the local consensus. + /// + /// The `Junction` parameter should generally be a `GlobalConsensus` variant since it is only + /// these which are children of the Universal Ancestor. + /// + /// Kind: *Command* + /// + /// Errors: *Fallible*. + UniversalOrigin(Junction), + + /// Send a message on to Non-Local Consensus system. + /// + /// This will tend to utilize some extra-consensus mechanism, the obvious one being a bridge. + /// A fee may be charged; this may be determined based on the contents of `xcm`. It will be + /// taken from the Holding register. + /// + /// - `network`: The remote consensus system to which the message should be exported. + /// - `destination`: The location relative to the remote consensus system to which the message + /// should be sent on arrival. + /// - `xcm`: The message to be exported. + /// + /// As an example, to export a message for execution on Statemine (parachain #1000 in the + /// Kusama network), you would call with `network: NetworkId::Kusama` and + /// `destination: [Parachain(1000)].into()`. Alternatively, to export a message for execution + /// on Polkadot, you would call with `network: NetworkId:: Polkadot` and `destination: Here`. + /// + /// Kind: *Command* + /// + /// Errors: *Fallible*. + ExportMessage { network: NetworkId, destination: InteriorLocation, xcm: Xcm<()> }, + + /// Lock the locally held asset and prevent further transfer or withdrawal. + /// + /// This restriction may be removed by the `UnlockAsset` instruction being called with an + /// Origin of `unlocker` and a `target` equal to the current `Origin`. + /// + /// If the locking is successful, then a `NoteUnlockable` instruction is sent to `unlocker`. + /// + /// - `asset`: The asset(s) which should be locked. + /// - `unlocker`: The value which the Origin must be for a corresponding `UnlockAsset` + /// instruction to work. + /// + /// Kind: *Command*. + /// + /// Errors: + LockAsset { asset: Asset, unlocker: Location }, + + /// Remove the lock over `asset` on this chain and (if nothing else is preventing it) allow the + /// asset to be transferred. + /// + /// - `asset`: The asset to be unlocked. + /// - `target`: The owner of the asset on the local chain. + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + /// Errors: + UnlockAsset { asset: Asset, target: Location }, + + /// Asset (`asset`) has been locked on the `origin` system and may not be transferred. It may + /// only be unlocked with the receipt of the `UnlockAsset` instruction from this chain. + /// + /// - `asset`: The asset(s) which are now unlockable from this origin. + /// - `owner`: The owner of the asset on the chain in which it was locked. This may be a + /// location specific to the origin network. + /// + /// Safety: `origin` must be trusted to have locked the corresponding `asset` + /// prior as a consequence of sending this message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + NoteUnlockable { asset: Asset, owner: Location }, + + /// Send an `UnlockAsset` instruction to the `locker` for the given `asset`. + /// + /// This may fail if the local system is making use of the fact that the asset is locked or, + /// of course, if there is no record that the asset actually is locked. + /// + /// - `asset`: The asset(s) to be unlocked. + /// - `locker`: The location from which a previous `NoteUnlockable` was sent and to which an + /// `UnlockAsset` should be sent. + /// + /// Kind: *Command*. + /// + /// Errors: + RequestUnlock { asset: Asset, locker: Location }, + + /// Sets the Fees Mode Register. + /// + /// - `jit_withdraw`: The fees mode item; if set to `true` then fees for any instructions are + /// withdrawn as needed using the same mechanism as `WithdrawAssets`. + /// + /// Kind: *Command*. + /// + /// Errors: + SetFeesMode { jit_withdraw: bool }, + + /// Set the Topic Register. + /// + /// The 32-byte array identifier in the parameter is not guaranteed to be + /// unique; if such a property is desired, it is up to the code author to + /// enforce uniqueness. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + /// + /// Errors: + SetTopic([u8; 32]), + + /// Clear the Topic Register. + /// + /// Kind: *Command* + /// + /// Errors: None. + ClearTopic, + + /// Alter the current Origin to another given origin. + /// + /// Kind: *Command* + /// + /// Errors: If the existing state would not allow such a change. + AliasOrigin(Location), + + /// A directive to indicate that the origin expects free execution of the message. + /// + /// At execution time, this instruction just does a check on the Origin register. + /// However, at the barrier stage messages starting with this instruction can be disregarded if + /// the origin is not acceptable for free execution or the `weight_limit` is `Limited` and + /// insufficient. + /// + /// Kind: *Indication* + /// + /// Errors: If the given origin is `Some` and not equal to the current Origin register. + UnpaidExecution { weight_limit: WeightLimit, check_origin: Option }, + + /// Pay Fees. + /// + /// Successor to `BuyExecution`. + /// Defined in fellowship RFC 105. + #[builder(pays_fees)] + PayFees { asset: Asset }, + + /// Initiates cross-chain transfer as follows: + /// + /// Assets in the holding register are matched using the given list of `AssetTransferFilter`s, + /// they are then transferred based on their specified transfer type: + /// + /// - teleport: burn local assets and append a `ReceiveTeleportedAsset` XCM instruction to the + /// XCM program to be sent onward to the `destination` location, + /// + /// - reserve deposit: place assets under the ownership of `destination` within this consensus + /// system (i.e. its sovereign account), and append a `ReserveAssetDeposited` XCM instruction + /// to the XCM program to be sent onward to the `destination` location, + /// + /// - reserve withdraw: burn local assets and append a `WithdrawAsset` XCM instruction to the + /// XCM program to be sent onward to the `destination` location, + /// + /// The onward XCM is then appended a `ClearOrigin` to allow safe execution of any following + /// custom XCM instructions provided in `remote_xcm`. + /// + /// The onward XCM also contains either a `PayFees` or `UnpaidExecution` instruction based + /// on the presence of the `remote_fees` parameter (see below). + /// + /// If an XCM program requires going through multiple hops, it can compose this instruction to + /// be used at every chain along the path, describing that specific leg of the flow. + /// + /// Parameters: + /// - `destination`: The location of the program next hop. + /// - `remote_fees`: If set to `Some(asset_xfer_filter)`, the single asset matching + /// `asset_xfer_filter` in the holding register will be transferred first in the remote XCM + /// program, followed by a `PayFees(fee)`, then rest of transfers follow. This guarantees + /// `remote_xcm` will successfully pass a `AllowTopLevelPaidExecutionFrom` barrier. If set to + /// `None`, a `UnpaidExecution` instruction is appended instead. Please note that these + /// assets are **reserved** for fees, they are sent to the fees register rather than holding. + /// Best practice is to only add here enough to cover fees, and transfer the rest through the + /// `assets` parameter. + /// - `preserve_origin`: Specifies whether the original origin should be preserved or cleared, + /// using the instructions `AliasOrigin` or `ClearOrigin` respectively. + /// - `assets`: List of asset filters matched against existing assets in holding. These are + /// transferred over to `destination` using the specified transfer type, and deposited to + /// holding on `destination`. + /// - `remote_xcm`: Custom instructions that will be executed on the `destination` chain. Note + /// that these instructions will be executed after a `ClearOrigin` so their origin will be + /// `None`. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + InitiateTransfer { + destination: Location, + remote_fees: Option, + preserve_origin: bool, + assets: Vec, + remote_xcm: Xcm<()>, + }, + + /// Executes inner `xcm` with origin set to the provided `descendant_origin`. Once the inner + /// `xcm` is executed, the original origin (the one active for this instruction) is restored. + /// + /// Parameters: + /// - `descendant_origin`: The origin that will be used during the execution of the inner + /// `xcm`. If set to `None`, the inner `xcm` is executed with no origin. If set to `Some(o)`, + /// the inner `xcm` is executed as if there was a `DescendOrigin(o)` executed before it, and + /// runs the inner xcm with origin: `original_origin.append_with(o)`. + /// - `xcm`: Inner instructions that will be executed with the origin modified according to + /// `descendant_origin`. + /// + /// Safety: No concerns. + /// + /// Kind: *Command* + /// + /// Errors: + /// - `BadOrigin` + ExecuteWithOrigin { descendant_origin: Option, xcm: Xcm }, + + /// Set hints for XCM execution. + /// + /// These hints change the behaviour of the XCM program they are present in. + /// + /// Parameters: + /// + /// - `hints`: A bounded vector of `ExecutionHint`, specifying the different hints that will + /// be activated. + SetHints { hints: BoundedVec }, +} + +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Eq, Clone, xcm_procedural::NumVariants)] +pub enum Hint { + /// Set asset claimer for all the trapped assets during the execution. + /// + /// - `location`: The claimer of any assets potentially trapped during the execution of current + /// XCM. It can be an arbitrary location, not necessarily the caller or origin. + AssetClaimer { location: Location }, +} + +impl Xcm { + pub fn into(self) -> Xcm { + Xcm::from(self) + } + pub fn from(xcm: Xcm) -> Self { + Self(xcm.0.into_iter().map(Instruction::::from).collect()) + } +} + +impl Instruction { + pub fn into(self) -> Instruction { + Instruction::from(self) + } + pub fn from(xcm: Instruction) -> Self { + use Instruction::*; + match xcm { + WithdrawAsset(assets) => WithdrawAsset(assets), + ReserveAssetDeposited(assets) => ReserveAssetDeposited(assets), + ReceiveTeleportedAsset(assets) => ReceiveTeleportedAsset(assets), + QueryResponse { query_id, response, max_weight, querier } => + QueryResponse { query_id, response, max_weight, querier }, + TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary }, + TransferReserveAsset { assets, dest, xcm } => + TransferReserveAsset { assets, dest, xcm }, + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, + HrmpChannelClosing { initiator, sender, recipient } => + HrmpChannelClosing { initiator, sender, recipient }, + Transact { origin_kind, call, fallback_max_weight } => + Transact { origin_kind, call: call.into(), fallback_max_weight }, + ReportError(response_info) => ReportError(response_info), + DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary }, + DepositReserveAsset { assets, dest, xcm } => DepositReserveAsset { assets, dest, xcm }, + ExchangeAsset { give, want, maximal } => ExchangeAsset { give, want, maximal }, + InitiateReserveWithdraw { assets, reserve, xcm } => + InitiateReserveWithdraw { assets, reserve, xcm }, + InitiateTeleport { assets, dest, xcm } => InitiateTeleport { assets, dest, xcm }, + ReportHolding { response_info, assets } => ReportHolding { response_info, assets }, + BuyExecution { fees, weight_limit } => BuyExecution { fees, weight_limit }, + ClearOrigin => ClearOrigin, + DescendOrigin(who) => DescendOrigin(who), + RefundSurplus => RefundSurplus, + SetErrorHandler(xcm) => SetErrorHandler(xcm.into()), + SetAppendix(xcm) => SetAppendix(xcm.into()), + ClearError => ClearError, + SetHints { hints } => SetHints { hints }, + ClaimAsset { assets, ticket } => ClaimAsset { assets, ticket }, + Trap(code) => Trap(code), + SubscribeVersion { query_id, max_response_weight } => + SubscribeVersion { query_id, max_response_weight }, + UnsubscribeVersion => UnsubscribeVersion, + BurnAsset(assets) => BurnAsset(assets), + ExpectAsset(assets) => ExpectAsset(assets), + ExpectOrigin(origin) => ExpectOrigin(origin), + ExpectError(error) => ExpectError(error), + ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status), + QueryPallet { module_name, response_info } => + QueryPallet { module_name, response_info }, + ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => + ExpectPallet { index, name, module_name, crate_major, min_crate_minor }, + ReportTransactStatus(response_info) => ReportTransactStatus(response_info), + ClearTransactStatus => ClearTransactStatus, + UniversalOrigin(j) => UniversalOrigin(j), + ExportMessage { network, destination, xcm } => + ExportMessage { network, destination, xcm }, + LockAsset { asset, unlocker } => LockAsset { asset, unlocker }, + UnlockAsset { asset, target } => UnlockAsset { asset, target }, + NoteUnlockable { asset, owner } => NoteUnlockable { asset, owner }, + RequestUnlock { asset, locker } => RequestUnlock { asset, locker }, + SetFeesMode { jit_withdraw } => SetFeesMode { jit_withdraw }, + SetTopic(topic) => SetTopic(topic), + ClearTopic => ClearTopic, + AliasOrigin(location) => AliasOrigin(location), + UnpaidExecution { weight_limit, check_origin } => + UnpaidExecution { weight_limit, check_origin }, + PayFees { asset } => PayFees { asset }, + InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } => + InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm }, + ExecuteWithOrigin { descendant_origin, xcm } => + ExecuteWithOrigin { descendant_origin, xcm: xcm.into() }, + } + } +} + +// TODO: Automate Generation +impl> GetWeight for Instruction { + fn weight(&self) -> Weight { + use Instruction::*; + match self { + WithdrawAsset(assets) => W::withdraw_asset(assets), + ReserveAssetDeposited(assets) => W::reserve_asset_deposited(assets), + ReceiveTeleportedAsset(assets) => W::receive_teleported_asset(assets), + QueryResponse { query_id, response, max_weight, querier } => + W::query_response(query_id, response, max_weight, querier), + TransferAsset { assets, beneficiary } => W::transfer_asset(assets, beneficiary), + TransferReserveAsset { assets, dest, xcm } => + W::transfer_reserve_asset(&assets, dest, xcm), + Transact { origin_kind, fallback_max_weight, call } => + W::transact(origin_kind, fallback_max_weight, call), + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + W::hrmp_new_channel_open_request(sender, max_message_size, max_capacity), + HrmpChannelAccepted { recipient } => W::hrmp_channel_accepted(recipient), + HrmpChannelClosing { initiator, sender, recipient } => + W::hrmp_channel_closing(initiator, sender, recipient), + ClearOrigin => W::clear_origin(), + DescendOrigin(who) => W::descend_origin(who), + ReportError(response_info) => W::report_error(&response_info), + DepositAsset { assets, beneficiary } => W::deposit_asset(assets, beneficiary), + DepositReserveAsset { assets, dest, xcm } => + W::deposit_reserve_asset(assets, dest, xcm), + ExchangeAsset { give, want, maximal } => W::exchange_asset(give, want, maximal), + InitiateReserveWithdraw { assets, reserve, xcm } => + W::initiate_reserve_withdraw(assets, reserve, xcm), + InitiateTeleport { assets, dest, xcm } => W::initiate_teleport(assets, dest, xcm), + ReportHolding { response_info, assets } => W::report_holding(&response_info, &assets), + BuyExecution { fees, weight_limit } => W::buy_execution(fees, weight_limit), + RefundSurplus => W::refund_surplus(), + SetErrorHandler(xcm) => W::set_error_handler(xcm), + SetAppendix(xcm) => W::set_appendix(xcm), + ClearError => W::clear_error(), + SetHints { hints } => W::set_hints(hints), + ClaimAsset { assets, ticket } => W::claim_asset(assets, ticket), + Trap(code) => W::trap(code), + SubscribeVersion { query_id, max_response_weight } => + W::subscribe_version(query_id, max_response_weight), + UnsubscribeVersion => W::unsubscribe_version(), + BurnAsset(assets) => W::burn_asset(assets), + ExpectAsset(assets) => W::expect_asset(assets), + ExpectOrigin(origin) => W::expect_origin(origin), + ExpectError(error) => W::expect_error(error), + ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status), + QueryPallet { module_name, response_info } => + W::query_pallet(module_name, response_info), + ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => + W::expect_pallet(index, name, module_name, crate_major, min_crate_minor), + ReportTransactStatus(response_info) => W::report_transact_status(response_info), + ClearTransactStatus => W::clear_transact_status(), + UniversalOrigin(j) => W::universal_origin(j), + ExportMessage { network, destination, xcm } => + W::export_message(network, destination, xcm), + LockAsset { asset, unlocker } => W::lock_asset(asset, unlocker), + UnlockAsset { asset, target } => W::unlock_asset(asset, target), + NoteUnlockable { asset, owner } => W::note_unlockable(asset, owner), + RequestUnlock { asset, locker } => W::request_unlock(asset, locker), + SetFeesMode { jit_withdraw } => W::set_fees_mode(jit_withdraw), + SetTopic(topic) => W::set_topic(topic), + ClearTopic => W::clear_topic(), + AliasOrigin(location) => W::alias_origin(location), + UnpaidExecution { weight_limit, check_origin } => + W::unpaid_execution(weight_limit, check_origin), + PayFees { asset } => W::pay_fees(asset), + InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } => + W::initiate_transfer(destination, remote_fees, preserve_origin, assets, remote_xcm), + ExecuteWithOrigin { descendant_origin, xcm } => + W::execute_with_origin(descendant_origin, xcm), + } + } +} + +pub mod opaque { + /// The basic concrete type of `Xcm`, which doesn't make any assumptions about the + /// format of a call other than it is pre-encoded. + pub type Xcm = super::Xcm<()>; + + /// The basic concrete type of `Instruction`, which doesn't make any assumptions about the + /// format of a call other than it is pre-encoded. + pub type Instruction = super::Instruction<()>; +} + +// Convert from a v4 XCM to a v5 XCM +impl TryFrom> for Xcm { + type Error = (); + fn try_from(old_xcm: OldXcm) -> result::Result { + Ok(Xcm(old_xcm.0.into_iter().map(TryInto::try_into).collect::>()?)) + } +} + +// Convert from a v4 instruction to a v5 instruction +impl TryFrom> for Instruction { + type Error = (); + fn try_from(old_instruction: OldInstruction) -> result::Result { + use OldInstruction::*; + Ok(match old_instruction { + WithdrawAsset(assets) => Self::WithdrawAsset(assets.try_into()?), + ReserveAssetDeposited(assets) => Self::ReserveAssetDeposited(assets.try_into()?), + ReceiveTeleportedAsset(assets) => Self::ReceiveTeleportedAsset(assets.try_into()?), + QueryResponse { query_id, response, max_weight, querier: Some(querier) } => + Self::QueryResponse { + query_id, + querier: querier.try_into()?, + response: response.try_into()?, + max_weight, + }, + QueryResponse { query_id, response, max_weight, querier: None } => + Self::QueryResponse { + query_id, + querier: None, + response: response.try_into()?, + max_weight, + }, + TransferAsset { assets, beneficiary } => Self::TransferAsset { + assets: assets.try_into()?, + beneficiary: beneficiary.try_into()?, + }, + TransferReserveAsset { assets, dest, xcm } => Self::TransferReserveAsset { + assets: assets.try_into()?, + dest: dest.try_into()?, + xcm: xcm.try_into()?, + }, + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + Self::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + HrmpChannelAccepted { recipient } => Self::HrmpChannelAccepted { recipient }, + HrmpChannelClosing { initiator, sender, recipient } => + Self::HrmpChannelClosing { initiator, sender, recipient }, + Transact { origin_kind, require_weight_at_most, call } => Self::Transact { + origin_kind, + call: call.into(), + fallback_max_weight: Some(require_weight_at_most), + }, + ReportError(response_info) => Self::ReportError(QueryResponseInfo { + query_id: response_info.query_id, + destination: response_info.destination.try_into().map_err(|_| ())?, + max_weight: response_info.max_weight, + }), + DepositAsset { assets, beneficiary } => { + let beneficiary = beneficiary.try_into()?; + let assets = assets.try_into()?; + Self::DepositAsset { assets, beneficiary } + }, + DepositReserveAsset { assets, dest, xcm } => { + let dest = dest.try_into()?; + let xcm = xcm.try_into()?; + let assets = assets.try_into()?; + Self::DepositReserveAsset { assets, dest, xcm } + }, + ExchangeAsset { give, want, maximal } => { + let give = give.try_into()?; + let want = want.try_into()?; + Self::ExchangeAsset { give, want, maximal } + }, + InitiateReserveWithdraw { assets, reserve, xcm } => { + let assets = assets.try_into()?; + let reserve = reserve.try_into()?; + let xcm = xcm.try_into()?; + Self::InitiateReserveWithdraw { assets, reserve, xcm } + }, + InitiateTeleport { assets, dest, xcm } => { + let assets = assets.try_into()?; + let dest = dest.try_into()?; + let xcm = xcm.try_into()?; + Self::InitiateTeleport { assets, dest, xcm } + }, + ReportHolding { response_info, assets } => { + let response_info = QueryResponseInfo { + destination: response_info.destination.try_into().map_err(|_| ())?, + query_id: response_info.query_id, + max_weight: response_info.max_weight, + }; + Self::ReportHolding { response_info, assets: assets.try_into()? } + }, + BuyExecution { fees, weight_limit } => { + let fees = fees.try_into()?; + let weight_limit = weight_limit.into(); + Self::BuyExecution { fees, weight_limit } + }, + ClearOrigin => Self::ClearOrigin, + DescendOrigin(who) => Self::DescendOrigin(who.try_into()?), + RefundSurplus => Self::RefundSurplus, + SetErrorHandler(xcm) => Self::SetErrorHandler(xcm.try_into()?), + SetAppendix(xcm) => Self::SetAppendix(xcm.try_into()?), + ClearError => Self::ClearError, + ClaimAsset { assets, ticket } => { + let assets = assets.try_into()?; + let ticket = ticket.try_into()?; + Self::ClaimAsset { assets, ticket } + }, + Trap(code) => Self::Trap(code), + SubscribeVersion { query_id, max_response_weight } => + Self::SubscribeVersion { query_id, max_response_weight }, + UnsubscribeVersion => Self::UnsubscribeVersion, + BurnAsset(assets) => Self::BurnAsset(assets.try_into()?), + ExpectAsset(assets) => Self::ExpectAsset(assets.try_into()?), + ExpectOrigin(maybe_location) => Self::ExpectOrigin( + maybe_location.map(|location| location.try_into()).transpose().map_err(|_| ())?, + ), + ExpectError(maybe_error) => Self::ExpectError( + maybe_error + .map(|(num, old_error)| (num, old_error.try_into())) + .map(|(num, result)| result.map(|inner| (num, inner))) + .transpose() + .map_err(|_| ())?, + ), + ExpectTransactStatus(maybe_error_code) => Self::ExpectTransactStatus(maybe_error_code), + QueryPallet { module_name, response_info } => Self::QueryPallet { + module_name, + response_info: response_info.try_into().map_err(|_| ())?, + }, + ExpectPallet { index, name, module_name, crate_major, min_crate_minor } => + Self::ExpectPallet { index, name, module_name, crate_major, min_crate_minor }, + ReportTransactStatus(response_info) => + Self::ReportTransactStatus(response_info.try_into().map_err(|_| ())?), + ClearTransactStatus => Self::ClearTransactStatus, + UniversalOrigin(junction) => + Self::UniversalOrigin(junction.try_into().map_err(|_| ())?), + ExportMessage { network, destination, xcm } => Self::ExportMessage { + network: network.into(), + destination: destination.try_into().map_err(|_| ())?, + xcm: xcm.try_into().map_err(|_| ())?, + }, + LockAsset { asset, unlocker } => Self::LockAsset { + asset: asset.try_into().map_err(|_| ())?, + unlocker: unlocker.try_into().map_err(|_| ())?, + }, + UnlockAsset { asset, target } => Self::UnlockAsset { + asset: asset.try_into().map_err(|_| ())?, + target: target.try_into().map_err(|_| ())?, + }, + NoteUnlockable { asset, owner } => Self::NoteUnlockable { + asset: asset.try_into().map_err(|_| ())?, + owner: owner.try_into().map_err(|_| ())?, + }, + RequestUnlock { asset, locker } => Self::RequestUnlock { + asset: asset.try_into().map_err(|_| ())?, + locker: locker.try_into().map_err(|_| ())?, + }, + SetFeesMode { jit_withdraw } => Self::SetFeesMode { jit_withdraw }, + SetTopic(topic) => Self::SetTopic(topic), + ClearTopic => Self::ClearTopic, + AliasOrigin(location) => Self::AliasOrigin(location.try_into().map_err(|_| ())?), + UnpaidExecution { weight_limit, check_origin } => Self::UnpaidExecution { + weight_limit, + check_origin: check_origin + .map(|location| location.try_into()) + .transpose() + .map_err(|_| ())?, + }, + }) + } +} + +#[cfg(test)] +mod tests { + use super::{prelude::*, *}; + use crate::v4::{ + AssetFilter as OldAssetFilter, Junctions::Here as OldHere, WildAsset as OldWildAsset, + }; + + #[test] + fn basic_roundtrip_works() { + let xcm = Xcm::<()>(vec![TransferAsset { + assets: (Here, 1u128).into(), + beneficiary: Here.into(), + }]); + let old_xcm = OldXcm::<()>(vec![OldInstruction::TransferAsset { + assets: (OldHere, 1u128).into(), + beneficiary: OldHere.into(), + }]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + assert_eq!(new_xcm, xcm); + } + + #[test] + fn teleport_roundtrip_works() { + let xcm = Xcm::<()>(vec![ + ReceiveTeleportedAsset((Here, 1u128).into()), + ClearOrigin, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() }, + ]); + let old_xcm: OldXcm<()> = OldXcm::<()>(vec![ + OldInstruction::ReceiveTeleportedAsset((OldHere, 1u128).into()), + OldInstruction::ClearOrigin, + OldInstruction::DepositAsset { + assets: crate::v4::AssetFilter::Wild(crate::v4::WildAsset::AllCounted(1)), + beneficiary: OldHere.into(), + }, + ]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + assert_eq!(new_xcm, xcm); + } + + #[test] + fn reserve_deposit_roundtrip_works() { + let xcm = Xcm::<()>(vec![ + ReserveAssetDeposited((Here, 1u128).into()), + ClearOrigin, + BuyExecution { + fees: (Here, 1u128).into(), + weight_limit: Some(Weight::from_parts(1, 1)).into(), + }, + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() }, + ]); + let old_xcm = OldXcm::<()>(vec![ + OldInstruction::ReserveAssetDeposited((OldHere, 1u128).into()), + OldInstruction::ClearOrigin, + OldInstruction::BuyExecution { + fees: (OldHere, 1u128).into(), + weight_limit: WeightLimit::Limited(Weight::from_parts(1, 1)), + }, + OldInstruction::DepositAsset { + assets: crate::v4::AssetFilter::Wild(crate::v4::WildAsset::AllCounted(1)), + beneficiary: OldHere.into(), + }, + ]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + assert_eq!(new_xcm, xcm); + } + + #[test] + fn deposit_asset_roundtrip_works() { + let xcm = Xcm::<()>(vec![ + WithdrawAsset((Here, 1u128).into()), + DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() }, + ]); + let old_xcm = OldXcm::<()>(vec![ + OldInstruction::WithdrawAsset((OldHere, 1u128).into()), + OldInstruction::DepositAsset { + assets: OldAssetFilter::Wild(OldWildAsset::AllCounted(1)), + beneficiary: OldHere.into(), + }, + ]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + assert_eq!(new_xcm, xcm); + } + + #[test] + fn deposit_reserve_asset_roundtrip_works() { + let xcm = Xcm::<()>(vec![ + WithdrawAsset((Here, 1u128).into()), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + dest: Here.into(), + xcm: Xcm::<()>(vec![]), + }, + ]); + let old_xcm = OldXcm::<()>(vec![ + OldInstruction::WithdrawAsset((OldHere, 1u128).into()), + OldInstruction::DepositReserveAsset { + assets: OldAssetFilter::Wild(OldWildAsset::AllCounted(1)), + dest: OldHere.into(), + xcm: OldXcm::<()>(vec![]), + }, + ]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + assert_eq!(new_xcm, xcm); + } + + #[test] + fn transact_roundtrip_works() { + // We can convert as long as there's a fallback. + let xcm = Xcm::<()>(vec![ + WithdrawAsset((Here, 1u128).into()), + Transact { + origin_kind: OriginKind::SovereignAccount, + call: vec![200, 200, 200].into(), + fallback_max_weight: Some(Weight::from_parts(1_000_000, 1_024)), + }, + ]); + let old_xcm = OldXcm::<()>(vec![ + OldInstruction::WithdrawAsset((OldHere, 1u128).into()), + OldInstruction::Transact { + origin_kind: OriginKind::SovereignAccount, + call: vec![200, 200, 200].into(), + require_weight_at_most: Weight::from_parts(1_000_000, 1_024), + }, + ]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + assert_eq!(new_xcm, xcm); + + // If we have no fallback the resulting message won't know the weight. + let xcm_without_fallback = Xcm::<()>(vec![ + WithdrawAsset((Here, 1u128).into()), + Transact { + origin_kind: OriginKind::SovereignAccount, + call: vec![200, 200, 200].into(), + fallback_max_weight: None, + }, + ]); + let old_xcm = OldXcm::<()>(vec![ + OldInstruction::WithdrawAsset((OldHere, 1u128).into()), + OldInstruction::Transact { + origin_kind: OriginKind::SovereignAccount, + call: vec![200, 200, 200].into(), + require_weight_at_most: Weight::MAX, + }, + ]); + assert_eq!(old_xcm, OldXcm::<()>::try_from(xcm_without_fallback.clone()).unwrap()); + let new_xcm: Xcm<()> = old_xcm.try_into().unwrap(); + let xcm_with_max_weight_fallback = Xcm::<()>(vec![ + WithdrawAsset((Here, 1u128).into()), + Transact { + origin_kind: OriginKind::SovereignAccount, + call: vec![200, 200, 200].into(), + fallback_max_weight: Some(Weight::MAX), + }, + ]); + assert_eq!(new_xcm, xcm_with_max_weight_fallback); + } + + #[test] + fn decoding_respects_limit() { + let max_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize]); + let encoded = max_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok()); + + let big_xcm = Xcm::<()>(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE as usize + 1]); + let encoded = big_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + + let nested_xcm = Xcm::<()>(vec![ + DepositReserveAsset { + assets: All.into(), + dest: Here.into(), + xcm: max_xcm, + }; + (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize + ]); + let encoded = nested_xcm.encode(); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + + let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]); + let encoded = even_more_nested_xcm.encode(); + assert_eq!(encoded.len(), 342530); + // This should not decode since the limit is 100 + assert_eq!(MAX_INSTRUCTIONS_TO_DECODE, 100, "precondition"); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); + } +} diff --git a/polkadot/xcm/src/v5/traits.rs b/polkadot/xcm/src/v5/traits.rs new file mode 100644 index 000000000000..79d328561428 --- /dev/null +++ b/polkadot/xcm/src/v5/traits.rs @@ -0,0 +1,537 @@ +// 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 . + +//! Cross-Consensus Message format data structures. + +pub use crate::v3::{Error as OldError, SendError, XcmHash}; +use codec::{Decode, Encode}; +use core::result; +use scale_info::TypeInfo; + +pub use sp_weights::Weight; + +use super::*; + +/// Error codes used in XCM. The first errors codes have explicit indices and are part of the XCM +/// format. Those trailing are merely part of the XCM implementation; there is no expectation that +/// they will retain the same index over time. +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +#[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] +pub enum Error { + // Errors that happen due to instructions being executed. These alone are defined in the + // XCM specification. + /// An arithmetic overflow happened. + #[codec(index = 0)] + Overflow, + /// The instruction is intentionally unsupported. + #[codec(index = 1)] + Unimplemented, + /// Origin Register does not contain a value value for a reserve transfer notification. + #[codec(index = 2)] + UntrustedReserveLocation, + /// Origin Register does not contain a value value for a teleport notification. + #[codec(index = 3)] + UntrustedTeleportLocation, + /// `MultiLocation` value too large to descend further. + #[codec(index = 4)] + LocationFull, + /// `MultiLocation` value ascend more parents than known ancestors of local location. + #[codec(index = 5)] + LocationNotInvertible, + /// The Origin Register does not contain a valid value for instruction. + #[codec(index = 6)] + BadOrigin, + /// The location parameter is not a valid value for the instruction. + #[codec(index = 7)] + InvalidLocation, + /// The given asset is not handled. + #[codec(index = 8)] + AssetNotFound, + /// An asset transaction (like withdraw or deposit) failed (typically due to type conversions). + #[codec(index = 9)] + FailedToTransactAsset(#[codec(skip)] &'static str), + /// An asset cannot be withdrawn, potentially due to lack of ownership, availability or rights. + #[codec(index = 10)] + NotWithdrawable, + /// An asset cannot be deposited under the ownership of a particular location. + #[codec(index = 11)] + LocationCannotHold, + /// Attempt to send a message greater than the maximum supported by the transport protocol. + #[codec(index = 12)] + ExceedsMaxMessageSize, + /// The given message cannot be translated into a format supported by the destination. + #[codec(index = 13)] + DestinationUnsupported, + /// Destination is routable, but there is some issue with the transport mechanism. + #[codec(index = 14)] + Transport(#[codec(skip)] &'static str), + /// Destination is known to be unroutable. + #[codec(index = 15)] + Unroutable, + /// Used by `ClaimAsset` when the given claim could not be recognized/found. + #[codec(index = 16)] + UnknownClaim, + /// Used by `Transact` when the functor cannot be decoded. + #[codec(index = 17)] + FailedToDecode, + /// Used by `Transact` to indicate that the given weight limit could be breached by the + /// functor. + #[codec(index = 18)] + MaxWeightInvalid, + /// Used by `BuyExecution` when the Holding Register does not contain payable fees. + #[codec(index = 19)] + NotHoldingFees, + /// Used by `BuyExecution` when the fees declared to purchase weight are insufficient. + #[codec(index = 20)] + TooExpensive, + /// Used by the `Trap` instruction to force an error intentionally. Its code is included. + #[codec(index = 21)] + Trap(u64), + /// Used by `ExpectAsset`, `ExpectError` and `ExpectOrigin` when the expectation was not true. + #[codec(index = 22)] + ExpectationFalse, + /// The provided pallet index was not found. + #[codec(index = 23)] + PalletNotFound, + /// The given pallet's name is different to that expected. + #[codec(index = 24)] + NameMismatch, + /// The given pallet's version has an incompatible version to that expected. + #[codec(index = 25)] + VersionIncompatible, + /// The given operation would lead to an overflow of the Holding Register. + #[codec(index = 26)] + HoldingWouldOverflow, + /// The message was unable to be exported. + #[codec(index = 27)] + ExportError, + /// `MultiLocation` value failed to be reanchored. + #[codec(index = 28)] + ReanchorFailed, + /// No deal is possible under the given constraints. + #[codec(index = 29)] + NoDeal, + /// Fees were required which the origin could not pay. + #[codec(index = 30)] + FeesNotMet, + /// Some other error with locking. + #[codec(index = 31)] + LockError, + /// The state was not in a condition where the operation was valid to make. + #[codec(index = 32)] + NoPermission, + /// The universal location of the local consensus is improper. + #[codec(index = 33)] + Unanchored, + /// An asset cannot be deposited, probably because (too much of) it already exists. + #[codec(index = 34)] + NotDepositable, + /// Too many assets matched the given asset filter. + #[codec(index = 35)] + TooManyAssets, + + // Errors that happen prior to instructions being executed. These fall outside of the XCM + // spec. + /// XCM version not able to be handled. + UnhandledXcmVersion, + /// Execution of the XCM would potentially result in a greater weight used than weight limit. + WeightLimitReached(Weight), + /// The XCM did not pass the barrier condition for execution. + /// + /// The barrier condition differs on different chains and in different circumstances, but + /// generally it means that the conditions surrounding the message were not such that the chain + /// considers the message worth spending time executing. Since most chains lift the barrier to + /// execution on appropriate payment, presentation of an NFT voucher, or based on the message + /// origin, it means that none of those were the case. + Barrier, + /// The weight of an XCM message is not computable ahead of execution. + WeightNotComputable, + /// Recursion stack limit reached + // TODO(https://github.com/paritytech/polkadot-sdk/issues/6199): This should have a fixed index since + // we use it in `FrameTransactionalProcessor` // which is used in instructions. + // Or we should create a different error for that. + ExceedsStackLimit, +} + +impl TryFrom for Error { + type Error = (); + fn try_from(old_error: OldError) -> result::Result { + use OldError::*; + Ok(match old_error { + Overflow => Self::Overflow, + Unimplemented => Self::Unimplemented, + UntrustedReserveLocation => Self::UntrustedReserveLocation, + UntrustedTeleportLocation => Self::UntrustedTeleportLocation, + LocationFull => Self::LocationFull, + LocationNotInvertible => Self::LocationNotInvertible, + BadOrigin => Self::BadOrigin, + InvalidLocation => Self::InvalidLocation, + AssetNotFound => Self::AssetNotFound, + FailedToTransactAsset(s) => Self::FailedToTransactAsset(s), + NotWithdrawable => Self::NotWithdrawable, + LocationCannotHold => Self::LocationCannotHold, + ExceedsMaxMessageSize => Self::ExceedsMaxMessageSize, + DestinationUnsupported => Self::DestinationUnsupported, + Transport(s) => Self::Transport(s), + Unroutable => Self::Unroutable, + UnknownClaim => Self::UnknownClaim, + FailedToDecode => Self::FailedToDecode, + MaxWeightInvalid => Self::MaxWeightInvalid, + NotHoldingFees => Self::NotHoldingFees, + TooExpensive => Self::TooExpensive, + Trap(i) => Self::Trap(i), + ExpectationFalse => Self::ExpectationFalse, + PalletNotFound => Self::PalletNotFound, + NameMismatch => Self::NameMismatch, + VersionIncompatible => Self::VersionIncompatible, + HoldingWouldOverflow => Self::HoldingWouldOverflow, + ExportError => Self::ExportError, + ReanchorFailed => Self::ReanchorFailed, + NoDeal => Self::NoDeal, + FeesNotMet => Self::FeesNotMet, + LockError => Self::LockError, + NoPermission => Self::NoPermission, + Unanchored => Self::Unanchored, + NotDepositable => Self::NotDepositable, + UnhandledXcmVersion => Self::UnhandledXcmVersion, + WeightLimitReached(weight) => Self::WeightLimitReached(weight), + Barrier => Self::Barrier, + WeightNotComputable => Self::WeightNotComputable, + ExceedsStackLimit => Self::ExceedsStackLimit, + }) + } +} + +impl MaxEncodedLen for Error { + fn max_encoded_len() -> usize { + // TODO: max_encoded_len doesn't quite work here as it tries to take notice of the fields + // marked `codec(skip)`. We can hard-code it with the right answer for now. + 1 + } +} + +impl From for Error { + fn from(e: SendError) -> Self { + match e { + SendError::NotApplicable | SendError::Unroutable | SendError::MissingArgument => + Error::Unroutable, + SendError::Transport(s) => Error::Transport(s), + SendError::DestinationUnsupported => Error::DestinationUnsupported, + SendError::ExceedsMaxMessageSize => Error::ExceedsMaxMessageSize, + SendError::Fees => Error::FeesNotMet, + } + } +} + +pub type Result = result::Result<(), Error>; + +/// Outcome of an XCM execution. +#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Outcome { + /// Execution completed successfully; given weight was used. + Complete { used: Weight }, + /// Execution started, but did not complete successfully due to the given error; given weight + /// was used. + Incomplete { used: Weight, error: Error }, + /// Execution did not start due to the given error. + Error { error: Error }, +} + +impl Outcome { + pub fn ensure_complete(self) -> Result { + match self { + Outcome::Complete { .. } => Ok(()), + Outcome::Incomplete { error, .. } => Err(error), + Outcome::Error { error, .. } => Err(error), + } + } + pub fn ensure_execution(self) -> result::Result { + match self { + Outcome::Complete { used, .. } => Ok(used), + Outcome::Incomplete { used, .. } => Ok(used), + Outcome::Error { error, .. } => Err(error), + } + } + /// How much weight was used by the XCM execution attempt. + pub fn weight_used(&self) -> Weight { + match self { + Outcome::Complete { used, .. } => *used, + Outcome::Incomplete { used, .. } => *used, + Outcome::Error { .. } => Weight::zero(), + } + } +} + +impl From for Outcome { + fn from(error: Error) -> Self { + Self::Error { error } + } +} + +pub trait PreparedMessage { + fn weight_of(&self) -> Weight; +} + +/// Type of XCM message executor. +pub trait ExecuteXcm { + type Prepared: PreparedMessage; + fn prepare(message: Xcm) -> result::Result>; + fn execute( + origin: impl Into, + pre: Self::Prepared, + id: &mut XcmHash, + weight_credit: Weight, + ) -> Outcome; + fn prepare_and_execute( + origin: impl Into, + message: Xcm, + id: &mut XcmHash, + weight_limit: Weight, + weight_credit: Weight, + ) -> Outcome { + let pre = match Self::prepare(message) { + Ok(x) => x, + Err(_) => return Outcome::Error { error: Error::WeightNotComputable }, + }; + let xcm_weight = pre.weight_of(); + if xcm_weight.any_gt(weight_limit) { + return Outcome::Error { error: Error::WeightLimitReached(xcm_weight) } + } + Self::execute(origin, pre, id, weight_credit) + } + + /// Deduct some `fees` to the sovereign account of the given `location` and place them as per + /// the convention for fees. + fn charge_fees(location: impl Into, fees: Assets) -> Result; +} + +pub enum Weightless {} +impl PreparedMessage for Weightless { + fn weight_of(&self) -> Weight { + unreachable!() + } +} + +impl ExecuteXcm for () { + type Prepared = Weightless; + fn prepare(message: Xcm) -> result::Result> { + Err(message) + } + fn execute(_: impl Into, _: Self::Prepared, _: &mut XcmHash, _: Weight) -> Outcome { + unreachable!() + } + fn charge_fees(_location: impl Into, _fees: Assets) -> Result { + Err(Error::Unimplemented) + } +} + +pub trait Reanchorable: Sized { + /// Type to return in case of an error. + type Error: Debug; + + /// Mutate `self` so that it represents the same location from the point of view of `target`. + /// The context of `self` is provided as `context`. + /// + /// Does not modify `self` in case of overflow. + fn reanchor( + &mut self, + target: &Location, + context: &InteriorLocation, + ) -> core::result::Result<(), ()>; + + /// Consume `self` and return a new value representing the same location from the point of view + /// of `target`. The context of `self` is provided as `context`. + /// + /// Returns the original `self` in case of overflow. + fn reanchored( + self, + target: &Location, + context: &InteriorLocation, + ) -> core::result::Result; +} + +/// Result value when attempting to send an XCM message. +pub type SendResult = result::Result<(T, Assets), SendError>; + +/// Utility for sending an XCM message to a given location. +/// +/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each +/// router might return `NotApplicable` to pass the execution to the next sender item. Note that +/// each `NotApplicable` might alter the destination and the XCM message for to the next router. +/// +/// # Example +/// ```rust +/// # use codec::Encode; +/// # use staging_xcm::v5::{prelude::*, Weight}; +/// # use staging_xcm::VersionedXcm; +/// # use std::convert::Infallible; +/// +/// /// A sender that only passes the message through and does nothing. +/// struct Sender1; +/// impl SendXcm for Sender1 { +/// type Ticket = Infallible; +/// fn validate(_: &mut Option, _: &mut Option>) -> SendResult { +/// Err(SendError::NotApplicable) +/// } +/// fn deliver(_: Infallible) -> Result { +/// unreachable!() +/// } +/// } +/// +/// /// A sender that accepts a message that has two junctions, otherwise stops the routing. +/// struct Sender2; +/// impl SendXcm for Sender2 { +/// type Ticket = (); +/// fn validate(destination: &mut Option, message: &mut Option>) -> SendResult<()> { +/// match destination.as_ref().ok_or(SendError::MissingArgument)?.unpack() { +/// (0, [j1, j2]) => Ok(((), Assets::new())), +/// _ => Err(SendError::Unroutable), +/// } +/// } +/// fn deliver(_: ()) -> Result { +/// Ok([0; 32]) +/// } +/// } +/// +/// /// A sender that accepts a message from a parent, passing through otherwise. +/// struct Sender3; +/// impl SendXcm for Sender3 { +/// type Ticket = (); +/// fn validate(destination: &mut Option, message: &mut Option>) -> SendResult<()> { +/// match destination.as_ref().ok_or(SendError::MissingArgument)?.unpack() { +/// (1, []) => Ok(((), Assets::new())), +/// _ => Err(SendError::NotApplicable), +/// } +/// } +/// fn deliver(_: ()) -> Result { +/// Ok([0; 32]) +/// } +/// } +/// +/// // A call to send via XCM. We don't really care about this. +/// # fn main() { +/// let call: Vec = ().encode(); +/// let message = Xcm(vec![Instruction::Transact { +/// origin_kind: OriginKind::Superuser, +/// call: call.into(), +/// fallback_max_weight: None, +/// }]); +/// let message_hash = message.using_encoded(sp_io::hashing::blake2_256); +/// +/// // Sender2 will block this. +/// assert!(send_xcm::<(Sender1, Sender2, Sender3)>(Parent.into(), message.clone()).is_err()); +/// +/// // Sender3 will catch this. +/// assert!(send_xcm::<(Sender1, Sender3)>(Parent.into(), message.clone()).is_ok()); +/// # } +/// ``` +pub trait SendXcm { + /// Intermediate value which connects the two phases of the send operation. + type Ticket; + + /// Check whether the given `_message` is deliverable to the given `_destination` and if so + /// determine the cost which will be paid by this chain to do so, returning a `Validated` token + /// which can be used to enact delivery. + /// + /// 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 + /// implementation to exit early without trying other type fields. + fn validate( + destination: &mut Option, + message: &mut Option>, + ) -> SendResult; + + /// Actually carry out the delivery operation for a previously validated message sending. + fn deliver(ticket: Self::Ticket) -> result::Result; + + /// Ensure `[Self::delivery]` is successful for the given `location` when called in benchmarks. + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(_location: Option) {} +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl SendXcm for Tuple { + for_tuples! { type Ticket = (#( Option ),* ); } + + fn validate( + destination: &mut Option, + message: &mut Option>, + ) -> SendResult { + let mut maybe_cost: Option = None; + let one_ticket: Self::Ticket = (for_tuples! { #( + if maybe_cost.is_some() { + None + } else { + match Tuple::validate(destination, message) { + Err(SendError::NotApplicable) => None, + Err(e) => { return Err(e) }, + Ok((v, c)) => { + maybe_cost = Some(c); + Some(v) + }, + } + } + ),* }); + if let Some(cost) = maybe_cost { + Ok((one_ticket, cost)) + } else { + Err(SendError::NotApplicable) + } + } + + fn deliver(one_ticket: Self::Ticket) -> result::Result { + for_tuples!( #( + if let Some(validated) = one_ticket.Tuple { + return Tuple::deliver(validated); + } + )* ); + Err(SendError::Unroutable) + } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(location: Option) { + for_tuples!( #( + return Tuple::ensure_successful_delivery(location.clone()); + )* ); + } +} + +/// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps +/// both in `Some` before passing them as mutable references into `T::send_xcm`. +pub fn validate_send(dest: Location, msg: Xcm<()>) -> SendResult { + T::validate(&mut Some(dest), &mut Some(msg)) +} + +/// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps +/// both in `Some` before passing them as mutable references into `T::send_xcm`. +/// +/// Returns either `Ok` with the price of the delivery, or `Err` with the reason why the message +/// could not be sent. +/// +/// Generally you'll want to validate and get the price first to ensure that the sender can pay it +/// before actually doing the delivery. +pub fn send_xcm( + dest: Location, + msg: Xcm<()>, +) -> result::Result<(XcmHash, Assets), SendError> { + let (ticket, price) = T::validate(&mut Some(dest), &mut Some(msg))?; + let hash = T::deliver(ticket)?; + Ok((hash, price)) +} diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index eaa115740f3e..f75c984c068e 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -5,40 +5,42 @@ authors.workspace = true edition.workspace = true license.workspace = true version = "7.0.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -impl-trait-for-tuples = { workspace = true } codec = { features = ["derive"], workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +impl-trait-for-tuples = { workspace = true } +log = { workspace = true } +pallet-asset-conversion = { workspace = true } +pallet-transaction-payment = { workspace = true } scale-info = { features = ["derive"], workspace = true } -xcm = { workspace = true } -xcm-executor = { workspace = true } sp-arithmetic = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-weights = { workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -pallet-transaction-payment = { workspace = true } -pallet-asset-conversion = { workspace = true } -log = { workspace = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } # Polkadot dependencies polkadot-parachain-primitives = { workspace = true } [dev-dependencies] -sp-core = { workspace = true, default-features = true } -primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } +assert_matches = { workspace = true } +pallet-assets = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } pallet-salary = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } -assert_matches = { workspace = true } polkadot-test-runtime = { workspace = true } +primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } +sp-core = { workspace = true, default-features = true } [features] default = ["std"] @@ -57,6 +59,7 @@ runtime-benchmarks = [ "polkadot-test-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] std = [ "codec/std", diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index c995361ea8a3..adba9a3ef79f 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -95,7 +95,8 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFrom })? .skip_inst_while(|inst| { matches!(inst, ClearOrigin | AliasOrigin(..)) || - matches!(inst, DescendOrigin(child) if child != &Here) + matches!(inst, DescendOrigin(child) if child != &Here) || + matches!(inst, SetHints { .. }) })? .match_next_inst(|inst| match inst { BuyExecution { weight_limit: Limited(ref mut weight), .. } @@ -108,6 +109,7 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFrom *weight_limit = Limited(max_weight); Ok(()) }, + PayFees { .. } => Ok(()), _ => Err(ProcessMessageError::Overweight(max_weight)), })?; Ok(()) diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index bec3bdcb05a0..3d68d8ed16ae 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -108,7 +108,7 @@ pub use nonfungible_adapter::{ }; mod origin_aliases; -pub use origin_aliases::AliasForeignAccountId32; +pub use origin_aliases::*; mod origin_conversion; pub use origin_conversion::{ diff --git a/polkadot/xcm/xcm-builder/src/origin_aliases.rs b/polkadot/xcm/xcm-builder/src/origin_aliases.rs index d568adc3127c..5bc8f0ca32b9 100644 --- a/polkadot/xcm/xcm-builder/src/origin_aliases.rs +++ b/polkadot/xcm/xcm-builder/src/origin_aliases.rs @@ -17,7 +17,7 @@ //! Implementation for `ContainsPair`. use core::marker::PhantomData; -use frame_support::traits::{Contains, ContainsPair}; +use frame_support::traits::{Contains, ContainsPair, Get}; use xcm::latest::prelude::*; /// Alias a Foreign `AccountId32` with a local `AccountId32` if the foreign `AccountId32` matches @@ -38,3 +38,34 @@ impl> ContainsPair false } } + +/// Alias a descendant location of the original origin. +pub struct AliasChildLocation; +impl ContainsPair for AliasChildLocation { + fn contains(origin: &Location, target: &Location) -> bool { + return target.starts_with(origin) + } +} + +/// Alias a location if it passes `Filter` and the original origin is root of `Origin`. +/// +/// This can be used to allow (trusted) system chains root to alias into other locations. +/// **Warning**: do not use with untrusted `Origin` chains. +pub struct AliasOriginRootUsingFilter(PhantomData<(Origin, Filter)>); +impl ContainsPair for AliasOriginRootUsingFilter +where + Origin: Get, + Filter: Contains, +{ + fn contains(origin: &Location, target: &Location) -> bool { + // check that `origin` is a root location + match origin.unpack() { + (1, [Parachain(_)]) | + (2, [GlobalConsensus(_)]) | + (2, [GlobalConsensus(_), Parachain(_)]) => (), + _ => return false, + }; + // check that `origin` matches `Origin` and `target` matches `Filter` + return Origin::get().eq(origin) && Filter::contains(target) + } +} diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index 978c6870cdaf..0093051290b7 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -70,8 +70,8 @@ impl< Router: SendXcm, Querier: QueryHandler, Timeout: Get, - Beneficiary: Clone, - AssetKind, + Beneficiary: Clone + core::fmt::Debug, + AssetKind: core::fmt::Debug, AssetKindToLocatableAsset: TryConvert, BeneficiaryRefToLocation: for<'a> TryConvert<&'a Beneficiary, Location>, > Pay @@ -144,10 +144,9 @@ impl< } #[cfg(feature = "runtime-benchmarks")] - fn ensure_successful(_: &Self::Beneficiary, _: Self::AssetKind, _: Self::Balance) { - // We cannot generally guarantee this will go through successfully since we don't have any - // control over the XCM transport layers. We just assume that the benchmark environment - // will be sending it somewhere sensible. + fn ensure_successful(_: &Self::Beneficiary, asset_kind: Self::AssetKind, _: Self::Balance) { + let locatable = AssetKindToLocatableAsset::try_convert(asset_kind).unwrap(); + Router::ensure_successful_delivery(Some(locatable.location)); } #[cfg(feature = "runtime-benchmarks")] diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index 2e6f8c5fb566..67c05c116e9d 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -18,7 +18,10 @@ use codec::{Decode, FullCodec, MaxEncodedLen}; use core::{fmt::Debug, marker::PhantomData}; -use frame_support::traits::{ProcessMessage, ProcessMessageError}; +use frame_support::{ + dispatch::GetDispatchInfo, + traits::{ProcessMessage, ProcessMessageError}, +}; use scale_info::TypeInfo; use sp_weights::{Weight, WeightMeter}; use xcm::prelude::*; @@ -32,7 +35,7 @@ pub struct ProcessXcmMessage( impl< MessageOrigin: Into + FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug, XcmExecutor: ExecuteXcm, - Call, + Call: Decode + GetDispatchInfo, > ProcessMessage for ProcessXcmMessage { type Origin = MessageOrigin; @@ -55,7 +58,7 @@ impl< let message = Xcm::::try_from(versioned_message).map_err(|_| { log::trace!( target: LOG_TARGET, - "Failed to convert `VersionedXcm` into `XcmV3`.", + "Failed to convert `VersionedXcm` into `xcm::prelude::Xcm`!", ); ProcessMessageError::Unsupported @@ -125,7 +128,7 @@ mod tests { traits::{ProcessMessageError, ProcessMessageError::*}, }; use polkadot_test_runtime::*; - use xcm::{v3, v4, VersionedXcm}; + use xcm::{v3, v4, v5, VersionedXcm}; const ORIGIN: Junction = Junction::OnlyChild; /// The processor to use for tests. @@ -137,13 +140,15 @@ mod tests { // ClearOrigin works. assert!(process(v3_xcm(true)).unwrap()); assert!(process(v4_xcm(true)).unwrap()); + assert!(process(v5_xcm(true)).unwrap()); } #[test] fn process_message_trivial_fails() { // Trap makes it fail. assert!(!process(v3_xcm(false)).unwrap()); - assert!(!process(v3_xcm(false)).unwrap()); + assert!(!process(v4_xcm(false)).unwrap()); + assert!(!process(v5_xcm(false)).unwrap()); } #[test] @@ -179,7 +184,7 @@ mod tests { type Processor = ProcessXcmMessage; - let xcm = VersionedXcm::V4(xcm::latest::Xcm::<()>(vec![ + let xcm = VersionedXcm::from(xcm::latest::Xcm::<()>(vec![ xcm::latest::Instruction::<()>::ClearOrigin, ])); assert_err!( @@ -235,6 +240,15 @@ mod tests { VersionedXcm::V4(v4::Xcm::(vec![instr])) } + fn v5_xcm(success: bool) -> VersionedXcm { + let instr = if success { + v5::Instruction::::ClearOrigin + } else { + v5::Instruction::::Trap(1) + }; + VersionedXcm::V5(v5::Xcm::(vec![instr])) + } + fn process(msg: VersionedXcm) -> Result { process_raw(msg.encode().as_slice()) } diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index fc2de89d2128..5b0d0a5f9835 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -60,6 +60,11 @@ impl SendXcm for WithUniqueTopic { Inner::deliver(ticket)?; Ok(unique_id) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(location: Option) { + Inner::ensure_successful_delivery(location); + } } impl InspectMessageQueues for WithUniqueTopic { fn clear_messages() { @@ -114,6 +119,11 @@ impl SendXcm for WithTopicSource) { + Inner::ensure_successful_delivery(location); + } } /// Trait for a type which ensures all requirements for successful delivery with XCM transport @@ -211,4 +221,9 @@ impl SendXcm for EnsureDecodableXcm { fn deliver(ticket: Self::Ticket) -> Result { Inner::deliver(ticket) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(location: Option) { + Inner::ensure_successful_delivery(location); + } } diff --git a/polkadot/xcm/xcm-builder/src/tests/aliases.rs b/polkadot/xcm/xcm-builder/src/tests/aliases.rs index 89c17b09396d..dc8b016a6aa4 100644 --- a/polkadot/xcm/xcm-builder/src/tests/aliases.rs +++ b/polkadot/xcm/xcm-builder/src/tests/aliases.rs @@ -88,3 +88,164 @@ fn alias_origin_should_work() { ); assert_eq!(r, Outcome::Complete { used: Weight::from_parts(10, 10) }); } + +#[test] +fn alias_child_location() { + // parents differ + assert!(!AliasChildLocation::contains( + &Location::new(0, Parachain(1)), + &Location::new(1, Parachain(1)), + )); + assert!(!AliasChildLocation::contains( + &Location::new(0, Here), + &Location::new(1, Parachain(1)), + )); + assert!(!AliasChildLocation::contains(&Location::new(1, Here), &Location::new(2, Here),)); + + // interiors differ + assert!(!AliasChildLocation::contains( + &Location::new(1, Parachain(1)), + &Location::new(1, OnlyChild), + )); + assert!(!AliasChildLocation::contains( + &Location::new(1, Parachain(1)), + &Location::new(1, Parachain(12)), + )); + assert!(!AliasChildLocation::contains( + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]), + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [1; 32] }]), + )); + assert!(!AliasChildLocation::contains( + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]), + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [1; 32] }]), + )); + + // child to parent not allowed + assert!(!AliasChildLocation::contains( + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]), + &Location::new(1, [Parachain(1)]), + )); + assert!(!AliasChildLocation::contains( + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [0; 32] }]), + &Location::new(1, Here), + )); + + // parent to child should work + assert!(AliasChildLocation::contains( + &Location::new(1, Here), + &Location::new(1, [Parachain(1), AccountId32 { network: None, id: [1; 32] }]), + )); + assert!( + AliasChildLocation::contains(&Location::new(1, Here), &Location::new(1, Parachain(1)),) + ); + assert!(AliasChildLocation::contains( + &Location::new(0, Here), + &Location::new(0, PalletInstance(42)), + )); + assert!(AliasChildLocation::contains( + &Location::new(2, GlobalConsensus(Kusama)), + &Location::new(2, [GlobalConsensus(Kusama), Parachain(42), GeneralIndex(12)]), + )); +} + +#[test] +fn alias_trusted_root_location() { + const ALICE: [u8; 32] = [111u8; 32]; + const BOB: [u8; 32] = [222u8; 32]; + const BOB_ON_ETH: [u8; 20] = [222u8; 20]; + + parameter_types! { + pub AliceOnAssetHub: Location = Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]); + pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + } + + struct MatchSiblingAccounts; + impl Contains for MatchSiblingAccounts { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, [Parachain(_), AccountId32 { .. }])) + } + } + + struct MatchOtherGlobalConsensus; + impl Contains for MatchOtherGlobalConsensus { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (2, [GlobalConsensus(_)]) | (2, [GlobalConsensus(_), _])) + } + } + + type AliceOnAssetHubAliasesSiblingAccounts = + AliasOriginRootUsingFilter; + type AssetHubAliasesSiblingAccounts = + AliasOriginRootUsingFilter; + type AssetHubAliasesOtherGlobalConsensus = + AliasOriginRootUsingFilter; + + // Fails if origin is not the root of a chain. + assert!(!AliceOnAssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]), + &Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]), + )); + assert!(!AliceOnAssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]), + &Location::new(2, [GlobalConsensus(NetworkId::Ethereum { chain_id: 1 })]), + )); + assert!(!AliceOnAssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1000), AccountId32 { id: ALICE, network: None }]), + &Location::new( + 2, + [ + GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }), + AccountKey20 { key: BOB_ON_ETH, network: None } + ] + ), + )); + // Fails if origin doesn't match. + assert!(!AssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1001)]), + &Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]), + )); + assert!(!AssetHubAliasesOtherGlobalConsensus::contains( + &Location::new(1, [Parachain(1001)]), + &Location::new( + 2, + [ + GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }), + AccountKey20 { key: BOB_ON_ETH, network: None } + ] + ), + )); + // Fails if filter doesn't match. + assert!(!AssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1000)]), + &Location::new(2, [GlobalConsensus(NetworkId::Ethereum { chain_id: 1 })]), + )); + assert!(!AssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1000)]), + &Location::new( + 2, + [ + GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }), + AccountKey20 { key: BOB_ON_ETH, network: None } + ] + ), + )); + assert!(!AssetHubAliasesOtherGlobalConsensus::contains( + &Location::new(1, [Parachain(1000)]), + &Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]), + )); + // Works when origin is a chain that matches Origin and filter also matches. + assert!(AssetHubAliasesSiblingAccounts::contains( + &Location::new(1, [Parachain(1000)]), + &Location::new(1, [Parachain(1000), AccountId32 { id: BOB, network: None }]), + )); + assert!(AssetHubAliasesOtherGlobalConsensus::contains( + &Location::new(1, [Parachain(1000)]), + &Location::new( + 2, + [ + GlobalConsensus(NetworkId::Ethereum { chain_id: 1 }), + AccountKey20 { key: BOB_ON_ETH, network: None } + ] + ), + )); +} diff --git a/polkadot/xcm/xcm-builder/src/tests/barriers.rs b/polkadot/xcm/xcm-builder/src/tests/barriers.rs index cd2b6db66efc..d8805274d3a5 100644 --- a/polkadot/xcm/xcm-builder/src/tests/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/tests/barriers.rs @@ -333,6 +333,26 @@ fn allow_paid_should_deprivilege_origin() { assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30)))); } +#[test] +fn allow_paid_should_allow_hints() { + AllowPaidFrom::set(vec![Parent.into()]); + let fees = (Parent, 1).into(); + + let mut paying_message_with_hints = Xcm::<()>(vec![ + ReserveAssetDeposited((Parent, 100).into()), + SetHints { hints: vec![AssetClaimer { location: Location::here() }].try_into().unwrap() }, + BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() }, + ]); + let r = AllowTopLevelPaidExecutionFrom::>::should_execute( + &Parent.into(), + paying_message_with_hints.inner_mut(), + Weight::from_parts(30, 30), + &mut props(Weight::zero()), + ); + assert_eq!(r, Ok(())); +} + #[test] fn suspension_should_work() { TestSuspender::set_suspended(true); diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs b/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs index 062faee2abd9..b4718edc6c98 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/pay.rs @@ -22,7 +22,7 @@ use frame_support::{assert_ok, traits::tokens::Pay}; /// Type representing both a location and an asset that is held at that location. /// The id of the held asset is relative to the location where it is being held. -#[derive(Encode, Decode, Clone, PartialEq, Eq)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)] pub struct AssetKind { destination: Location, asset_id: AssetId, diff --git a/polkadot/xcm/xcm-builder/src/tests/transacting.rs b/polkadot/xcm/xcm-builder/src/tests/transacting.rs index a85c8b9986c8..ba932beaeb3d 100644 --- a/polkadot/xcm/xcm-builder/src/tests/transacting.rs +++ b/polkadot/xcm/xcm-builder/src/tests/transacting.rs @@ -22,8 +22,8 @@ fn transacting_should_work() { let message = Xcm::(vec![Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }]); let mut hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(60, 60); @@ -43,8 +43,8 @@ fn transacting_should_respect_max_weight_requirement() { let message = Xcm::(vec![Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(40, 40), call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }]); let mut hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(60, 60); @@ -55,10 +55,7 @@ fn transacting_should_respect_max_weight_requirement() { weight_limit, Weight::zero(), ); - assert_eq!( - r, - Outcome::Incomplete { used: Weight::from_parts(50, 50), error: XcmError::MaxWeightInvalid } - ); + assert_eq!(r, Outcome::Complete { used: Weight::from_parts(60, 60) }); } #[test] @@ -67,10 +64,10 @@ fn transacting_should_refund_weight() { let message = Xcm::(vec![Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::Any(Weight::from_parts(50, 50), Some(Weight::from_parts(30, 30))) .encode() .into(), + fallback_max_weight: None, }]); let mut hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(60, 60); @@ -98,11 +95,11 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { BuyExecution { fees, weight_limit: Limited(Weight::from_parts(100, 100)) }, Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), // call estimated at 50 but only takes 10. call: TestCall::Any(Weight::from_parts(50, 50), Some(Weight::from_parts(10, 10))) .encode() .into(), + fallback_max_weight: None, }, RefundSurplus, DepositAsset { assets: AllCounted(1).into(), beneficiary: one }, @@ -130,8 +127,8 @@ fn report_successful_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ReportTransactStatus(QueryResponseInfo { destination: Parent.into(), @@ -166,8 +163,8 @@ fn report_failed_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ReportTransactStatus(QueryResponseInfo { destination: Parent.into(), @@ -202,8 +199,8 @@ fn expect_successful_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ExpectTransactStatus(MaybeErrorCode::Success), ]); @@ -221,8 +218,8 @@ fn expect_successful_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ExpectTransactStatus(MaybeErrorCode::Success), ]); @@ -248,8 +245,8 @@ fn expect_failed_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ExpectTransactStatus(vec![2].into()), ]); @@ -267,8 +264,8 @@ fn expect_failed_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ExpectTransactStatus(vec![2].into()), ]); @@ -294,8 +291,8 @@ fn clear_transact_status_should_work() { let message = Xcm::(vec![ Transact { origin_kind: OriginKind::Native, - require_weight_at_most: Weight::from_parts(50, 50), call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(), + fallback_max_weight: None, }, ClearTransactStatus, ReportTransactStatus(QueryResponseInfo { diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 5c754f01ec0a..6b3c3adf737d 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -68,25 +68,36 @@ impl> SendXcm fn validate( dest: &mut Option, - xcm: &mut Option>, + msg: &mut Option>, ) -> SendResult { - let d = dest.take().ok_or(MissingArgument)?; + // This `clone` ensures that `dest` is not consumed in any case. + let d = dest.clone().take().ok_or(MissingArgument)?; let universal_source = UniversalLocation::get(); - let devolved = match ensure_is_remote(universal_source.clone(), d) { - Ok(x) => x, - Err(d) => { - *dest = Some(d); - return Err(NotApplicable) - }, - }; - let (network, destination) = devolved; - let xcm = xcm.take().ok_or(SendError::MissingArgument)?; - validate_export::(network, 0, universal_source, destination, xcm) + let devolved = ensure_is_remote(universal_source.clone(), d).map_err(|_| NotApplicable)?; + let (remote_network, remote_location) = devolved; + let xcm = msg.take().ok_or(MissingArgument)?; + + validate_export::( + remote_network, + 0, + universal_source, + remote_location, + xcm.clone(), + ) + .inspect_err(|err| { + if let NotApplicable = err { + // We need to make sure that msg is not consumed in case of `NotApplicable`. + *msg = Some(xcm); + } + }) } fn deliver(ticket: Exporter::Ticket) -> Result { Exporter::deliver(ticket) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(_: Option) {} } pub trait ExporterFor { @@ -95,7 +106,7 @@ pub trait ExporterFor { /// /// The payment is specified from the local context, not the bridge chain. This is the /// total amount to withdraw in to Holding and should cover both payment for the execution on - /// the bridge chain as well as payment for the use of the `ExportMessage` instruction. + /// the bridge chain and payment for the use of the `ExportMessage` instruction. fn exporter_for( network: &NetworkId, remote_location: &InteriorLocation, @@ -205,7 +216,8 @@ impl, msg: &mut Option>, ) -> SendResult { - let d = dest.clone().ok_or(MissingArgument)?; + // This `clone` ensures that `dest` is not consumed in any case. + let d = dest.clone().take().ok_or(MissingArgument)?; let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?; let (remote_network, remote_location) = devolved; let xcm = msg.take().ok_or(MissingArgument)?; @@ -216,7 +228,7 @@ impl(bridge, message) + validate_send::(bridge, message).inspect_err(|err| { + if let NotApplicable = err { + // We need to make sure that msg is not consumed in case of `NotApplicable`. + *msg = Some(xcm); + } + }) } fn deliver(validation: Self::Ticket) -> Result { Router::deliver(validation) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(location: Option) { + Router::ensure_successful_delivery(location); + } } /// Implementation of `SendXcm` which wraps the message inside an `ExportMessage` instruction @@ -272,9 +298,9 @@ impl, msg: &mut Option>, ) -> SendResult { - let d = dest.as_ref().ok_or(MissingArgument)?; - let devolved = - ensure_is_remote(UniversalLocation::get(), d.clone()).map_err(|_| NotApplicable)?; + // This `clone` ensures that `dest` is not consumed in any case. + let d = dest.clone().take().ok_or(MissingArgument)?; + let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?; let (remote_network, remote_location) = devolved; let xcm = msg.take().ok_or(MissingArgument)?; @@ -284,7 +310,7 @@ impl(bridge, message)?; + let (v, mut cost) = validate_send::(bridge, message).inspect_err(|err| { + if let NotApplicable = err { + // We need to make sure that msg is not consumed in case of `NotApplicable`. + *msg = Some(xcm); + } + })?; if let Some(bridge_payment) = maybe_payment { cost.push(bridge_payment); } @@ -335,6 +369,11 @@ impl Result { Router::deliver(ticket) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(location: Option) { + Router::ensure_successful_delivery(location); + } } impl InspectMessageQueues @@ -476,10 +515,10 @@ impl< let Location { parents, interior: mut junctions } = BridgedNetwork::get(); match junctions.take_first() { Some(GlobalConsensus(network)) => (network, parents), - _ => return Err(SendError::NotApplicable), + _ => return Err(NotApplicable), } }; - ensure!(&network == &bridged_network, SendError::NotApplicable); + ensure!(&network == &bridged_network, NotApplicable); // We don't/can't use the `channel` for this adapter. let dest = destination.take().ok_or(SendError::MissingArgument)?; @@ -496,7 +535,7 @@ impl< }, Err((dest, _)) => { *destination = Some(dest); - return Err(SendError::NotApplicable) + return Err(NotApplicable) }, }; @@ -540,6 +579,10 @@ impl< #[cfg(test)] mod tests { use super::*; + use frame_support::{ + assert_err, assert_ok, + traits::{Contains, Equals}, + }; #[test] fn ensure_is_remote_works() { @@ -564,20 +607,50 @@ mod tests { assert_eq!(x, Err((Parent, Polkadot, Parachain(1000)).into())); } - pub struct OkSender; - impl SendXcm for OkSender { + pub struct OkFor(PhantomData); + impl> SendXcm for OkFor { type Ticket = (); fn validate( - _destination: &mut Option, + destination: &mut Option, _message: &mut Option>, ) -> SendResult { - Ok(((), Assets::new())) + if let Some(d) = destination.as_ref() { + if Filter::contains(&d) { + return Ok(((), Assets::new())) + } + } + Err(NotApplicable) } fn deliver(_ticket: Self::Ticket) -> Result { Ok([0; 32]) } + + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful_delivery(_: Option) {} + } + impl> ExportXcm for OkFor { + type Ticket = (); + + fn validate( + network: NetworkId, + _: u32, + _: &mut Option, + destination: &mut Option, + _: &mut Option>, + ) -> SendResult { + if let Some(d) = destination.as_ref() { + if Filter::contains(&(network, d.clone())) { + return Ok(((), Assets::new())) + } + } + Err(NotApplicable) + } + + fn deliver(_ticket: Self::Ticket) -> Result { + Ok([1; 32]) + } } /// Generic test case asserting that dest and msg is not consumed by `validate` implementation @@ -598,46 +671,168 @@ mod tests { } #[test] - fn remote_exporters_does_not_consume_dest_or_msg_on_not_applicable() { + fn local_exporters_works() { frame_support::parameter_types! { pub Local: NetworkId = ByGenesis([0; 32]); pub UniversalLocation: InteriorLocation = [GlobalConsensus(Local::get()), Parachain(1234)].into(); pub DifferentRemote: NetworkId = ByGenesis([22; 32]); - // no routers - pub BridgeTable: Vec = vec![]; + pub RemoteDestination: Junction = Parachain(9657); + pub RoutableBridgeFilter: (NetworkId, InteriorLocation) = (DifferentRemote::get(), RemoteDestination::get().into()); } + type RoutableBridgeExporter = OkFor>; + type NotApplicableBridgeExporter = OkFor<()>; + assert_ok!(validate_export::( + DifferentRemote::get(), + 0, + UniversalLocation::get(), + RemoteDestination::get().into(), + Xcm::default() + )); + assert_err!( + validate_export::( + DifferentRemote::get(), + 0, + UniversalLocation::get(), + RemoteDestination::get().into(), + Xcm::default() + ), + NotApplicable + ); - // check with local destination (should be remote) + // 1. check with local destination (should be remote) let local_dest: Location = (Parent, Parachain(5678)).into(); assert!(ensure_is_remote(UniversalLocation::get(), local_dest.clone()).is_err()); + // UnpaidLocalExporter ensure_validate_does_not_consume_dest_or_msg::< - UnpaidRemoteExporter, OkSender, UniversalLocation>, + UnpaidLocalExporter, >(local_dest.clone(), |result| assert_eq!(Err(NotApplicable), result)); + // 2. check with not applicable from the inner router (using `NotApplicableBridgeSender`) + let remote_dest: Location = + (Parent, Parent, DifferentRemote::get(), RemoteDestination::get()).into(); + assert!(ensure_is_remote(UniversalLocation::get(), remote_dest.clone()).is_ok()); + + // UnpaidLocalExporter + ensure_validate_does_not_consume_dest_or_msg::< + UnpaidLocalExporter, + >(remote_dest.clone(), |result| assert_eq!(Err(NotApplicable), result)); + + // 3. Ok - deliver + // UnpaidRemoteExporter + assert_ok!(send_xcm::>( + remote_dest, + Xcm::default() + )); + } + + #[test] + fn remote_exporters_works() { + frame_support::parameter_types! { + pub Local: NetworkId = ByGenesis([0; 32]); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(Local::get()), Parachain(1234)].into(); + pub DifferentRemote: NetworkId = ByGenesis([22; 32]); + pub RoutableBridge: Location = Location::new(1, Parachain(9657)); + // not routable + pub NotApplicableBridgeTable: Vec = vec![]; + // routable + pub RoutableBridgeTable: Vec = vec![ + NetworkExportTableItem::new( + DifferentRemote::get(), + None, + RoutableBridge::get(), + None + ) + ]; + } + type RoutableBridgeSender = OkFor>; + type NotApplicableBridgeSender = OkFor<()>; + assert_ok!(validate_send::(RoutableBridge::get(), Xcm::default())); + assert_err!( + validate_send::(RoutableBridge::get(), Xcm::default()), + NotApplicable + ); + + // 1. check with local destination (should be remote) + let local_dest: Location = (Parent, Parachain(5678)).into(); + assert!(ensure_is_remote(UniversalLocation::get(), local_dest.clone()).is_err()); + + // UnpaidRemoteExporter + ensure_validate_does_not_consume_dest_or_msg::< + UnpaidRemoteExporter< + NetworkExportTable, + RoutableBridgeSender, + UniversalLocation, + >, + >(local_dest.clone(), |result| assert_eq!(Err(NotApplicable), result)); + // SovereignPaidRemoteExporter ensure_validate_does_not_consume_dest_or_msg::< SovereignPaidRemoteExporter< - NetworkExportTable, - OkSender, + NetworkExportTable, + RoutableBridgeSender, UniversalLocation, >, >(local_dest, |result| assert_eq!(Err(NotApplicable), result)); - // check with not applicable destination + // 2. check with not applicable destination (`NotApplicableBridgeTable`) let remote_dest: Location = (Parent, Parent, DifferentRemote::get()).into(); assert!(ensure_is_remote(UniversalLocation::get(), remote_dest.clone()).is_ok()); + // UnpaidRemoteExporter ensure_validate_does_not_consume_dest_or_msg::< - UnpaidRemoteExporter, OkSender, UniversalLocation>, + UnpaidRemoteExporter< + NetworkExportTable, + RoutableBridgeSender, + UniversalLocation, + >, >(remote_dest.clone(), |result| assert_eq!(Err(NotApplicable), result)); - + // SovereignPaidRemoteExporter ensure_validate_does_not_consume_dest_or_msg::< SovereignPaidRemoteExporter< - NetworkExportTable, - OkSender, + NetworkExportTable, + RoutableBridgeSender, UniversalLocation, >, >(remote_dest, |result| assert_eq!(Err(NotApplicable), result)); + + // 3. check with not applicable from the inner router (using `NotApplicableBridgeSender`) + let remote_dest: Location = (Parent, Parent, DifferentRemote::get()).into(); + assert!(ensure_is_remote(UniversalLocation::get(), remote_dest.clone()).is_ok()); + + // UnpaidRemoteExporter + ensure_validate_does_not_consume_dest_or_msg::< + UnpaidRemoteExporter< + NetworkExportTable, + NotApplicableBridgeSender, + UniversalLocation, + >, + >(remote_dest.clone(), |result| assert_eq!(Err(NotApplicable), result)); + // SovereignPaidRemoteExporter + ensure_validate_does_not_consume_dest_or_msg::< + SovereignPaidRemoteExporter< + NetworkExportTable, + NotApplicableBridgeSender, + UniversalLocation, + >, + >(remote_dest.clone(), |result| assert_eq!(Err(NotApplicable), result)); + + // 4. Ok - deliver + // UnpaidRemoteExporter + assert_ok!(send_xcm::< + UnpaidRemoteExporter< + NetworkExportTable, + RoutableBridgeSender, + UniversalLocation, + >, + >(remote_dest.clone(), Xcm::default())); + // SovereignPaidRemoteExporter + assert_ok!(send_xcm::< + SovereignPaidRemoteExporter< + NetworkExportTable, + RoutableBridgeSender, + UniversalLocation, + >, + >(remote_dest, Xcm::default())); } #[test] diff --git a/polkadot/xcm/xcm-builder/src/weight.rs b/polkadot/xcm/xcm-builder/src/weight.rs index 7861fdcc2e57..6521121f2c94 100644 --- a/polkadot/xcm/xcm-builder/src/weight.rs +++ b/polkadot/xcm/xcm-builder/src/weight.rs @@ -43,27 +43,30 @@ impl, C: Decode + GetDispatchInfo, M: Get> WeightBounds let mut instructions_left = M::get(); Self::weight_with_limit(message, &mut instructions_left) } - fn instr_weight(instruction: &Instruction) -> Result { + fn instr_weight(instruction: &mut Instruction) -> Result { Self::instr_weight_with_limit(instruction, &mut u32::max_value()) } } impl, C: Decode + GetDispatchInfo, M> FixedWeightBounds { - fn weight_with_limit(message: &Xcm, instrs_limit: &mut u32) -> Result { + fn weight_with_limit(message: &mut Xcm, instrs_limit: &mut u32) -> Result { let mut r: Weight = Weight::zero(); *instrs_limit = instrs_limit.checked_sub(message.0.len() as u32).ok_or(())?; - for m in message.0.iter() { - r = r.checked_add(&Self::instr_weight_with_limit(m, instrs_limit)?).ok_or(())?; + for instruction in message.0.iter_mut() { + r = r + .checked_add(&Self::instr_weight_with_limit(instruction, instrs_limit)?) + .ok_or(())?; } Ok(r) } fn instr_weight_with_limit( - instruction: &Instruction, + instruction: &mut Instruction, instrs_limit: &mut u32, ) -> Result { let instr_weight = match instruction { - Transact { require_weight_at_most, .. } => *require_weight_at_most, - SetErrorHandler(xcm) | SetAppendix(xcm) => Self::weight_with_limit(xcm, instrs_limit)?, + Transact { ref mut call, .. } => call.ensure_decoded()?.get_dispatch_info().call_weight, + SetErrorHandler(xcm) | SetAppendix(xcm) | ExecuteWithOrigin { xcm, .. } => + Self::weight_with_limit(xcm, instrs_limit)?, _ => Weight::zero(), }; T::get().checked_add(&instr_weight).ok_or(()) @@ -83,7 +86,7 @@ where let mut instructions_left = M::get(); Self::weight_with_limit(message, &mut instructions_left) } - fn instr_weight(instruction: &Instruction) -> Result { + fn instr_weight(instruction: &mut Instruction) -> Result { Self::instr_weight_with_limit(instruction, &mut u32::max_value()) } } @@ -95,20 +98,22 @@ where M: Get, Instruction: xcm::latest::GetWeight, { - fn weight_with_limit(message: &Xcm, instrs_limit: &mut u32) -> Result { + fn weight_with_limit(message: &mut Xcm, instrs_limit: &mut u32) -> Result { let mut r: Weight = Weight::zero(); *instrs_limit = instrs_limit.checked_sub(message.0.len() as u32).ok_or(())?; - for m in message.0.iter() { - r = r.checked_add(&Self::instr_weight_with_limit(m, instrs_limit)?).ok_or(())?; + for instruction in message.0.iter_mut() { + r = r + .checked_add(&Self::instr_weight_with_limit(instruction, instrs_limit)?) + .ok_or(())?; } Ok(r) } fn instr_weight_with_limit( - instruction: &Instruction, + instruction: &mut Instruction, instrs_limit: &mut u32, ) -> Result { let instr_weight = match instruction { - Transact { require_weight_at_most, .. } => *require_weight_at_most, + Transact { ref mut call, .. } => call.ensure_decoded()?.get_dispatch_info().call_weight, SetErrorHandler(xcm) | SetAppendix(xcm) => Self::weight_with_limit(xcm, instrs_limit)?, _ => Weight::zero(), }; @@ -227,7 +232,7 @@ impl< log::trace!(target: "xcm::weight", "UsingComponents::buy_weight weight: {:?}, payment: {:?}, context: {:?}", weight, payment, context); let amount = WeightToFee::weight_to_fee(&weight); let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?; - let required = (AssetId(AssetIdValue::get()), u128_amount).into(); + let required = Asset { id: AssetId(AssetIdValue::get()), fun: Fungible(u128_amount) }; let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?; self.0 = self.0.saturating_add(weight); self.1 = self.1.saturating_add(amount); diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index cc966f91fe4d..381dca54a5fb 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -5,24 +5,26 @@ authors.workspace = true edition.workspace = true license.workspace = true version = "7.0.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] -impl-trait-for-tuples = { workspace = true } -environmental = { workspace = true } codec = { features = ["derive"], workspace = true } +environmental = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +impl-trait-for-tuples = { workspace = true } scale-info = { features = ["derive", "serde"], workspace = true } -xcm = { workspace = true } -sp-io = { workspace = true } sp-arithmetic = { workspace = true } sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-weights = { workspace = true } -frame-support = { workspace = true } tracing = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } +xcm = { workspace = true } [features] default = ["std"] @@ -30,6 +32,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm/runtime-benchmarks", ] std = [ "codec/std", diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index 7e6bfe967b90..6c2e56669bc3 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -13,21 +13,24 @@ workspace = true [dependencies] codec = { workspace = true, default-features = true } frame-support = { workspace = true } +frame-system = { workspace = true, default-features = true } futures = { workspace = true } +pallet-sudo = { workspace = true, default-features = true } pallet-transaction-payment = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } polkadot-test-client = { workspace = true } polkadot-test-runtime = { workspace = true } polkadot-test-service = { workspace = true } sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-runtime = { workspace = true } sp-state-machine = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } xcm = { workspace = true } xcm-executor = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } [features] default = ["std"] -std = ["frame-support/std", "sp-runtime/std", "xcm/std"] +std = ["frame-support/std", "frame-system/std", "pallet-sudo/std", "polkadot-runtime-parachains/std", "sp-runtime/std", "xcm/std"] diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index e95473c5407e..dfcc3fc4187f 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -17,7 +17,7 @@ #![cfg(test)] use codec::Encode; -use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; +use frame_support::weights::Weight; use polkadot_test_client::{ BlockBuilderExt, ClientBlockImportExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder, TestClientBuilder, TestClientBuilderExt, @@ -81,8 +81,8 @@ fn transact_recursion_limit_works() { BuyExecution { fees: (Here, 1).into(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Native, - require_weight_at_most: call.get_dispatch_info().call_weight, call: call.encode().into(), + fallback_max_weight: None, }, ]) }; @@ -241,7 +241,7 @@ fn query_response_fires() { assert_eq!( polkadot_test_runtime::Xcm::query(query_id), Some(QueryStatus::Ready { - response: VersionedResponse::V4(Response::ExecutionResult(None)), + response: VersionedResponse::from(Response::ExecutionResult(None)), at: 2u32.into() }), ) @@ -375,6 +375,26 @@ fn deposit_reserve_asset_works_for_any_xcm_sender() { let mut block_builder = client.init_polkadot_block_builder(); + // Make the para available, so that `DMP` doesn't reject the XCM because the para is unknown. + let make_para_available = + construct_extrinsic( + &client, + polkadot_test_runtime::RuntimeCall::Sudo(pallet_sudo::Call::sudo { + call: Box::new(polkadot_test_runtime::RuntimeCall::System( + frame_system::Call::set_storage { + items: vec![( + polkadot_runtime_parachains::paras::Heads::< + polkadot_test_runtime::Runtime, + >::hashed_key_for(2000u32), + vec![1, 2, 3], + )], + }, + )), + }), + sp_keyring::Sr25519Keyring::Alice, + 0, + ); + // Simulate execution of an incoming XCM message at the reserve chain let execute = construct_extrinsic( &client, @@ -383,9 +403,12 @@ fn deposit_reserve_asset_works_for_any_xcm_sender() { max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), }), sp_keyring::Sr25519Keyring::Alice, - 0, + 1, ); + block_builder + .push_polkadot_extrinsic(make_para_available) + .expect("pushes extrinsic"); block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic"); let block = block_builder.build().expect("Finalizes the block").block; diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index e3addfa3e794..d0f18aea1ab3 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -29,7 +29,7 @@ use frame_support::{ use sp_core::defer; use sp_io::hashing::blake2_128; use sp_weights::Weight; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, AssetTransferFilter}; pub mod traits; use traits::{ @@ -47,6 +47,9 @@ pub use assets::AssetsInHolding; mod config; pub use config::Config; +#[cfg(test)] +mod tests; + /// A struct to specify how fees are being paid. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct FeesMode { @@ -83,13 +86,17 @@ pub struct XcmExecutor { appendix_weight: Weight, transact_status: MaybeErrorCode, fees_mode: FeesMode, + fees: AssetsInHolding, /// Asset provided in last `BuyExecution` instruction (if any) in current XCM program. Same /// asset type will be used for paying any potential delivery fees incurred by the program. - asset_used_for_fees: Option, + asset_used_in_buy_execution: Option, + /// Stores the current message's weight. + message_weight: Weight, + asset_claimer: Option, _config: PhantomData, } -#[cfg(feature = "runtime-benchmarks")] +#[cfg(any(test, feature = "runtime-benchmarks"))] impl XcmExecutor { pub fn holding(&self) -> &AssetsInHolding { &self.holding @@ -175,12 +182,24 @@ impl XcmExecutor { pub fn set_fees_mode(&mut self, v: FeesMode) { self.fees_mode = v } + pub fn fees(&self) -> &AssetsInHolding { + &self.fees + } + pub fn set_fees(&mut self, value: AssetsInHolding) { + self.fees = value; + } pub fn topic(&self) -> &Option<[u8; 32]> { &self.context.topic } pub fn set_topic(&mut self, v: Option<[u8; 32]>) { self.context.topic = v; } + pub fn asset_claimer(&self) -> Option { + self.asset_claimer.clone() + } + pub fn set_message_weight(&mut self, weight: Weight) { + self.message_weight = weight; + } } pub struct WeighedMessage(Weight, Xcm); @@ -249,6 +268,7 @@ impl ExecuteXcm for XcmExecutor XcmAssetTransfers for XcmExecutor { type AssetTransactor = Config::AssetTransactor; } -#[derive(Debug)] +impl FeeManager for XcmExecutor { + fn is_waived(origin: Option<&Location>, r: FeeReason) -> bool { + Config::FeeManager::is_waived(origin, r) + } + + fn handle_fee(fee: Assets, context: Option<&XcmContext>, r: FeeReason) { + Config::FeeManager::handle_fee(fee, context, r) + } +} + +#[derive(Debug, PartialEq)] pub struct ExecutorError { pub index: u32, pub xcm_error: XcmError, @@ -322,7 +352,10 @@ impl XcmExecutor { appendix_weight: Weight::zero(), transact_status: Default::default(), fees_mode: FeesMode { jit_withdraw: false }, - asset_used_for_fees: None, + fees: AssetsInHolding::new(), + asset_used_in_buy_execution: None, + message_weight: Weight::zero(), + asset_claimer: None, _config: PhantomData, } } @@ -346,9 +379,12 @@ impl XcmExecutor { original_origin = ?self.original_origin, "Trapping assets in holding register", ); - let effective_origin = self.context.origin.as_ref().unwrap_or(&self.original_origin); - let trap_weight = - Config::AssetTrap::drop_assets(effective_origin, self.holding, &self.context); + let claimer = if let Some(asset_claimer) = self.asset_claimer.as_ref() { + asset_claimer + } else { + self.context.origin.as_ref().unwrap_or(&self.original_origin) + }; + let trap_weight = Config::AssetTrap::drop_assets(claimer, self.holding, &self.context); weight_used.saturating_accrue(trap_weight); }; @@ -466,6 +502,11 @@ impl XcmExecutor { self.holding.subsume_assets(w.into()); } } + // If there are any leftover `fees`, merge them with `holding`. + if !self.fees.is_empty() { + let leftover_fees = self.fees.saturating_take(Wild(All)); + self.holding.subsume_assets(leftover_fees); + } tracing::trace!( target: "xcm::refund_surplus", total_refunded = ?self.total_refunded, @@ -490,7 +531,7 @@ impl XcmExecutor { Some(fee) => fee, None => return Ok(()), // No delivery fees need to be paid. }; - // If `BuyExecution` was called, we use that asset for delivery fees as well. + // If `BuyExecution` or `PayFees` was called, we use that asset for delivery fees as well. let asset_to_pay_for_fees = self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone()); tracing::trace!(target: "xcm::fees", ?asset_to_pay_for_fees); @@ -505,15 +546,31 @@ impl XcmExecutor { tracing::trace!(target: "xcm::fees", ?asset_needed_for_fees); asset_to_pay_for_fees.clone().into() } else { - let assets_taken_from_holding_to_pay_delivery_fees = self - .holding - .try_take(asset_to_pay_for_fees.clone().into()) - .map_err(|e| { - tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees, "Failed to take asset_to_pay_for_fees from holding"); - XcmError::NotHoldingFees - })?; - tracing::trace!(target: "xcm::fees", ?assets_taken_from_holding_to_pay_delivery_fees); - let mut iter = assets_taken_from_holding_to_pay_delivery_fees.fungible_assets_iter(); + // This condition exists to support `BuyExecution` while the ecosystem + // transitions to `PayFees`. + let assets_to_pay_delivery_fees: AssetsInHolding = if self.fees.is_empty() { + // Means `BuyExecution` was used, we'll find the fees in the `holding` register. + self.holding + .try_take(asset_to_pay_for_fees.clone().into()) + .map_err(|e| { + tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees, + "Holding doesn't hold enough for fees"); + XcmError::NotHoldingFees + })? + .into() + } else { + // Means `PayFees` was used, we'll find the fees in the `fees` register. + self.fees + .try_take(asset_to_pay_for_fees.clone().into()) + .map_err(|e| { + tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees, + "Fees register doesn't hold enough for fees"); + XcmError::NotHoldingFees + })? + .into() + }; + tracing::trace!(target: "xcm::fees", ?assets_to_pay_delivery_fees); + let mut iter = assets_to_pay_delivery_fees.fungible_assets_iter(); let asset = iter.next().ok_or(XcmError::NotHoldingFees)?; asset.into() }; @@ -544,41 +601,45 @@ impl XcmExecutor { Ok(()) } - /// Calculates the amount of `self.asset_used_for_fees` required to swap for - /// `asset_needed_for_fees`. + /// Calculates the amount of asset used in `PayFees` or `BuyExecution` that would be + /// charged for swapping to `asset_needed_for_fees`. /// /// The calculation is done by `Config::AssetExchanger`. - /// If `self.asset_used_for_fees` is not set, it will just return `asset_needed_for_fees`. + /// If neither `PayFees` or `BuyExecution` were not used, or no swap is required, + /// it will just return `asset_needed_for_fees`. fn calculate_asset_for_delivery_fees(&self, asset_needed_for_fees: Asset) -> Asset { - if let Some(asset_wanted_for_fees) = &self.asset_used_for_fees { - if *asset_wanted_for_fees != asset_needed_for_fees.id { - match Config::AssetExchanger::quote_exchange_price( - &(asset_wanted_for_fees.clone(), Fungible(0)).into(), - &asset_needed_for_fees.clone().into(), - false, // Minimal. - ) { - Some(necessary_assets) => - // We only use the first asset for fees. - // If this is not enough to swap for the fee asset then it will error later down - // the line. - necessary_assets.get(0).unwrap_or(&asset_needed_for_fees.clone()).clone(), - // If we can't convert, then we return the original asset. - // It will error later in any case. - None => { - tracing::trace!( - target: "xcm::calculate_asset_for_delivery_fees", - ?asset_wanted_for_fees, - "Could not convert fees", - ); - asset_needed_for_fees.clone() - }, - } - } else { - asset_needed_for_fees - } - } else { + let Some(asset_wanted_for_fees) = + // we try to swap first asset in the fees register (should only ever be one), + self.fees.fungible.first_key_value().map(|(id, _)| id).or_else(|| { + // or the one used in BuyExecution + self.asset_used_in_buy_execution.as_ref() + }) + // if it is different than what we need + .filter(|&id| asset_needed_for_fees.id.ne(id)) + else { + // either nothing to swap or we're already holding the right asset + return asset_needed_for_fees + }; + Config::AssetExchanger::quote_exchange_price( + &(asset_wanted_for_fees.clone(), Fungible(0)).into(), + &asset_needed_for_fees.clone().into(), + false, // Minimal. + ) + .and_then(|necessary_assets| { + // We only use the first asset for fees. + // If this is not enough to swap for the fee asset then it will error later down + // the line. + necessary_assets.into_inner().into_iter().next() + }) + .unwrap_or_else(|| { + // If we can't convert, then we return the original asset. + // It will error later in any case. + tracing::trace!( + target: "xcm::calculate_asset_for_delivery_fees", + ?asset_wanted_for_fees, "Could not convert fees", + ); asset_needed_for_fees - } + }) } /// Calculates what `local_querier` would be from the perspective of `destination`. @@ -614,6 +675,74 @@ impl XcmExecutor { self.send(destination, message, fee_reason) } + fn do_reserve_deposit_assets( + assets: AssetsInHolding, + dest: &Location, + remote_xcm: &mut Vec>, + context: Option<&XcmContext>, + ) -> Result { + Self::deposit_assets_with_retry(&assets, dest, context)?; + // Note that we pass `None` as `maybe_failed_bin` and drop any assets which + // cannot be reanchored, because we have already called `deposit_asset` on + // all assets. + let reanchored_assets = Self::reanchored(assets, dest, None); + remote_xcm.push(ReserveAssetDeposited(reanchored_assets.clone())); + + Ok(reanchored_assets) + } + + fn do_reserve_withdraw_assets( + assets: AssetsInHolding, + failed_bin: &mut AssetsInHolding, + reserve: &Location, + remote_xcm: &mut Vec>, + ) -> Result { + // Must ensure that we recognise the assets as being managed by the destination. + #[cfg(not(any(test, 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 reanchored_assets = Self::reanchored(assets, reserve, Some(failed_bin)); + remote_xcm.push(WithdrawAsset(reanchored_assets.clone())); + + Ok(reanchored_assets) + } + + fn do_teleport_assets( + assets: AssetsInHolding, + dest: &Location, + remote_xcm: &mut Vec>, + context: &XcmContext, + ) -> Result { + for asset in assets.assets_iter() { + // Must ensure that we have teleport trust with destination for these assets. + #[cfg(not(any(test, feature = "runtime-benchmarks")))] + ensure!( + Config::IsTeleporter::contains(&asset, &dest), + XcmError::UntrustedTeleportLocation + ); + // 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 ourselves, so it's unlikely, but we don't want to allow that kind + // of bug to leak into a trusted chain. + Config::AssetTransactor::can_check_out(dest, &asset, context)?; + } + for asset in assets.assets_iter() { + Config::AssetTransactor::check_out(dest, &asset, context); + } + // Note that we pass `None` as `maybe_failed_bin` and drop any assets which + // cannot be reanchored, because we have already checked all assets out. + let reanchored_assets = Self::reanchored(assets, dest, None); + remote_xcm.push(ReceiveTeleportedAsset(reanchored_assets.clone())); + + Ok(reanchored_assets) + } + fn try_reanchor( reanchorable: T, destination: &Location, @@ -638,11 +767,16 @@ impl XcmExecutor { assets.into_assets_iter().collect::>().into() } - #[cfg(feature = "runtime-benchmarks")] + #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn bench_process(&mut self, xcm: Xcm) -> Result<(), ExecutorError> { self.process(xcm) } + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub fn bench_post_process(self, xcm_weight: Weight) -> Outcome { + self.post_process(xcm_weight) + } + fn process(&mut self, xcm: Xcm) -> Result<(), ExecutorError> { tracing::trace!( target: "xcm::process", @@ -652,7 +786,7 @@ impl XcmExecutor { error_handler_weight = ?self.error_handler_weight, ); let mut result = Ok(()); - for (i, instr) in xcm.0.into_iter().enumerate() { + for (i, mut instr) in xcm.0.into_iter().enumerate() { match &mut result { r @ Ok(()) => { // Initialize the recursion count only the first time we hit this code in our @@ -688,7 +822,7 @@ impl XcmExecutor { } }, Err(ref mut error) => - if let Ok(x) = Config::Weigher::instr_weight(&instr) { + if let Ok(x) = Config::Weigher::instr_weight(&mut instr) { error.weight.saturating_accrue(x) }, } @@ -805,7 +939,8 @@ impl XcmExecutor { Ok(()) }) }, - Transact { origin_kind, require_weight_at_most, mut call } => { + // `fallback_max_weight` is not used in the executor, it's only for conversions. + Transact { origin_kind, mut call, .. } => { // We assume that the Relay-chain is allowed to use transact on this parachain. let origin = self.cloned_origin().ok_or_else(|| { tracing::trace!( @@ -862,18 +997,6 @@ impl XcmExecutor { ); let weight = message_call.get_dispatch_info().call_weight; - - if !weight.all_lte(require_weight_at_most) { - tracing::trace!( - target: "xcm::process_instruction::transact", - %weight, - %require_weight_at_most, - "Max weight bigger than require at most", - ); - - return Err(XcmError::MaxWeightInvalid) - } - let maybe_actual_weight = match Config::CallDispatcher::dispatch(message_call, dispatch_origin) { Ok(post_info) => { @@ -898,9 +1021,7 @@ impl XcmExecutor { }; let actual_weight = maybe_actual_weight.unwrap_or(weight); let surplus = weight.saturating_sub(actual_weight); - // We assume that the `Config::Weigher` will count the `require_weight_at_most` - // for the estimate of how much weight this instruction will take. Now that we know - // that it's less, we credit it. + // If the actual weight of the call was less than the specified weight, we credit it. // // We make the adjustment for the total surplus, which is used eventually // reported back to the caller and this ensures that they account for the total @@ -921,19 +1042,25 @@ impl XcmExecutor { ); Ok(()) }, - DescendOrigin(who) => self - .context - .origin - .as_mut() - .ok_or(XcmError::BadOrigin)? - .append_with(who) - .map_err(|e| { - tracing::error!(target: "xcm::process_instruction::descend_origin", ?e, "Failed to append junctions"); - XcmError::LocationFull - }), - ClearOrigin => { - self.context.origin = None; - Ok(()) + DescendOrigin(who) => self.do_descend_origin(who), + ClearOrigin => self.do_clear_origin(), + ExecuteWithOrigin { descendant_origin, xcm } => { + let previous_origin = self.context.origin.clone(); + + // Set new temporary origin. + if let Some(who) = descendant_origin { + self.do_descend_origin(who)?; + } else { + self.do_clear_origin()?; + } + // Process instructions. + let result = self.process(xcm).map_err(|error| { + tracing::error!(target: "xcm::execute", ?error, actual_origin = ?self.context.origin, original_origin = ?previous_origin, "ExecuteWithOrigin inner xcm failure"); + error.xcm_error + }); + // Reset origin to previous one. + self.context.origin = previous_origin; + result }, ReportError(response_info) => { // Report the given result by sending a QueryResponse XCM to a previously given @@ -950,7 +1077,7 @@ impl XcmExecutor { let old_holding = self.holding.clone(); let result = Config::TransactionalProcessor::process(|| { let deposited = self.holding.saturating_take(assets); - self.deposit_assets_with_retry(&deposited, &beneficiary) + Self::deposit_assets_with_retry(&deposited, &beneficiary, Some(&self.context)) }); if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { self.holding = old_holding; @@ -960,42 +1087,29 @@ impl XcmExecutor { DepositReserveAsset { assets, dest, xcm } => { let old_holding = self.holding.clone(); let result = Config::TransactionalProcessor::process(|| { - // we need to do this take/put cycle to solve wildcards and get exact assets to - // be weighed - let to_weigh = self.holding.saturating_take(assets.clone()); - self.holding.subsume_assets(to_weigh.clone()); - let to_weigh_reanchored = Self::reanchored(to_weigh, &dest, None); - let mut message_to_weigh = - vec![ReserveAssetDeposited(to_weigh_reanchored), ClearOrigin]; - message_to_weigh.extend(xcm.0.clone().into_iter()); - let (_, fee) = - validate_send::(dest.clone(), Xcm(message_to_weigh))?; - let maybe_delivery_fee = fee.get(0).map(|asset_needed_for_fees| { - tracing::trace!( - target: "xcm::DepositReserveAsset", - "Asset provided to pay for fees {:?}, asset required for delivery fees: {:?}", - self.asset_used_for_fees, asset_needed_for_fees, - ); - let asset_to_pay_for_fees = - self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone()); - // set aside fee to be charged by XcmSender - let delivery_fee = - self.holding.saturating_take(asset_to_pay_for_fees.into()); - tracing::trace!(target: "xcm::DepositReserveAsset", ?delivery_fee); - delivery_fee - }); - // now take assets to deposit (after having taken delivery fees) - let deposited = self.holding.saturating_take(assets); - tracing::trace!(target: "xcm::DepositReserveAsset", ?deposited, "Assets except delivery fee"); - self.deposit_assets_with_retry(&deposited, &dest)?; - // Note that we pass `None` as `maybe_failed_bin` and drop any assets which - // cannot be reanchored because we have already called `deposit_asset` on all - // assets. - let assets = Self::reanchored(deposited, &dest, None); - let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin]; + let mut assets = self.holding.saturating_take(assets); + // When not using `PayFees`, nor `JIT_WITHDRAW`, delivery fees are paid from + // transferred assets. + let maybe_delivery_fee_from_assets = if self.fees.is_empty() && !self.fees_mode.jit_withdraw { + // Deduct and return the part of `assets` that shall be used for delivery fees. + self.take_delivery_fee_from_assets(&mut assets, &dest, FeeReason::DepositReserveAsset, &xcm)? + } else { + None + }; + let mut message = Vec::with_capacity(xcm.len() + 2); + tracing::trace!(target: "xcm::DepositReserveAsset", ?assets, "Assets except delivery fee"); + Self::do_reserve_deposit_assets( + assets, + &dest, + &mut message, + Some(&self.context), + )?; + // clear origin for subsequent custom instructions + message.push(ClearOrigin); + // append custom instructions message.extend(xcm.0.into_iter()); - // put back delivery_fee in holding register to be charged by XcmSender - if let Some(delivery_fee) = maybe_delivery_fee { + if let Some(delivery_fee) = maybe_delivery_fee_from_assets { + // Put back delivery_fee in holding register to be charged by XcmSender. self.holding.subsume_assets(delivery_fee); } self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?; @@ -1009,20 +1123,30 @@ 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(assets, &reserve, Some(&mut self.holding)); - let mut message = vec![WithdrawAsset(assets), ClearOrigin]; + let mut assets = self.holding.saturating_take(assets); + // When not using `PayFees`, nor `JIT_WITHDRAW`, delivery fees are paid from + // transferred assets. + let maybe_delivery_fee_from_assets = if self.fees.is_empty() && !self.fees_mode.jit_withdraw { + // Deduct and return the part of `assets` that shall be used for delivery fees. + self.take_delivery_fee_from_assets(&mut assets, &reserve, FeeReason::InitiateReserveWithdraw, &xcm)? + } else { + None + }; + let mut message = Vec::with_capacity(xcm.len() + 2); + Self::do_reserve_withdraw_assets( + assets, + &mut self.holding, + &reserve, + &mut message, + )?; + // clear origin for subsequent custom instructions + message.push(ClearOrigin); + // append custom instructions message.extend(xcm.0.into_iter()); + if let Some(delivery_fee) = maybe_delivery_fee_from_assets { + // Put back delivery_fee in holding register to be charged by XcmSender. + self.holding.subsume_assets(delivery_fee); + } self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?; Ok(()) }); @@ -1033,37 +1157,143 @@ impl XcmExecutor { }, InitiateTeleport { assets, dest, xcm } => { let old_holding = self.holding.clone(); - 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 - // ourselves, so it's unlikely, but we don't want to allow that kind of bug - // to leak into a trusted chain. - Config::AssetTransactor::can_check_out(&dest, &asset, &self.context)?; - } - // Note that we pass `None` as `maybe_failed_bin` and drop any assets which - // cannot be reanchored because we have already checked all assets out. - let reanchored_assets = Self::reanchored(assets.clone(), &dest, None); - let mut message = vec![ReceiveTeleportedAsset(reanchored_assets), ClearOrigin]; + let result = Config::TransactionalProcessor::process(|| { + let mut assets = self.holding.saturating_take(assets); + // When not using `PayFees`, nor `JIT_WITHDRAW`, delivery fees are paid from + // transferred assets. + let maybe_delivery_fee_from_assets = if self.fees.is_empty() && !self.fees_mode.jit_withdraw { + // Deduct and return the part of `assets` that shall be used for delivery fees. + self.take_delivery_fee_from_assets(&mut assets, &dest, FeeReason::InitiateTeleport, &xcm)? + } else { + None + }; + let mut message = Vec::with_capacity(xcm.len() + 2); + Self::do_teleport_assets(assets, &dest, &mut message, &self.context)?; + // clear origin for subsequent custom instructions + message.push(ClearOrigin); + // append custom instructions message.extend(xcm.0.into_iter()); + if let Some(delivery_fee) = maybe_delivery_fee_from_assets { + // Put back delivery_fee in holding register to be charged by XcmSender. + self.holding.subsume_assets(delivery_fee); + } self.send(dest.clone(), Xcm(message), FeeReason::InitiateTeleport)?; + Ok(()) + }); + if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { + self.holding = old_holding; + } + result + }, + InitiateTransfer { destination, remote_fees, preserve_origin, assets, remote_xcm } => { + let old_holding = self.holding.clone(); + let result = Config::TransactionalProcessor::process(|| { + let mut message = Vec::with_capacity(assets.len() + remote_xcm.len() + 2); + + // We need to transfer the fees and buy execution on remote chain _BEFORE_ + // transferring the other assets. This is required to satisfy the + // `MAX_ASSETS_FOR_BUY_EXECUTION` limit in the `AllowTopLevelPaidExecutionFrom` + // barrier. + if let Some(remote_fees) = remote_fees { + let reanchored_fees = match remote_fees { + AssetTransferFilter::Teleport(fees_filter) => { + let teleport_fees = self + .holding + .try_take(fees_filter) + .map_err(|_| XcmError::NotHoldingFees)?; + Self::do_teleport_assets( + teleport_fees, + &destination, + &mut message, + &self.context, + )? + }, + AssetTransferFilter::ReserveDeposit(fees_filter) => { + let reserve_deposit_fees = self + .holding + .try_take(fees_filter) + .map_err(|_| XcmError::NotHoldingFees)?; + Self::do_reserve_deposit_assets( + reserve_deposit_fees, + &destination, + &mut message, + Some(&self.context), + )? + }, + AssetTransferFilter::ReserveWithdraw(fees_filter) => { + let reserve_withdraw_fees = self + .holding + .try_take(fees_filter) + .map_err(|_| XcmError::NotHoldingFees)?; + Self::do_reserve_withdraw_assets( + reserve_withdraw_fees, + &mut self.holding, + &destination, + &mut message, + )? + }, + }; + ensure!(reanchored_fees.len() == 1, XcmError::TooManyAssets); + let fees = + reanchored_fees.into_inner().pop().ok_or(XcmError::NotHoldingFees)?; + // move these assets to the fees register for covering execution and paying + // any subsequent fees + message.push(PayFees { asset: fees }); + } else { + // unpaid execution + message + .push(UnpaidExecution { weight_limit: Unlimited, check_origin: None }); + } - for asset in assets.assets_iter() { - Config::AssetTransactor::check_out(&dest, &asset, &self.context); + // add any extra asset transfers + for asset_filter in assets { + match asset_filter { + AssetTransferFilter::Teleport(assets) => Self::do_teleport_assets( + self.holding.saturating_take(assets), + &destination, + &mut message, + &self.context, + )?, + AssetTransferFilter::ReserveDeposit(assets) => + Self::do_reserve_deposit_assets( + self.holding.saturating_take(assets), + &destination, + &mut message, + Some(&self.context), + )?, + AssetTransferFilter::ReserveWithdraw(assets) => + Self::do_reserve_withdraw_assets( + self.holding.saturating_take(assets), + &mut self.holding, + &destination, + &mut message, + )?, + }; + } + if preserve_origin { + // preserve current origin for subsequent user-controlled instructions on + // remote chain + let original_origin = self + .origin_ref() + .cloned() + .and_then(|origin| { + Self::try_reanchor(origin, &destination) + .map(|(reanchored, _)| reanchored) + .ok() + }) + .ok_or(XcmError::BadOrigin)?; + message.push(AliasOrigin(original_origin)); + } else { + // clear origin for subsequent user-controlled instructions on remote chain + message.push(ClearOrigin); } + // append custom instructions + message.extend(remote_xcm.0.into_iter()); + // send the onward XCM + self.send(destination, Xcm(message), FeeReason::InitiateTransfer)?; Ok(()) - })(); - if result.is_err() { + }); + if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { self.holding = old_holding; } result @@ -1090,24 +1320,61 @@ impl XcmExecutor { let old_holding = self.holding.clone(); // Save the asset being used for execution fees, so we later know what should be // used for delivery fees. - self.asset_used_for_fees = Some(fees.id.clone()); - tracing::trace!(target: "xcm::executor::BuyExecution", asset_used_for_fees = ?self.asset_used_for_fees); + self.asset_used_in_buy_execution = Some(fees.id.clone()); + tracing::trace!( + target: "xcm::executor::BuyExecution", + asset_used_in_buy_execution = ?self.asset_used_in_buy_execution + ); // pay for `weight` using up to `fees` of the holding register. let max_fee = self.holding.try_take(fees.clone().into()).map_err(|e| { - tracing::error!(target: "xcm::process_instruction::buy_execution", ?e, ?fees, "Failed to take fees from holding"); + tracing::error!(target: "xcm::process_instruction::buy_execution", ?e, ?fees, + "Failed to take fees from holding"); XcmError::NotHoldingFees })?; - let result = || -> Result<(), XcmError> { + let result = Config::TransactionalProcessor::process(|| { let unspent = self.trader.buy_weight(weight, max_fee, &self.context)?; self.holding.subsume_assets(unspent); Ok(()) - }(); + }); if result.is_err() { self.holding = old_holding; } result }, + PayFees { asset } => { + // Message was not weighed, there is nothing to pay. + if self.message_weight == Weight::zero() { + tracing::warn!( + target: "xcm::executor::PayFees", + "Message was not weighed or weight was 0. Nothing will be charged.", + ); + return Ok(()); + } + // Record old holding in case we need to rollback. + let old_holding = self.holding.clone(); + // The max we're willing to pay for fees is decided by the `asset` operand. + tracing::trace!( + target: "xcm::executor::PayFees", + asset_for_fees = ?asset, + message_weight = ?self.message_weight, + ); + let max_fee = + self.holding.try_take(asset.into()).map_err(|_| XcmError::NotHoldingFees)?; + // Pay for execution fees. + let result = Config::TransactionalProcessor::process(|| { + let unspent = + self.trader.buy_weight(self.message_weight, max_fee, &self.context)?; + // Move unspent to the `fees` register. + self.fees.subsume_assets(unspent); + Ok(()) + }); + if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() { + // Rollback. + self.holding = old_holding; + } + result + }, RefundSurplus => self.refund_surplus(), SetErrorHandler(mut handler) => { let handler_weight = Config::Weigher::weight(&mut handler) @@ -1129,6 +1396,16 @@ impl XcmExecutor { self.error = None; Ok(()) }, + SetHints { hints } => { + for hint in hints.into_iter() { + match hint { + AssetClaimer { location } => { + self.asset_claimer = Some(location) + }, + } + } + Ok(()) + }, ClaimAsset { assets, ticket } => { let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; self.ensure_can_subsume_assets(assets.len())?; @@ -1338,7 +1615,7 @@ impl XcmExecutor { ExchangeAsset { give, want, maximal } => { let old_holding = self.holding.clone(); let give = self.holding.saturating_take(give); - let result = (|| -> Result<(), XcmError> { + let result = Config::TransactionalProcessor::process(|| { self.ensure_can_subsume_assets(want.len())?; let exchange_result = Config::AssetExchanger::exchange_asset( self.origin_ref(), @@ -1352,7 +1629,7 @@ impl XcmExecutor { } else { Err(XcmError::NoDeal) } - })(); + }); if result.is_err() { self.holding = old_holding; } @@ -1404,6 +1681,23 @@ impl XcmExecutor { } } + fn do_descend_origin(&mut self, who: InteriorLocation) -> XcmResult { + self.context + .origin + .as_mut() + .ok_or(XcmError::BadOrigin)? + .append_with(who) + .map_err(|e| { + tracing::error!(target: "xcm::do_descend_origin", ?e, "Failed to append junctions"); + XcmError::LocationFull + }) + } + + fn do_clear_origin(&mut self) -> XcmResult { + self.context.origin = None; + Ok(()) + } + /// Deposit `to_deposit` assets to `beneficiary`, without giving up on the first (transient) /// error, and retrying once just in case one of the subsequently deposited assets satisfy some /// requirement. @@ -1414,16 +1708,15 @@ impl XcmExecutor { /// This function can write into storage and also return an error at the same time, it should /// always be called within a transactional context. fn deposit_assets_with_retry( - &mut self, to_deposit: &AssetsInHolding, beneficiary: &Location, + context: Option<&XcmContext>, ) -> Result<(), XcmError> { let mut failed_deposits = Vec::with_capacity(to_deposit.len()); let mut deposit_result = Ok(()); for asset in to_deposit.assets_iter() { - deposit_result = - Config::AssetTransactor::deposit_asset(&asset, &beneficiary, Some(&self.context)); + deposit_result = Config::AssetTransactor::deposit_asset(&asset, &beneficiary, context); // if deposit failed for asset, mark it for retry after depositing the others. if deposit_result.is_err() { failed_deposits.push(asset); @@ -1441,8 +1734,55 @@ impl XcmExecutor { // retry previously failed deposits, this time short-circuiting on any error. for asset in failed_deposits { - Config::AssetTransactor::deposit_asset(&asset, &beneficiary, Some(&self.context))?; + Config::AssetTransactor::deposit_asset(&asset, &beneficiary, context)?; } Ok(()) } + + /// Take from transferred `assets` the delivery fee required to send an onward transfer message + /// to `destination`. + /// + /// Will be removed once the transition from `BuyExecution` to `PayFees` is complete. + fn take_delivery_fee_from_assets( + &self, + assets: &mut AssetsInHolding, + destination: &Location, + reason: FeeReason, + xcm: &Xcm<()>, + ) -> Result, XcmError> { + let to_weigh = assets.clone(); + let to_weigh_reanchored = Self::reanchored(to_weigh, &destination, None); + let remote_instruction = match reason { + FeeReason::DepositReserveAsset => ReserveAssetDeposited(to_weigh_reanchored), + FeeReason::InitiateReserveWithdraw => WithdrawAsset(to_weigh_reanchored), + FeeReason::InitiateTeleport => ReceiveTeleportedAsset(to_weigh_reanchored), + _ => { + tracing::debug!( + target: "xcm::take_delivery_fee_from_assets", + "Unexpected delivery fee reason", + ); + return Err(XcmError::NotHoldingFees); + }, + }; + let mut message_to_weigh = Vec::with_capacity(xcm.len() + 2); + message_to_weigh.push(remote_instruction); + message_to_weigh.push(ClearOrigin); + message_to_weigh.extend(xcm.0.clone().into_iter()); + let (_, fee) = + validate_send::(destination.clone(), Xcm(message_to_weigh))?; + let maybe_delivery_fee = fee.get(0).map(|asset_needed_for_fees| { + tracing::trace!( + target: "xcm::fees::take_delivery_fee_from_assets", + "Asset provided to pay for fees {:?}, asset required for delivery fees: {:?}", + self.asset_used_in_buy_execution, asset_needed_for_fees, + ); + let asset_to_pay_for_fees = + self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone()); + // set aside fee to be charged by XcmSender + let delivery_fee = assets.saturating_take(asset_to_pay_for_fees.into()); + tracing::trace!(target: "xcm::fees::take_delivery_fee_from_assets", ?delivery_fee); + delivery_fee + }); + Ok(maybe_delivery_fee) + } } diff --git a/polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs b/polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs new file mode 100644 index 000000000000..daba8ae1c036 --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/tests/execute_with_origin.rs @@ -0,0 +1,177 @@ +// 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 . + +//! Unit tests for the `ExecuteWithOrigin` instruction. +//! +//! See the [XCM RFC](https://github.com/polkadot-fellows/xcm-format/pull/38) +//! and the [specification](https://github.com/polkadot-fellows/xcm-format/tree/8cef08e375c6f6d3966909ccf773ed46ac703917) for more information. +//! +//! The XCM RFCs were moved to the fellowship RFCs but this one was approved and merged before that. + +use xcm::prelude::*; + +use super::mock::*; +use crate::ExecutorError; + +// The sender and recipient we use across these tests. +const SENDER_1: [u8; 32] = [0; 32]; +const SENDER_2: [u8; 32] = [1; 32]; +const RECIPIENT: [u8; 32] = [2; 32]; + +// ===== Happy path ===== + +// In this test, root descends into one account to pay fees, pops that origin +// and descends into a second account to withdraw funds. +// These assets can now be used to perform actions as root. +#[test] +fn root_can_descend_into_more_than_one_account() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER_1, (Here, 10u128)); + add_asset(SENDER_2, (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder_unsafe() + .execute_with_origin( + Some(SENDER_1.into()), + Xcm::::builder_unsafe() + .withdraw_asset((Here, 10u128)) + .pay_fees((Here, 10u128)) + .build(), + ) + .execute_with_origin( + Some(SENDER_2.into()), + Xcm::::builder_unsafe().withdraw_asset((Here, 100u128)).build(), + ) + .expect_origin(Some(Here.into())) + .deposit_asset(All, RECIPIENT) + .build(); + + let (mut vm, weight) = instantiate_executor(Here, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + assert!(vm.bench_post_process(weight).ensure_complete().is_ok()); + + // RECIPIENT gets the funds. + assert_eq!(asset_list(RECIPIENT), [(Here, 100u128).into()]); +} + +// ExecuteWithOrigin works for clearing the origin as well. +#[test] +fn works_for_clearing_origin() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER_1, (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder_unsafe() + // Root code. + .expect_origin(Some(Here.into())) + .execute_with_origin( + None, + // User code, we run it with no origin. + Xcm::::builder_unsafe().expect_origin(None).build(), + ) + // We go back to root code. + .build(); + + let (mut vm, weight) = instantiate_executor(Here, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + assert!(vm.bench_post_process(weight).ensure_complete().is_ok()); +} + +// Setting the error handler or appendix inside of `ExecuteWithOrigin` +// will work as expected. +#[test] +fn set_error_handler_and_appendix_work() { + add_asset(SENDER_1, (Here, 110u128)); + + let xcm = Xcm::::builder_unsafe() + .execute_with_origin( + Some(SENDER_1.into()), + Xcm::::builder_unsafe() + .withdraw_asset((Here, 110u128)) + .pay_fees((Here, 10u128)) + .set_error_handler( + Xcm::::builder_unsafe() + .deposit_asset(vec![(Here, 10u128).into()], SENDER_2) + .build(), + ) + .set_appendix( + Xcm::::builder_unsafe().deposit_asset(All, RECIPIENT).build(), + ) + .build(), + ) + .build(); + + let (mut vm, weight) = instantiate_executor(Here, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + + assert_eq!( + vm.error_handler(), + &Xcm::(vec![DepositAsset { + assets: vec![Asset { id: AssetId(Location::new(0, [])), fun: Fungible(10) }].into(), + beneficiary: Location::new(0, [AccountId32 { id: SENDER_2, network: None }]), + },]) + ); + assert_eq!( + vm.appendix(), + &Xcm::(vec![DepositAsset { + assets: All.into(), + beneficiary: Location::new(0, [AccountId32 { id: RECIPIENT, network: None }]), + },]) + ); + + assert!(vm.bench_post_process(weight).ensure_complete().is_ok()); +} + +// ===== Unhappy path ===== + +// Processing still can't be called recursively more than the limit. +#[test] +fn recursion_exceeds_limit() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER_1, (Here, 10u128)); + add_asset(SENDER_2, (Here, 100u128)); + + let mut xcm = Xcm::::builder_unsafe() + .execute_with_origin(None, Xcm::::builder_unsafe().clear_origin().build()) + .build(); + + // 10 is the RECURSION_LIMIT. + for _ in 0..10 { + let clone_of_xcm = xcm.clone(); + if let ExecuteWithOrigin { xcm: ref mut inner, .. } = xcm.inner_mut()[0] { + *inner = clone_of_xcm; + } + } + + let (mut vm, weight) = instantiate_executor(Here, xcm.clone()); + + // Program errors with `ExceedsStackLimit`. + assert_eq!( + vm.bench_process(xcm), + Err(ExecutorError { + index: 0, + xcm_error: XcmError::ExceedsStackLimit, + weight: Weight::zero(), + }) + ); + assert!(vm.bench_post_process(weight).ensure_complete().is_ok()); +} diff --git a/polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs b/polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs new file mode 100644 index 000000000000..09ed1f44cc4a --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/tests/initiate_transfer.rs @@ -0,0 +1,106 @@ +// 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 . + +//! Unit tests related to the `InitiateTransfer` instruction. +//! +//! See [Fellowship RFC 100](https://github.com/polkadot-fellows/rfCs/pull/100), +//! [Fellowship RFC 122](https://github.com/polkadot-fellows/rfCs/pull/122), and the +//! [specification](https://github.com/polkadot-fellows/xcm-format) for more information. + +use xcm::{latest::AssetTransferFilter, prelude::*}; + +use super::mock::*; + +// The sender and recipient we use across these tests. +const SENDER: [u8; 32] = [0; 32]; +const RECIPIENT: [u8; 32] = [1; 32]; + +#[test] +fn clears_origin() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + let xcm_on_dest = + Xcm(vec![RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: RECIPIENT.into() }]); + let assets: Assets = (Here, 90u128).into(); + let xcm = Xcm::(vec![ + WithdrawAsset((Here, 100u128).into()), + PayFees { asset: (Here, 10u128).into() }, + InitiateTransfer { + destination: Parent.into(), + remote_fees: Some(AssetTransferFilter::ReserveDeposit(assets.into())), + preserve_origin: false, + assets: vec![], + remote_xcm: xcm_on_dest, + }, + ]); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + let res = vm.bench_process(xcm); + assert!(res.is_ok(), "execution error {:?}", res); + + let (dest, sent_message) = sent_xcm().pop().unwrap(); + assert_eq!(dest, Parent.into()); + assert_eq!(sent_message.len(), 5); + let mut instr = sent_message.inner().iter(); + assert!(matches!(instr.next().unwrap(), ReserveAssetDeposited(..))); + assert!(matches!(instr.next().unwrap(), PayFees { .. })); + assert!(matches!(instr.next().unwrap(), ClearOrigin)); + assert!(matches!(instr.next().unwrap(), RefundSurplus)); + assert!(matches!(instr.next().unwrap(), DepositAsset { .. })); +} + +#[test] +fn preserves_origin() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + let xcm_on_dest = + Xcm(vec![RefundSurplus, DepositAsset { assets: Wild(All), beneficiary: RECIPIENT.into() }]); + let assets: Assets = (Here, 90u128).into(); + let xcm = Xcm::(vec![ + WithdrawAsset((Here, 100u128).into()), + PayFees { asset: (Here, 10u128).into() }, + InitiateTransfer { + destination: Parent.into(), + remote_fees: Some(AssetTransferFilter::ReserveDeposit(assets.into())), + preserve_origin: true, + assets: vec![], + remote_xcm: xcm_on_dest, + }, + ]); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + let res = vm.bench_process(xcm); + assert!(res.is_ok(), "execution error {:?}", res); + + let (dest, sent_message) = sent_xcm().pop().unwrap(); + assert_eq!(dest, Parent.into()); + assert_eq!(sent_message.len(), 5); + let mut instr = sent_message.inner().iter(); + assert!(matches!(instr.next().unwrap(), ReserveAssetDeposited(..))); + assert!(matches!(instr.next().unwrap(), PayFees { .. })); + assert!(matches!( + instr.next().unwrap(), + AliasOrigin(origin) if matches!(origin.unpack(), (0, [Parachain(1000), AccountId32 { id: SENDER, network: None }])) + )); + assert!(matches!(instr.next().unwrap(), RefundSurplus)); + assert!(matches!(instr.next().unwrap(), DepositAsset { .. })); +} diff --git a/polkadot/xcm/xcm-executor/src/tests/mock.rs b/polkadot/xcm/xcm-executor/src/tests/mock.rs new file mode 100644 index 000000000000..9cf258331f38 --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/tests/mock.rs @@ -0,0 +1,279 @@ +// 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 . + +//! Mock types and XcmConfig for all executor unit tests. + +use alloc::collections::btree_map::BTreeMap; +use codec::{Decode, Encode}; +use core::cell::RefCell; +use frame_support::{ + dispatch::{DispatchInfo, DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo}, + parameter_types, + traits::{Everything, Nothing, ProcessMessageError}, + weights::Weight, +}; +use sp_runtime::traits::Dispatchable; +use xcm::prelude::*; + +use crate::{ + traits::{DropAssets, Properties, ShouldExecute, TransactAsset, WeightBounds, WeightTrader}, + AssetsInHolding, Config, XcmExecutor, +}; + +/// We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we +/// can inspect its fields. +pub fn instantiate_executor( + origin: impl Into, + message: Xcm<::RuntimeCall>, +) -> (XcmExecutor, Weight) { + let mut vm = + XcmExecutor::::new(origin, message.using_encoded(sp_io::hashing::blake2_256)); + let weight = XcmExecutor::::prepare(message.clone()).unwrap().weight_of(); + vm.message_weight = weight; + (vm, weight) +} + +parameter_types! { + pub const MaxAssetsIntoHolding: u32 = 10; + pub const BaseXcmWeight: Weight = Weight::from_parts(1, 1); + pub const MaxInstructions: u32 = 10; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)].into(); +} + +/// Test origin. +#[derive(Debug)] +pub struct TestOrigin; + +/// Test call. +/// +/// Doesn't dispatch anything, has an empty implementation of [`Dispatchable`] that +/// just returns `Ok` with an empty [`PostDispatchInfo`]. +#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone, Copy, scale_info::TypeInfo)] +pub struct TestCall; +impl Dispatchable for TestCall { + type RuntimeOrigin = TestOrigin; + type Config = (); + type Info = (); + type PostInfo = PostDispatchInfo; + + fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo { + Ok(PostDispatchInfo::default()) + } +} +impl GetDispatchInfo for TestCall { + fn get_dispatch_info(&self) -> DispatchInfo { + DispatchInfo::default() + } +} + +/// Test weigher that just returns a fixed weight for every program. +pub struct TestWeigher; +impl WeightBounds for TestWeigher { + fn weight(_message: &mut Xcm) -> Result { + Ok(Weight::from_parts(2, 2)) + } + + fn instr_weight(_instruction: &mut Instruction) -> Result { + Ok(Weight::from_parts(2, 2)) + } +} + +thread_local! { + pub static ASSETS: RefCell> = RefCell::new(BTreeMap::new()); + pub static SENT_XCM: RefCell)>> = RefCell::new(Vec::new()); +} + +pub fn add_asset(who: impl Into, what: impl Into) { + ASSETS.with(|a| { + a.borrow_mut() + .entry(who.into()) + .or_insert(AssetsInHolding::new()) + .subsume(what.into()) + }); +} + +pub fn asset_list(who: impl Into) -> Vec { + Assets::from(assets(who)).into_inner() +} + +pub fn assets(who: impl Into) -> AssetsInHolding { + ASSETS.with(|a| a.borrow().get(&who.into()).cloned()).unwrap_or_default() +} + +pub fn get_first_fungible(assets: &AssetsInHolding) -> Option { + assets.fungible_assets_iter().next() +} + +/// Test asset transactor that withdraws from and deposits to a thread local assets storage. +pub struct TestAssetTransactor; +impl TransactAsset for TestAssetTransactor { + fn deposit_asset( + what: &Asset, + who: &Location, + _context: Option<&XcmContext>, + ) -> Result<(), XcmError> { + add_asset(who.clone(), what.clone()); + Ok(()) + } + + fn withdraw_asset( + what: &Asset, + who: &Location, + _context: Option<&XcmContext>, + ) -> Result { + ASSETS.with(|a| { + a.borrow_mut() + .get_mut(who) + .ok_or(XcmError::NotWithdrawable)? + .try_take(what.clone().into()) + .map_err(|_| XcmError::NotWithdrawable) + }) + } +} + +/// Test barrier that just lets everything through. +pub struct TestBarrier; +impl ShouldExecute for TestBarrier { + fn should_execute( + _origin: &Location, + _instructions: &mut [Instruction], + _max_weight: Weight, + _properties: &mut Properties, + ) -> Result<(), ProcessMessageError> { + Ok(()) + } +} + +/// Test weight to fee that just multiplies `Weight.ref_time` and `Weight.proof_size`. +pub struct WeightToFee; +impl WeightToFee { + pub fn weight_to_fee(weight: &Weight) -> u128 { + weight.ref_time() as u128 * weight.proof_size() as u128 + } +} + +/// Test weight trader that just buys weight with the native asset (`Here`) and +/// uses the test `WeightToFee`. +pub struct TestTrader { + weight_bought_so_far: Weight, +} +impl WeightTrader for TestTrader { + fn new() -> Self { + Self { weight_bought_so_far: Weight::zero() } + } + + fn buy_weight( + &mut self, + weight: Weight, + payment: AssetsInHolding, + _context: &XcmContext, + ) -> Result { + let amount = WeightToFee::weight_to_fee(&weight); + let required: Asset = (Here, amount).into(); + let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?; + self.weight_bought_so_far.saturating_add(weight); + Ok(unused) + } + + fn refund_weight(&mut self, weight: Weight, _context: &XcmContext) -> Option { + let weight = weight.min(self.weight_bought_so_far); + let amount = WeightToFee::weight_to_fee(&weight); + self.weight_bought_so_far -= weight; + if amount > 0 { + Some((Here, amount).into()) + } else { + None + } + } +} + +/// Account where all dropped assets are deposited. +pub const TRAPPED_ASSETS: [u8; 32] = [255; 32]; + +/// Test asset trap that moves all dropped assets to the `TRAPPED_ASSETS` account. +pub struct TestAssetTrap; +impl DropAssets for TestAssetTrap { + fn drop_assets(_origin: &Location, assets: AssetsInHolding, _context: &XcmContext) -> Weight { + ASSETS.with(|a| { + a.borrow_mut() + .entry(TRAPPED_ASSETS.into()) + .or_insert(AssetsInHolding::new()) + .subsume_assets(assets) + }); + Weight::zero() + } +} + +/// Test sender that always succeeds and puts messages in a dummy queue. +/// +/// It charges `1` for the delivery fee. +pub struct TestSender; +impl SendXcm for TestSender { + type Ticket = (Location, Xcm<()>); + + fn validate( + destination: &mut Option, + message: &mut Option>, + ) -> SendResult { + let ticket = (destination.take().unwrap(), message.take().unwrap()); + let delivery_fee: Asset = (Here, 1u128).into(); + Ok((ticket, delivery_fee.into())) + } + + fn deliver(ticket: Self::Ticket) -> Result { + SENT_XCM.with(|q| q.borrow_mut().push(ticket)); + Ok([0; 32]) + } +} + +/// Gets queued test messages. +pub fn sent_xcm() -> Vec<(Location, Xcm<()>)> { + SENT_XCM.with(|q| (*q.borrow()).clone()) +} + +/// Test XcmConfig that uses all the test implementations in this file. +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = TestCall; + type XcmSender = TestSender; + type AssetTransactor = TestAssetTransactor; + type OriginConverter = (); + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = TestBarrier; + type Weigher = TestWeigher; + type Trader = TestTrader; + type ResponseHandler = (); + type AssetTrap = TestAssetTrap; + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = Self::RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} diff --git a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs b/polkadot/xcm/xcm-executor/src/tests/mod.rs similarity index 68% rename from polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs rename to polkadot/xcm/xcm-executor/src/tests/mod.rs index dc5c679a96e7..15a0565e357c 100644 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/buy_execution_named_fields.rs +++ b/polkadot/xcm/xcm-executor/src/tests/mod.rs @@ -14,17 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Test error when the `BuyExecution` instruction doesn't take named fields. - -use xcm_procedural::Builder; - -struct Xcm(pub Vec>); - -#[derive(Builder)] -enum Instruction { - BuyExecution(u128), - UnpaidExecution { weight_limit: (u32, u32) }, - Transact { call: Call }, -} - -fn main() {} +//! Unit tests for the XCM executor. +//! +//! These exclude any cross-chain functionality. For those, look at the +//! `xcm-emulator` based tests in the cumulus folder. +//! These tests deal with internal state changes of the XCVM. + +mod execute_with_origin; +mod initiate_transfer; +mod mock; +mod pay_fees; +mod set_asset_claimer; diff --git a/polkadot/xcm/xcm-executor/src/tests/pay_fees.rs b/polkadot/xcm/xcm-executor/src/tests/pay_fees.rs new file mode 100644 index 000000000000..4c196831e6a4 --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/tests/pay_fees.rs @@ -0,0 +1,257 @@ +// 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 . + +//! Unit tests related to the `fees` register and `PayFees` instruction. +//! +//! See [Fellowship RFC 105](https://github.com/polkadot-fellows/rfCs/pull/105) +//! and the [specification](https://github.com/polkadot-fellows/xcm-format) for more information. + +use xcm::prelude::*; + +use super::mock::*; + +// The sender and recipient we use across these tests. +const SENDER: [u8; 32] = [0; 32]; +const RECIPIENT: [u8; 32] = [1; 32]; + +// ===== Happy path ===== + +// This is a sort of backwards compatibility test. +// Since `PayFees` is a replacement for `BuyExecution`, we need to make sure it at least +// manages to do the same thing, paying for execution fees. +#[test] +fn works_for_execution_fees() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder() + .withdraw_asset((Here, 100u128)) + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .deposit_asset(All, RECIPIENT) + .build(); + + let (mut vm, weight) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + + // Nothing is left in the `holding` register. + assert_eq!(get_first_fungible(vm.holding()), None); + // Execution fees were 4, so we still have 6 left in the `fees` register. + assert_eq!(get_first_fungible(vm.fees()).unwrap(), (Here, 6u128).into()); + + // The recipient received all the assets in the holding register, so `100` that + // were withdrawn, minus the `10` that were destinated for fee payment. + assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]); + + // Leftover fees get trapped. + assert!(vm.bench_post_process(weight).ensure_complete().is_ok()); + assert_eq!(asset_list(TRAPPED_ASSETS), [(Here, 6u128).into()]) +} + +// This tests the new functionality provided by `PayFees`, being able to pay for +// delivery fees from the `fees` register. +#[test] +fn works_for_delivery_fees() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + // Information to send messages. + // We don't care about the specifics since we're not actually sending them. + let query_response_info = + QueryResponseInfo { destination: Parent.into(), query_id: 0, max_weight: Weight::zero() }; + + // Build xcm. + let xcm = Xcm::::builder() + .withdraw_asset((Here, 100u128)) + .pay_fees((Here, 10u128)) + // Send a bunch of messages, each charging delivery fees. + .report_error(query_response_info.clone()) + .report_error(query_response_info.clone()) + .report_error(query_response_info) + .deposit_asset(All, RECIPIENT) + .build(); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + + // Nothing is left in the `holding` register. + assert_eq!(get_first_fungible(vm.holding()), None); + // Execution fees were 4, delivery were 3, so we are left with only 3 in the `fees` register. + assert_eq!(get_first_fungible(vm.fees()).unwrap(), (Here, 3u128).into()); + + // The recipient received all the assets in the holding register, so `100` that + // were withdrawn, minus the `10` that were destinated for fee payment. + assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]); + + let querier: Location = + (Parachain(1000), AccountId32 { id: SENDER.into(), network: None }).into(); + let sent_message = Xcm(vec![QueryResponse { + query_id: 0, + response: Response::ExecutionResult(None), + max_weight: Weight::zero(), + querier: Some(querier), + }]); + + // The messages were "sent" successfully. + assert_eq!( + sent_xcm(), + vec![ + (Parent.into(), sent_message.clone()), + (Parent.into(), sent_message.clone()), + (Parent.into(), sent_message.clone()) + ] + ); +} + +// Tests the support for `BuyExecution` while the ecosystem transitions to `PayFees`. +#[test] +fn buy_execution_works_as_before() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder() + .withdraw_asset((Here, 100u128)) + // We can put everything here, since excess will be returned to holding. + // We have to specify `Limited` here to actually work, it's normally + // set in the `AllowTopLevelPaidExecutionFrom` barrier. + .buy_execution((Here, 100u128), Limited(Weight::from_parts(2, 2))) + .deposit_asset(All, RECIPIENT) + .build(); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + + // Nothing is left in the `holding` register. + assert_eq!(get_first_fungible(vm.holding()), None); + // `BuyExecution` does not interact with the `fees` register. + assert_eq!(get_first_fungible(vm.fees()), None); + + // The recipient received all the assets in the holding register, so `100` that + // were withdrawn, minus the `4` from paying the execution fees. + assert_eq!(asset_list(RECIPIENT), [(Here, 96u128).into()]); +} + +// Tests the interaction between `PayFees` and `RefundSurplus`. +#[test] +fn fees_can_be_refunded() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder() + .withdraw_asset((Here, 100u128)) + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .deposit_asset(All, RECIPIENT) + .refund_surplus() + .deposit_asset(All, SENDER) + .build(); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + + // Nothing is left in the `holding` register. + assert_eq!(get_first_fungible(vm.holding()), None); + // Nothing was left in the `fees` register since it was refunded. + assert_eq!(get_first_fungible(vm.fees()), None); + + // The recipient received all the assets in the holding register, so `100` that + // were withdrawn, minus the `10` that were destinated for fee payment. + assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]); + + // The sender got back `6` from unused assets. + assert_eq!(asset_list(SENDER), [(Here, 6u128).into()]); +} + +// ===== Unhappy path ===== + +#[test] +fn putting_all_assets_in_pay_fees() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder() + .withdraw_asset((Here, 100u128)) + .pay_fees((Here, 100u128)) // 100% destined for fees, this is not going to end well... + .deposit_asset(All, RECIPIENT) + .build(); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program runs successfully. + assert!(vm.bench_process(xcm).is_ok()); + + // Nothing is left in the `holding` register. + assert_eq!(get_first_fungible(vm.holding()), None); + // We destined `100` for fee payment, after `4` for execution fees, we are left with `96`. + assert_eq!(get_first_fungible(vm.fees()).unwrap(), (Here, 96u128).into()); + + // The recipient received no assets since they were all destined for fee payment. + assert_eq!(asset_list(RECIPIENT), []); +} + +#[test] +fn refunding_too_early() { + // Make sure the sender has enough funds to withdraw. + add_asset(SENDER, (Here, 100u128)); + + // Information to send messages. + // We don't care about the specifics since we're not actually sending them. + let query_response_info = + QueryResponseInfo { destination: Parent.into(), query_id: 0, max_weight: Weight::zero() }; + + // Build xcm. + let xcm = Xcm::::builder() + .withdraw_asset((Here, 100u128)) + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .deposit_asset(All, RECIPIENT) + .refund_surplus() + .deposit_asset(All, SENDER) + // `refund_surplus` cleared the `fees` register. + // `holding` is used as a fallback, but we also cleared that. + // The instruction will error and the message won't be sent :(. + .report_error(query_response_info) + .build(); + + let (mut vm, _) = instantiate_executor(SENDER, xcm.clone()); + + // Program fails to run. + assert!(vm.bench_process(xcm).is_err()); + + // Nothing is left in the `holding` register. + assert_eq!(get_first_fungible(vm.holding()), None); + // Nothing was left in the `fees` register since it was refunded. + assert_eq!(get_first_fungible(vm.fees()), None); + + // The recipient received all the assets in the holding register, so `100` that + // were withdrawn, minus the `10` that were destinated for fee payment. + assert_eq!(asset_list(RECIPIENT), [(Here, 90u128).into()]); + + // The sender got back `6` from unused assets. + assert_eq!(asset_list(SENDER), [(Here, 6u128).into()]); + + // No messages were "sent". + assert_eq!(sent_xcm(), Vec::new()); +} diff --git a/polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs b/polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs new file mode 100644 index 000000000000..cc97e2b3a16e --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/tests/set_asset_claimer.rs @@ -0,0 +1,138 @@ +// 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 . + +//! Unit tests related to the `fees` register and `PayFees` instruction. +//! +//! See [Fellowship RFC 105](https://github.com/polkadot-fellows/rfCs/pull/105) +//! and the [specification](https://github.com/polkadot-fellows/xcm-format) for more information. + +use codec::Encode; +use xcm::prelude::*; + +use super::mock::*; +use crate::XcmExecutor; + +#[test] +fn set_asset_claimer() { + let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]); + let bob = Location::new(0, [AccountId32 { id: [2; 32], network: None }]); + + // Make sure the user has enough funds to withdraw. + add_asset(sender.clone(), (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder_unsafe() + // if withdrawing fails we're not missing any corner case. + .withdraw_asset((Here, 100u128)) + .clear_origin() + .set_hints(vec![AssetClaimer { location: bob.clone() }]) + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .build(); + + // We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we + // can inspect its fields. + let mut vm = + XcmExecutor::::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256)); + vm.message_weight = XcmExecutor::::prepare(xcm.clone()).unwrap().weight_of(); + + let result = vm.bench_process(xcm); + assert!(result.is_ok()); + assert_eq!(vm.asset_claimer(), Some(bob)); +} + +#[test] +fn do_not_set_asset_claimer_none() { + let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]); + + // Make sure the user has enough funds to withdraw. + add_asset(sender.clone(), (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder_unsafe() + // if withdrawing fails we're not missing any corner case. + .withdraw_asset((Here, 100u128)) + .clear_origin() + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .build(); + + // We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we + // can inspect its fields. + let mut vm = + XcmExecutor::::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256)); + vm.message_weight = XcmExecutor::::prepare(xcm.clone()).unwrap().weight_of(); + + let result = vm.bench_process(xcm); + assert!(result.is_ok()); + assert_eq!(vm.asset_claimer(), None); +} + +#[test] +fn trap_then_set_asset_claimer() { + let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]); + let bob = Location::new(0, [AccountId32 { id: [2; 32], network: None }]); + + // Make sure the user has enough funds to withdraw. + add_asset(sender.clone(), (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder_unsafe() + // if withdrawing fails we're not missing any corner case. + .withdraw_asset((Here, 100u128)) + .clear_origin() + .trap(0u64) + .set_hints(vec![AssetClaimer { location: bob }]) + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .build(); + + // We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we + // can inspect its fields. + let mut vm = + XcmExecutor::::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256)); + vm.message_weight = XcmExecutor::::prepare(xcm.clone()).unwrap().weight_of(); + + let result = vm.bench_process(xcm); + assert!(result.is_err()); + assert_eq!(vm.asset_claimer(), None); +} + +#[test] +fn set_asset_claimer_then_trap() { + let sender = Location::new(0, [AccountId32 { id: [0; 32], network: None }]); + let bob = Location::new(0, [AccountId32 { id: [2; 32], network: None }]); + + // Make sure the user has enough funds to withdraw. + add_asset(sender.clone(), (Here, 100u128)); + + // Build xcm. + let xcm = Xcm::::builder_unsafe() + // if withdrawing fails we're not missing any corner case. + .withdraw_asset((Here, 100u128)) + .clear_origin() + .set_hints(vec![AssetClaimer { location: bob.clone() }]) + .trap(0u64) + .pay_fees((Here, 10u128)) // 10% destined for fees, not more. + .build(); + + // We create an XCVM instance instead of calling `XcmExecutor::<_>::prepare_and_execute` so we + // can inspect its fields. + let mut vm = + XcmExecutor::::new(sender, xcm.using_encoded(sp_io::hashing::blake2_256)); + vm.message_weight = XcmExecutor::::prepare(xcm.clone()).unwrap().weight_of(); + + let result = vm.bench_process(xcm); + assert!(result.is_err()); + assert_eq!(vm.asset_claimer(), Some(bob)); +} diff --git a/polkadot/xcm/xcm-executor/src/traits/export.rs b/polkadot/xcm/xcm-executor/src/traits/export.rs index b356e0da7df7..3e9275edab37 100644 --- a/polkadot/xcm/xcm-executor/src/traits/export.rs +++ b/polkadot/xcm/xcm-executor/src/traits/export.rs @@ -108,7 +108,7 @@ impl ExportXcm for Tuple { } /// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps -/// both in `Some` before passing them as as mutable references into `T::send_xcm`. +/// both in `Some` before passing them as mutable references into `T::send_xcm`. pub fn validate_export( network: NetworkId, channel: u32, @@ -120,7 +120,7 @@ pub fn validate_export( } /// Convenience function for using a `SendXcm` implementation. Just interprets the `dest` and wraps -/// both in `Some` before passing them as as mutable references into `T::send_xcm`. +/// both in `Some` before passing them as mutable references into `T::send_xcm`. /// /// Returns either `Ok` with the price of the delivery, or `Err` with the reason why the message /// could not be sent. diff --git a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs index b6e303daaad8..256f47fec4f0 100644 --- a/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs +++ b/polkadot/xcm/xcm-executor/src/traits/fee_manager.rs @@ -39,6 +39,8 @@ pub enum FeeReason { InitiateReserveWithdraw, /// When the `InitiateTeleport` instruction is called. InitiateTeleport, + /// When the `InitiateTransfer` instruction is called. + InitiateTransfer, /// When the `QueryPallet` instruction is called. QueryPallet, /// When the `ExportMessage` instruction is called (and includes the network ID). diff --git a/polkadot/xcm/xcm-executor/src/traits/weight.rs b/polkadot/xcm/xcm-executor/src/traits/weight.rs index 61545c330621..4e41aa5b4753 100644 --- a/polkadot/xcm/xcm-executor/src/traits/weight.rs +++ b/polkadot/xcm/xcm-executor/src/traits/weight.rs @@ -26,7 +26,7 @@ pub trait WeightBounds { /// Return the maximum amount of weight that an attempted execution of this instruction could /// consume. - fn instr_weight(instruction: &Instruction) -> Result; + fn instr_weight(instruction: &mut Instruction) -> Result; } /// Charge for weight in order to execute XCM. diff --git a/polkadot/xcm/xcm-runtime-apis/Cargo.toml b/polkadot/xcm/xcm-runtime-apis/Cargo.toml index 9ccca76c321c..96afb10e5397 100644 --- a/polkadot/xcm/xcm-runtime-apis/Cargo.toml +++ b/polkadot/xcm/xcm-runtime-apis/Cargo.toml @@ -21,17 +21,17 @@ xcm = { workspace = true } xcm-executor = { workspace = true } [dev-dependencies] +frame-executive = { workspace = true } frame-system = { workspace = true } -sp-io = { workspace = true } -xcm-builder = { workspace = true } hex-literal = { workspace = true } -pallet-xcm = { workspace = true } -pallet-balances = { workspace = true } -pallet-assets = { workspace = true } -xcm-executor = { workspace = true } -frame-executive = { workspace = true } log = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } +pallet-xcm = { workspace = true } +sp-io = { workspace = true } sp-tracing = { workspace = true, default-features = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } [features] default = ["std"] @@ -60,4 +60,5 @@ runtime-benchmarks = [ "pallet-xcm/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index 2d14b4e571c6..c3046b134d1f 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -353,3 +353,26 @@ fn dry_run_xcm() { ); }); } + +#[test] +fn calling_payment_api_with_a_lower_version_works() { + let transfer_amount = 100u128; + let xcm_to_weigh = Xcm::::builder_unsafe() + .withdraw_asset((Here, transfer_amount)) + .buy_execution((Here, transfer_amount), Unlimited) + .deposit_asset(AllCounted(1), [1u8; 32]) + .build(); + let versioned_xcm_to_weigh = VersionedXcm::from(xcm_to_weigh.clone().into()); + let lower_version_xcm_to_weigh = versioned_xcm_to_weigh.into_version(XCM_VERSION - 1).unwrap(); + let client = TestClient; + let runtime_api = client.runtime_api(); + let xcm_weight = + runtime_api.query_xcm_weight(H256::zero(), lower_version_xcm_to_weigh).unwrap(); + assert!(xcm_weight.is_ok()); + let native_token = VersionedAssetId::from(AssetId(Here.into())); + let lower_version_native_token = native_token.into_version(XCM_VERSION - 1).unwrap(); + let execution_fees = runtime_api + .query_weight_to_asset_fee(H256::zero(), xcm_weight.unwrap(), lower_version_native_token) + .unwrap(); + assert!(execution_fees.is_ok()); +} diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 4a5de8875007..fb5d1ae7c0e5 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -144,7 +144,7 @@ parameter_types! { pub const BaseXcmWeight: Weight = Weight::from_parts(100, 10); // Random value. pub const MaxInstructions: u32 = 100; pub const NativeTokenPerSecondPerByte: (AssetId, u128, u128) = (AssetId(HereLocation::get()), 1, 1); - pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(2000)].into(); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(2000)].into(); pub const HereLocation: Location = Location::here(); pub const RelayLocation: Location = Location::parent(); pub const MaxAssetsIntoHolding: u32 = 64; @@ -453,7 +453,8 @@ sp_api::mock_impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - match asset.try_as::() { + let latest_asset_id: Result = asset.clone().try_into(); + match latest_asset_id { Ok(asset_id) if asset_id.0 == HereLocation::get() => { Ok(WeightToFee::weight_to_fee(&weight)) }, diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index c7caa49393ed..10c6f14bc8b9 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -5,25 +5,27 @@ version = "7.0.0" authors.workspace = true edition.workspace = true license.workspace = true +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] codec = { workspace = true, default-features = true } -scale-info = { workspace = true } paste = { workspace = true, default-features = true } +scale-info = { workspace = true } frame-support = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-builder = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } polkadot-core-primitives = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index e0aff9b7782a..ccf0ecc39c4c 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -5,34 +5,36 @@ authors.workspace = true edition.workspace = true license.workspace = true version = "7.0.0" +homepage.workspace = true +repository.workspace = true [lints] workspace = true [dependencies] codec = { workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-message-queue = { workspace = true, default-features = true } pallet-uniques = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-simulator = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-builder = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } polkadot-core-primitives = { workspace = true, default-features = true } -polkadot-runtime-parachains = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +xcm-simulator = { workspace = true, default-features = true } [features] default = [] @@ -48,4 +50,5 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs index 34c1feb6e946..f971812f4f4d 100644 --- a/polkadot/xcm/xcm-simulator/example/src/tests.rs +++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs @@ -46,8 +46,8 @@ fn dmp() { Parachain(1), Xcm(vec![Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), call: remark.encode().into(), + fallback_max_weight: None, }]), )); }); @@ -74,8 +74,8 @@ fn ump() { Parent, Xcm(vec![Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), call: remark.encode().into(), + fallback_max_weight: None, }]), )); }); @@ -102,8 +102,8 @@ fn xcmp() { (Parent, Parachain(2)), Xcm(vec![Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), call: remark.encode().into(), + fallback_max_weight: None, }]), )); }); @@ -383,7 +383,6 @@ fn reserve_asset_class_create_and_reserve_transfer() { let message = Xcm(vec![Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(1_000_000_000, 1024 * 1024), call: parachain::RuntimeCall::from( pallet_uniques::Call::::create { collection: (Parent, 2u64).into(), @@ -392,6 +391,7 @@ fn reserve_asset_class_create_and_reserve_transfer() { ) .encode() .into(), + fallback_max_weight: None, }]); // Send creation. assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message)); diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index 04f8ba115173..62a047975c87 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -11,30 +11,30 @@ publish = false workspace = true [dependencies] +arbitrary = { workspace = true } codec = { workspace = true, default-features = true } honggfuzz = { workspace = true } -arbitrary = { workspace = true } scale-info = { features = ["derive"], workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } frame-executive = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } frame-try-runtime = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-message-queue = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-simulator = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-builder = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } polkadot-core-primitives = { workspace = true, default-features = true } -polkadot-runtime-parachains = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } +xcm-builder = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +xcm-simulator = { workspace = true, default-features = true } [features] try-runtime = [ @@ -59,6 +59,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] [[bin]] diff --git a/polkadot/zombienet-sdk-tests/Cargo.toml b/polkadot/zombienet-sdk-tests/Cargo.toml index 4eac7af49f8a..120857c9a42e 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] +anyhow = { workspace = true } +codec = { workspace = true, features = ["derive"] } env_logger = { workspace = true } log = { workspace = true } +serde = { workspace = true } +serde_json = { 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-sdk-tests/build.rs b/polkadot/zombienet-sdk-tests/build.rs index 240d86386af2..f7a62a53a8ac 100644 --- a/polkadot/zombienet-sdk-tests/build.rs +++ b/polkadot/zombienet-sdk-tests/build.rs @@ -25,39 +25,47 @@ fn make_env_key(k: &str) -> String { replace_dashes(&k.to_ascii_uppercase()) } +fn wasm_sub_path(chain: &str) -> String { + let (package, runtime_name) = + if let Some(cumulus_test_runtime) = chain.strip_prefix("cumulus-test-runtime-") { + ( + "cumulus-test-runtime".to_string(), + format!("wasm_binary_{}.rs", replace_dashes(cumulus_test_runtime)), + ) + } else { + (format!("{chain}-runtime"), replace_dashes(&format!("{chain}-runtime"))) + }; + + format!("{}/{}.wasm", package, runtime_name) +} + fn find_wasm(chain: &str) -> Option { const PROFILES: [&str; 2] = ["release", "testnet"]; let manifest_path = env::var("CARGO_WORKSPACE_ROOT_DIR").unwrap(); let manifest_path = manifest_path.strip_suffix('/').unwrap(); debug_output!("manifest_path is : {}", manifest_path); - let package = format!("{chain}-runtime"); + + let sub_path = wasm_sub_path(chain); + let profile = PROFILES.into_iter().find(|p| { - let full_path = format!( - "{}/target/{}/wbuild/{}/{}.wasm", - manifest_path, - p, - &package, - replace_dashes(&package) - ); + let full_path = format!("{}/target/{}/wbuild/{}", manifest_path, p, sub_path); debug_output!("checking wasm at : {}", full_path); matches!(path::PathBuf::from(&full_path).try_exists(), Ok(true)) }); debug_output!("profile is : {:?}", profile); profile.map(|profile| { - PathBuf::from(&format!( - "{}/target/{}/wbuild/{}/{}.wasm", - manifest_path, - profile, - &package, - replace_dashes(&package) - )) + PathBuf::from(&format!("{}/target/{}/wbuild/{}", manifest_path, profile, sub_path)) }) } // based on https://gist.github.com/s0me0ne-unkn0wn/bbd83fe32ce10327086adbf13e750eec fn build_wasm(chain: &str) -> PathBuf { - let package = format!("{chain}-runtime"); + let package = if chain.starts_with("cumulus-test-runtime-") { + String::from("cumulus-test-runtime") + } else { + format!("{chain}-runtime") + }; let cargo = env::var("CARGO").unwrap(); let target = env::var("TARGET").unwrap(); @@ -81,11 +89,7 @@ fn build_wasm(chain: &str) -> PathBuf { .status() .unwrap(); - let wasm_path = &format!( - "{target_dir}/{target}/release/wbuild/{}/{}.wasm", - &package, - replace_dashes(&package) - ); + let wasm_path = &format!("{target_dir}/{target}/release/wbuild/{}", wasm_sub_path(chain)); PathBuf::from(wasm_path) } @@ -128,6 +132,10 @@ fn main() { const METADATA_DIR: &str = "metadata-files"; const CHAINS: [&str; 2] = ["rococo", "coretime-rococo"]; + // Add some cumulus test runtimes if needed. Formatted like + // "cumulus-test-runtime-elastic-scaling". + const CUMULUS_TEST_RUNTIMES: [&str; 0] = []; + let metadata_path = format!("{manifest_path}/{METADATA_DIR}"); for chain in CHAINS { @@ -145,6 +153,21 @@ fn main() { }; } + for chain in CUMULUS_TEST_RUNTIMES { + let full_path = format!("{metadata_path}/{chain}-local.scale"); + let output_path = path::PathBuf::from(&full_path); + + match output_path.try_exists() { + Ok(true) => { + debug_output!("got: {}", full_path); + }, + _ => { + debug_output!("needs: {}", full_path); + fetch_metadata_file(chain, &output_path); + }, + }; + } + substrate_build_script_utils::generate_cargo_keys(); substrate_build_script_utils::rerun_if_git_head_changed(); println!("cargo:rerun-if-changed={}", metadata_path); diff --git a/polkadot/zombienet-sdk-tests/tests/elastic_scaling/helpers.rs b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/helpers.rs new file mode 100644 index 000000000000..7d4ad4a1dd8b --- /dev/null +++ b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/helpers.rs @@ -0,0 +1,60 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +use super::rococo; +use std::{collections::HashMap, ops::Range}; +use subxt::{OnlineClient, PolkadotConfig}; + +// Helper function for asserting the throughput of parachains (total number of backed candidates in +// a window of relay chain blocks), after the first session change. +pub async fn assert_para_throughput( + relay_client: &OnlineClient, + stop_at: u32, + expected_candidate_ranges: HashMap>, +) -> Result<(), anyhow::Error> { + let mut blocks_sub = relay_client.blocks().subscribe_finalized().await?; + let mut candidate_count: HashMap = HashMap::new(); + let mut current_block_count = 0; + let mut had_first_session_change = false; + + while let Some(block) = blocks_sub.next().await { + let block = block?; + log::debug!("Finalized relay chain block {}", block.number()); + let events = block.events().await?; + let is_session_change = events.has::()?; + + if !had_first_session_change && is_session_change { + had_first_session_change = true; + } + + if had_first_session_change && !is_session_change { + current_block_count += 1; + + for event in events.find::() { + *(candidate_count.entry(event?.0.descriptor.para_id.0).or_default()) += 1; + } + } + + if current_block_count == stop_at { + break; + } + } + + log::info!( + "Reached {} finalized relay chain blocks that contain backed candidates. The per-parachain distribution is: {:#?}", + stop_at, + candidate_count + ); + + for (para_id, expected_candidate_range) in expected_candidate_ranges { + let actual = candidate_count + .get(¶_id) + .expect("ParaId did not have any backed candidates"); + assert!( + expected_candidate_range.contains(actual), + "Candidate count {actual} not within range {expected_candidate_range:?}" + ); + } + + Ok(()) +} diff --git a/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs new file mode 100644 index 000000000000..bb296a419df1 --- /dev/null +++ b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/mod.rs @@ -0,0 +1,8 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +#[subxt::subxt(runtime_metadata_path = "metadata-files/rococo-local.scale")] +pub mod rococo {} + +mod helpers; +mod slot_based_3cores; diff --git a/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_3cores.rs b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_3cores.rs new file mode 100644 index 000000000000..41ec1250ecc4 --- /dev/null +++ b/polkadot/zombienet-sdk-tests/tests/elastic_scaling/slot_based_3cores.rs @@ -0,0 +1,166 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Test that parachains that use a single slot-based collator with elastic scaling MVP and with +// elastic scaling with RFC103 can achieve full throughput of 3 candidates per block. + +use anyhow::anyhow; + +use super::{ + helpers::assert_para_throughput, + rococo, + rococo::runtime_types::{ + pallet_broker::coretime_interface::CoreAssignment, + polkadot_runtime_parachains::assigner_coretime::PartsOf57600, + }, +}; +use serde_json::json; +use subxt::{OnlineClient, PolkadotConfig}; +use subxt_signer::sr25519::dev; +use zombienet_sdk::NetworkConfigBuilder; + +#[tokio::test(flavor = "multi_thread")] +async fn slot_based_3cores_test() -> Result<(), anyhow::Error> { + let _ = env_logger::try_init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + + let images = zombienet_sdk::environment::get_images_from_env(); + + let config = NetworkConfigBuilder::new() + .with_relaychain(|r| { + let r = r + .with_chain("rococo-local") + .with_default_command("polkadot") + .with_default_image(images.polkadot.as_str()) + .with_default_args(vec![("-lparachain=debug").into()]) + .with_genesis_overrides(json!({ + "configuration": { + "config": { + "scheduler_params": { + // Num cores is 4, because 2 extra will be added automatically when registering the paras. + "num_cores": 4, + "max_validators_per_core": 2 + }, + "async_backing_params": { + "max_candidate_depth": 6, + "allowed_ancestry_len": 2 + } + } + } + })) + // Have to set a `with_node` outside of the loop below, so that `r` has the right + // type. + .with_node(|node| node.with_name("validator-0")); + + (1..12) + .fold(r, |acc, i| acc.with_node(|node| node.with_name(&format!("validator-{i}")))) + }) + .with_parachain(|p| { + // Para 2100 uses the old elastic scaling mvp, which doesn't send the new UMP signal + // commitment for selecting the core index. + p.with_id(2100) + .with_default_command("test-parachain") + .with_default_image(images.cumulus.as_str()) + .with_chain("elastic-scaling-mvp") + .with_default_args(vec![("--experimental-use-slot-based").into()]) + .with_default_args(vec![ + ("--experimental-use-slot-based").into(), + ("-lparachain=debug,aura=debug").into(), + ]) + .with_collator(|n| n.with_name("collator-elastic-mvp")) + }) + .with_parachain(|p| { + // Para 2200 uses the new RFC103-enabled collator which sends the UMP signal commitment + // for selecting the core index + p.with_id(2200) + .with_default_command("test-parachain") + .with_default_image(images.cumulus.as_str()) + .with_chain("elastic-scaling") + .with_default_args(vec![ + ("--experimental-use-slot-based").into(), + ("-lparachain=debug,aura=debug").into(), + ]) + .with_collator(|n| n.with_name("collator-elastic")) + }) + .build() + .map_err(|e| { + let errs = e.into_iter().map(|e| e.to_string()).collect::>().join(" "); + anyhow!("config errs: {errs}") + })?; + + let spawn_fn = zombienet_sdk::environment::get_spawn_fn(); + let network = spawn_fn(config).await?; + + let relay_node = network.get_node("validator-0")?; + + let relay_client: OnlineClient = relay_node.wait_client().await?; + let alice = dev::alice(); + + // Assign two extra cores to each parachain. + relay_client + .tx() + .sign_and_submit_then_watch_default( + &rococo::tx() + .sudo() + .sudo(rococo::runtime_types::rococo_runtime::RuntimeCall::Utility( + rococo::runtime_types::pallet_utility::pallet::Call::batch { + calls: vec![ + rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime( + rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core { + core: 0, + begin: 0, + assignment: vec![(CoreAssignment::Task(2100), PartsOf57600(57600))], + end_hint: None + } + ), + rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime( + rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core { + core: 1, + begin: 0, + assignment: vec![(CoreAssignment::Task(2100), PartsOf57600(57600))], + end_hint: None + } + ), + rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime( + rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core { + core: 2, + begin: 0, + assignment: vec![(CoreAssignment::Task(2200), PartsOf57600(57600))], + end_hint: None + } + ), + rococo::runtime_types::rococo_runtime::RuntimeCall::Coretime( + rococo::runtime_types::polkadot_runtime_parachains::coretime::pallet::Call::assign_core { + core: 3, + begin: 0, + assignment: vec![(CoreAssignment::Task(2200), PartsOf57600(57600))], + end_hint: None + } + ) + ], + }, + )), + &alice, + ) + .await? + .wait_for_finalized_success() + .await?; + + log::info!("2 more cores assigned to each parachain"); + + // Expect a backed candidate count of at least 39 for each parachain in 15 relay chain blocks + // (2.6 candidates per para per relay chain block). + // Note that only blocks after the first session change and blocks that don't contain a session + // change will be counted. + assert_para_throughput( + &relay_client, + 15, + [(2100, 39..46), (2200, 39..46)].into_iter().collect(), + ) + .await?; + + log::info!("Test finished successfully"); + + Ok(()) +} diff --git a/polkadot/zombienet-sdk-tests/tests/lib.rs b/polkadot/zombienet-sdk-tests/tests/lib.rs index 74cdc0765600..977e0f90b1c9 100644 --- a/polkadot/zombienet-sdk-tests/tests/lib.rs +++ b/polkadot/zombienet-sdk-tests/tests/lib.rs @@ -1,4 +1,7 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 +#[cfg(feature = "zombie-metadata")] +mod elastic_scaling; +#[cfg(feature = "zombie-metadata")] mod smoke; diff --git a/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs b/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs index 7880dc782d05..2da2436a1111 100644 --- a/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs +++ b/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs @@ -180,7 +180,7 @@ where #[tokio::test(flavor = "multi_thread")] async fn coretime_revenue_test() -> Result<(), anyhow::Error> { - env_logger::init_from_env( + let _ = env_logger::try_init_from_env( env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), ); @@ -499,7 +499,7 @@ async fn coretime_revenue_test() -> Result<(), anyhow::Error> { assert_total_issuance(relay_client.clone(), para_client.clone(), total_issuance).await; - log::info!("Test finished successfuly"); + log::info!("Test finished successfully"); Ok(()) } diff --git a/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs b/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs index a3fe15382674..072a9d54ecda 100644 --- a/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs +++ b/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs @@ -1,5 +1,4 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "zombie-metadata")] mod coretime_revenue; diff --git a/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.toml b/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.toml index 9b3576eaa3c2..046d707cc1e8 100644 --- a/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.toml +++ b/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.toml @@ -37,4 +37,4 @@ onboard_as_parachain = false [parachains.collator] name = "collator2000" command = "polkadot-parachain" - args = [ "-lparachain=debug" ] + args = [ "-lparachain=debug", "--experimental-use-slot-based" ] diff --git a/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.zndsl b/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.zndsl index 7ba896e1c903..0cfc29f532d1 100644 --- a/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.zndsl +++ b/polkadot/zombienet_tests/elastic_scaling/0002-elastic-scaling-doesnt-break-parachains.zndsl @@ -12,7 +12,7 @@ validator: parachain 2000 block height is at least 10 within 200 seconds # Register the second core assigned to this parachain. alice: js-script ./assign-core.js with "0,2000,57600" return is 0 within 600 seconds -alice: js-script ./assign-core.js with "0,2000,57600" return is 0 within 600 seconds +alice: js-script ./assign-core.js with "1,2000,57600" return is 0 within 600 seconds validator: reports substrate_block_height{status="finalized"} is at least 35 within 100 seconds diff --git a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml index 745c4f9e24b1..d3ff00002242 100644 --- a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml +++ b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml @@ -36,4 +36,4 @@ chain = "glutton-westend-local-2000" name = "collator-2000" image = "{{CUMULUS_IMAGE}}" command = "polkadot-parachain" - args = ["-lparachain=debug"] + args = ["-lparachain=debug", "--experimental-use-slot-based"] diff --git a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl index 80ecf6ae1b9b..dce52505444e 100644 --- a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl +++ b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl @@ -8,4 +8,4 @@ validator-0: js-script ./force-register-paras.js with "2000" return is 0 within # assign core 0 to be shared by two paras, but only one exists validator-0: js-script ./assign-core.js with "0,2000,28800,2001,28800" return is 0 within 600 seconds -collator-2000: reports block height is at least 10 within 180 seconds +collator-2000: reports block height is at least 10 within 210 seconds diff --git a/polkadot/zombienet_tests/functional/0019-coretime-collation-fetching-fairness.toml b/polkadot/zombienet_tests/functional/0019-coretime-collation-fetching-fairness.toml new file mode 100644 index 000000000000..43f3ef8f9e55 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0019-coretime-collation-fetching-fairness.toml @@ -0,0 +1,58 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] + max_candidate_depth = 3 + allowed_ancestry_len = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 4 + num_cores = 1 + lookahead = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + needed_approvals = 3 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +command = "polkadot" + + [[relaychain.node_groups]] + name = "validator" + args = ["-lparachain=debug,parachain::collator-protocol=trace" ] + count = 4 + +[[parachains]] +id = 2000 +register_para = false +onboard_as_parachain = false +add_to_genesis = false +chain = "glutton-westend-local-2000" + [parachains.genesis.runtimeGenesis.patch.glutton] + compute = "50000000" + storage = "2500000000" + trashDataCount = 5120 + + [parachains.collator] + name = "collator-2000" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" + args = ["-lparachain=debug,parachain::collator-protocol=trace", "--experimental-use-slot-based"] + +[[parachains]] +id = 2001 +register_para = false +onboard_as_parachain = false +add_to_genesis = false +chain = "glutton-westend-local-2001" + [parachains.genesis.runtimeGenesis.patch.glutton] + compute = "50000000" + storage = "2500000000" + trashDataCount = 5120 + + [parachains.collator] + name = "collator-2001" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" + args = ["-lparachain=debug"] diff --git a/polkadot/zombienet_tests/functional/0019-coretime-collation-fetching-fairness.zndsl b/polkadot/zombienet_tests/functional/0019-coretime-collation-fetching-fairness.zndsl new file mode 100644 index 000000000000..8892b03ac29c --- /dev/null +++ b/polkadot/zombienet_tests/functional/0019-coretime-collation-fetching-fairness.zndsl @@ -0,0 +1,16 @@ +Description: CT shared core fairness test +Network: ./0019-coretime-collation-fetching-fairness.toml +Creds: config + +validator: reports node_roles is 4 + +validator-0: js-script ./force-register-paras.js with "2000,2001" return is 0 within 600 seconds +# core 0 is shared 3:1 between paras +validator-0: js-script ./assign-core.js with "0,2000,43200,2001,14400" return is 0 within 600 seconds + +collator-2000: reports block height is at least 9 within 200 seconds +collator-2001: reports block height is at least 3 within 10 seconds + +# hardcoded check to verify that included onchain events are indeed 3:1 +validator-0: js-script ./0019-verify-included-events.js return is 1 within 120 seconds + diff --git a/polkadot/zombienet_tests/functional/0019-verify-included-events.js b/polkadot/zombienet_tests/functional/0019-verify-included-events.js new file mode 100644 index 000000000000..6557a5a80e6b --- /dev/null +++ b/polkadot/zombienet_tests/functional/0019-verify-included-events.js @@ -0,0 +1,51 @@ +function parse_pjs_int(input) { + return parseInt(input.replace(/,/g, '')); +} + +async function run(nodeName, networkInfo) { + const { wsUri, userDefinedTypes } = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + let blocks_per_para = {}; + + await new Promise(async (resolve, _) => { + let block_count = 0; + const unsubscribe = await api.query.system.events(async (events, block_hash) => { + block_count++; + + events.forEach((record) => { + const event = record.event; + + if (event.method != 'CandidateIncluded') { + return; + } + + let included_para_id = parse_pjs_int(event.toHuman().data[0].descriptor.paraId); + let relay_parent = event.toHuman().data[0].descriptor.relayParent; + if (blocks_per_para[included_para_id] == undefined) { + blocks_per_para[included_para_id] = 1; + } else { + blocks_per_para[included_para_id]++; + } + console.log(`CandidateIncluded for ${included_para_id}: block_offset=${block_count} relay_parent=${relay_parent}`); + }); + + if (block_count == 12) { + unsubscribe(); + return resolve(); + } + }); + }); + + console.log(`Result: 2000: ${blocks_per_para[2000]}, 2001: ${blocks_per_para[2001]}`); + // This check assumes that para 2000 runs slot based collator which respects its claim queue + // and para 2001 runs lookahead which generates blocks for each relay parent. + // + // For 12 blocks there will be one session change. One block won't have anything backed/included. + // In the next there will be one backed so for 12 blocks we should expect 10 included events - no + // more than 4 for para 2001 and at least 6 for para 2000. This should also cover the unlucky + // case when we observe two session changes during the 12 block period. + return (blocks_per_para[2000] >= 6) && (blocks_per_para[2001] <= 4); +} + +module.exports = { run }; diff --git a/prdoc/pr_4273.prdoc b/prdoc/pr_4273.prdoc new file mode 100644 index 000000000000..1ff0a5782a41 --- /dev/null +++ b/prdoc/pr_4273.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: "[pallet-broker] add extrinsic to reserve a system core without having to wait two sale boundaries" + +doc: + - audience: Runtime User + description: | + When calling the reserve extrinsic after sales have started, the assignment will be reserved, + but two sale period boundaries must pass before the core is actually assigned. A new + `force_reserve` extrinsic is introduced to allow a core to be immediately assigned. + +crates: + - name: pallet-broker + bump: major + - name: coretime-rococo-runtime + bump: patch + - name: coretime-westend-runtime + bump: patch diff --git a/prdoc/pr_4880.prdoc b/prdoc/pr_4880.prdoc new file mode 100644 index 000000000000..1bcd09088b5f --- /dev/null +++ b/prdoc/pr_4880.prdoc @@ -0,0 +1,31 @@ +title: Collation fetching fairness in collator protocol + +doc: + - audience: "Node Dev" + description: | + Implements collation fetching fairness in the validator side of the collator protocol. With + core time in place if two (or more) parachains share a single core no fairness was guaranteed + between them in terms of collation fetching. The current implementation was accepting up to + `max_candidate_depth + 1` seconded collations per relay parent and once this limit is reached + no new collations are accepted. A misbehaving collator can abuse this fact and prevent other + collators/parachains from advertising collations by advertising `max_candidate_depth + 1` + collations of its own. + To address this issue two changes are made: + 1. For each parachain id the validator accepts advertisements until the number of entries in + the claim queue equals the number of seconded candidates. + 2. When new collation should be fetched the validator inspects what was seconded so far, + what's in the claim queue and picks the first slot which hasn't got a collation seconded + and there is no candidate pending seconding for it. If there is an advertisement in the + waiting queue for it it is fetched. Otherwise the next free slot is picked. + These two changes guarantee that: + 1. Validator doesn't accept more collations than it can actually back. + 2. Each parachain has got a fair share of core time based on its allocations in the claim + queue. + +crates: + - name: polkadot-collator-protocol + bump: patch + - name: polkadot + bump: patch + - name: polkadot-node-subsystem-util + bump: minor \ No newline at end of file diff --git a/prdoc/pr_5363.prdoc b/prdoc/pr_5363.prdoc new file mode 100644 index 000000000000..c3ecfffb9e52 --- /dev/null +++ b/prdoc/pr_5363.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-xcm] waive transport fees based on XcmConfig" + +doc: + - audience: Runtime Dev + description: | + pallet-xcm::send() no longer implicitly waives transport fees for the local root location, + but instead relies on xcm_executor::Config::FeeManager to determine whether certain locations have free transport. + + 🚨 Warning: 🚨 If your chain relies on free transport for local root, please make + sure to add Location::here() to the waived-fee locations in your configured xcm_executor::Config::FeeManager. + +crates: + - name: pallet-xcm + bump: major \ No newline at end of file diff --git a/prdoc/pr_5656.prdoc b/prdoc/pr_5656.prdoc new file mode 100644 index 000000000000..b20546bf7a5e --- /dev/null +++ b/prdoc/pr_5656.prdoc @@ -0,0 +1,18 @@ +# 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: Use Relay Blocknumber in Pallet Broker + +doc: + - audience: Runtime Dev + description: | + Changing `sale_start`, `interlude_length` and `leading_length` in `pallet_broker` to use relay chain block numbers instead of parachain block numbers. + Relay chain block numbers are almost deterministic and more future proof. + +crates: + - name: pallet-broker + bump: major + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major \ No newline at end of file diff --git a/prdoc/pr_5703.prdoc b/prdoc/pr_5703.prdoc new file mode 100644 index 000000000000..3cef4468a87d --- /dev/null +++ b/prdoc/pr_5703.prdoc @@ -0,0 +1,13 @@ +title: Properly handle block gap created by fast sync + +doc: + - audience: Node Dev + description: | + Implements support for handling block gaps generated during fast sync. This includes managing the creation, + updating, and removal of block gaps. + Note that this feature is not fully activated until the `body` attribute is removed from the `LightState` + block request in chain sync, which will occur after the issue #5406 is resolved. + +crates: + - name: sc-client-db + bump: patch diff --git a/prdoc/pr_5723.prdoc b/prdoc/pr_5723.prdoc new file mode 100644 index 000000000000..ded5f9cebd1d --- /dev/null +++ b/prdoc/pr_5723.prdoc @@ -0,0 +1,24 @@ +title: Adds `BlockNumberProvider` in multisig, proxy and nft pallets + +doc: + - audience: Runtime Dev + description: | + This PR adds the ability for these pallets to specify their source of the block number. + This is useful when these pallets are migrated from the relay chain to a parachain and + vice versa. + + This change is backwards compatible: + 1. If the `BlockNumberProvider` continues to use the system pallet's block number + 2. When a pallet deployed on the relay chain is moved to a parachain, but still uses the + relay chain's block number + + However, we would need migrations if the deployed pallets are upgraded on an existing parachain, + and the `BlockNumberProvider` uses the relay chain block number. + +crates: + - name: pallet-multisig + bump: major + - name: pallet-proxy + bump: major + - name: pallet-nfts + bump: major diff --git a/prdoc/pr_5724.prdoc b/prdoc/pr_5724.prdoc new file mode 100644 index 000000000000..be9d21c214a8 --- /dev/null +++ b/prdoc/pr_5724.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: Validator Re-Enabling (master PR) + +doc: + - audience: Runtime Dev + description: | + Implementation of the Stage 3 for the New Disabling Strategy: https://github.com/paritytech/polkadot-sdk/issues/4359 + + This PR changes when an active validator node gets disabled for comitting offences. + When Byzantine Threshold Validators (1/3) are already disabled instead of no longer + disabling the highest offenders will be disabled potentially re-enabling low offenders. + + - audience: Node Operator + description: | + Implementation of the Stage 3 for the New Disabling Strategy: https://github.com/paritytech/polkadot-sdk/issues/4359 + + This PR changes when an active validator node gets disabled within parachain consensus (reduced responsibilities and + reduced rewards) for comitting offences. This should not affect active validators on a day-to-day basis and will only + be relevant when the network is under attack or there is a wide spread malfunction causing slashes. In that case + lowest offenders might get eventually re-enabled (back to normal responsibilities and normal rewards). + +migrations: + db: [] + runtime: + - reference: pallet-staking + description: | + Migrating `DisabledValidators` from `Vec` to `Vec<(u32, PerBill)>` where the PerBill represents the severity + of the offence in terms of the % slash. + +crates: + - name: pallet-staking + bump: minor + + - name: pallet-session + bump: minor diff --git a/prdoc/pr_5842.prdoc b/prdoc/pr_5842.prdoc new file mode 100644 index 000000000000..0175c7583419 --- /dev/null +++ b/prdoc/pr_5842.prdoc @@ -0,0 +1,18 @@ +# 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: Get rid of libp2p dependency in sc-authority-discovery + +doc: + - audience: Node Dev + description: | + Removes `libp2p` types in authority-discovery, and replace them with network backend agnostic types from `sc-network-types`. + The `sc-network` interface is therefore updated accordingly. + +crates: + - name: sc-network + bump: patch + - name: sc-network-types + bump: patch + - name: sc-authority-discovery + bump: patch diff --git a/prdoc/pr_5855.prdoc b/prdoc/pr_5855.prdoc new file mode 100644 index 000000000000..7735cfee9f37 --- /dev/null +++ b/prdoc/pr_5855.prdoc @@ -0,0 +1,15 @@ +# 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 feature `test-helpers` from sc-service + +doc: + - audience: Node Dev + description: | + Removes feature `test-helpers` from sc-service. + +crates: + - name: sc-service + bump: major + - name: sc-rpc-spec-v2 + bump: major diff --git a/prdoc/pr_5899.prdoc b/prdoc/pr_5899.prdoc new file mode 100644 index 000000000000..fef810dd5f20 --- /dev/null +++ b/prdoc/pr_5899.prdoc @@ -0,0 +1,52 @@ +# 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 usage of AccountKeyring" + +doc: + - audience: Runtime Dev + description: | + Compared with AccountKeyring, Sr25519Keyring and Ed25519Keyring are more intuitive. + When both Sr25519Keyring and Ed25519Keyring are required, using AccountKeyring bring confusion. + There are two AccountKeyring definitions, it becomes more complex if export two AccountKeyring from frame. + +crates: + - name: frame-support + bump: patch + - name: sp-keyring + bump: major + - name: sc-service + bump: patch + - name: sc-chain-spec + bump: patch + - name: sc-rpc + bump: patch + - name: sc-transaction-pool + bump: patch + - name: sc-rpc-spec-v2 + bump: patch + - name: polkadot-node-metrics + bump: patch + - name: substrate-frame-rpc-system + bump: patch + - name: westend-runtime + bump: patch + - name: polkadot-sdk-frame + bump: patch + - name: rococo-runtime + bump: patch + - name: sc-basic-authorship + bump: patch + - name: bridge-hub-test-utils + bump: patch + - name: sc-consensus-manual-seal + bump: patch + - name: snowbridge-pallet-inbound-queue + bump: patch + - name: snowbridge-runtime-test-common + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + diff --git a/prdoc/pr_6111.prdoc b/prdoc/pr_6111.prdoc new file mode 100644 index 000000000000..4ada3031c805 --- /dev/null +++ b/prdoc/pr_6111.prdoc @@ -0,0 +1,17 @@ +title: "[pallet-revive] Update delegate_call to accept address and weight" + +doc: + - audience: Runtime Dev + description: | + Enhance the `delegate_call` function to accept an `address` target parameter instead of a `code_hash`. + This allows direct identification of the target contract using the provided address. + Additionally, introduce parameters for specifying a customizable `ref_time` limit and `proof_size` limit, + thereby improving flexibility and control during contract interactions. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6163.prdoc b/prdoc/pr_6163.prdoc new file mode 100644 index 000000000000..c8571f80ed52 --- /dev/null +++ b/prdoc/pr_6163.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: Expose more syncing types to enable custom syncing strategy + +doc: + - audience: Node Dev + description: | + Exposes additional syncing types to facilitate the development of a custom syncing strategy. + +crates: + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_6184.prdoc b/prdoc/pr_6184.prdoc new file mode 100644 index 000000000000..e05a5884e930 --- /dev/null +++ b/prdoc/pr_6184.prdoc @@ -0,0 +1,24 @@ +title: Remove pallet::getter from pallet-staking +doc: + - audience: Runtime Dev + description: | + This PR removes all pallet::getter occurrences from pallet-staking and replaces them with explicit implementations. + It also adds tests to verify that retrieval of affected entities works as expected so via storage::getter. + +crates: + - name: pallet-babe + bump: patch + - name: pallet-beefy + bump: patch + - name: pallet-election-provider-multi-phase + bump: patch + - name: pallet-grandpa + bump: patch + - name: pallet-nomination-pools + bump: patch + - name: pallet-root-offences + bump: patch + - name: westend-runtime + bump: patch + - name: pallet-staking + bump: patch \ No newline at end of file diff --git a/prdoc/pr_6215.prdoc b/prdoc/pr_6215.prdoc new file mode 100644 index 000000000000..3726a2fc5788 --- /dev/null +++ b/prdoc/pr_6215.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: Remove `ProspectiveParachainsMode` from backing subsystem +doc: + - audience: "Node Dev" + description: | + Removes `ProspectiveParachainsMode` usage from the backing subsystem and assumes + `async_backing_params` runtime api is always available. Since the runtime api v7 is released on + all networks it should always be true. + +crates: + - name: polkadot-node-core-backing + bump: patch + - name: polkadot-statement-table + bump: major diff --git a/prdoc/pr_6220.prdoc b/prdoc/pr_6220.prdoc new file mode 100644 index 000000000000..6a5ee4fa59be --- /dev/null +++ b/prdoc/pr_6220.prdoc @@ -0,0 +1,10 @@ +title: Fix metrics not shutting down if there are open connections + +doc: + - audience: Runtime Dev + description: | + Fix prometheus metrics not shutting down if there are open connections + +crates: +- name: substrate-prometheus-endpoint + bump: patch diff --git a/prdoc/pr_6248.prdoc b/prdoc/pr_6248.prdoc new file mode 100644 index 000000000000..71fb0891cac6 --- /dev/null +++ b/prdoc/pr_6248.prdoc @@ -0,0 +1,16 @@ +title: Upgrade libp2p to 0.54.1 + +doc: + - audience: [Node Dev, Node Operator] + description: | + Upgrade libp2p from 0.52.4 to 0.54.1 + +crates: + - name: sc-network + bump: major + - name: sc-network-types + bump: minor + - name: sc-network-sync + bump: patch + - name: sc-telemetry + bump: minor diff --git a/prdoc/pr_6249.prdoc b/prdoc/pr_6249.prdoc new file mode 100644 index 000000000000..52fa10b22627 --- /dev/null +++ b/prdoc/pr_6249.prdoc @@ -0,0 +1,10 @@ +title: Pure state sync refactoring (part-1) + +doc: +- audience: Node Dev + description: | + The pure refactoring of state sync is preparing for https://github.com/paritytech/polkadot-sdk/issues/4. This is the first part, focusing on isolating the function `process_state_key_values()` as the central point for storing received state data in memory. This function will later be adapted to forward the state data directly to the DB layer to resolve the OOM issue and support persistent state sync. + +crates: +- name: sc-network-sync + bump: none diff --git a/prdoc/pr_6262.prdoc b/prdoc/pr_6262.prdoc new file mode 100644 index 000000000000..8ad99bc6ad28 --- /dev/null +++ b/prdoc/pr_6262.prdoc @@ -0,0 +1,10 @@ +title: "Size limits implemented for fork aware transaction pool" + +doc: + - audience: Node Dev + description: | + Size limits are now obeyed in fork aware transaction pool + +crates: + - name: sc-transaction-pool + bump: minor diff --git a/prdoc/pr_6284.prdoc b/prdoc/pr_6284.prdoc new file mode 100644 index 000000000000..e2d9ebb526d2 --- /dev/null +++ b/prdoc/pr_6284.prdoc @@ -0,0 +1,22 @@ +title: "backing: improve session buffering for runtime information" + +doc: + - audience: Node Dev + description: | + This PR implements caching within the backing module for session-stable information, + reducing redundant runtime API calls. + + Specifically, it introduces a local cache for the: + - validators list; + - node features; + - executor parameters; + - minimum backing votes threshold; + - validator-to-group mapping. + + Previously, this data was fetched or computed repeatedly each time `PerRelayParentState` + was built. With this update, the cached information is fetched once and reused throughout + the session. + +crates: + - name: polkadot-node-core-backing + bump: patch diff --git a/prdoc/pr_6290.prdoc b/prdoc/pr_6290.prdoc new file mode 100644 index 000000000000..a05d0cd15acf --- /dev/null +++ b/prdoc/pr_6290.prdoc @@ -0,0 +1,11 @@ +title: Migrate pallet-transaction-storage and pallet-indices to benchmark v2 +doc: +- audience: Runtime Dev + description: |- + Part of: + #6202 +crates: +- name: pallet-indices + bump: patch +- name: pallet-transaction-storage + bump: patch diff --git a/prdoc/pr_6301.prdoc b/prdoc/pr_6301.prdoc new file mode 100644 index 000000000000..d4c05c17c8fb --- /dev/null +++ b/prdoc/pr_6301.prdoc @@ -0,0 +1,11 @@ +title: migrate pallet-nft-fractionalization to benchmarking v2 syntax +doc: +- audience: Runtime Dev + description: |- + Migrates pallet-nft-fractionalization to benchmarking v2 syntax. + + Part of: + * #6202 +crates: +- name: pallet-nft-fractionalization + bump: patch diff --git a/prdoc/pr_6302.prdoc b/prdoc/pr_6302.prdoc new file mode 100644 index 000000000000..8b3e0964b6a6 --- /dev/null +++ b/prdoc/pr_6302.prdoc @@ -0,0 +1,8 @@ +title: migrate pallet-nomination-pool-benchmarking to benchmarking syntax v2 +doc: +- audience: Runtime Dev + description: |- + migrate pallet-nomination-pool-benchmarking to benchmarking syntax v2 +crates: +- name: pallet-nomination-pools-benchmarking + bump: patch diff --git a/prdoc/pr_6310.prdoc b/prdoc/pr_6310.prdoc new file mode 100644 index 000000000000..ab421791dc72 --- /dev/null +++ b/prdoc/pr_6310.prdoc @@ -0,0 +1,12 @@ +title: Migrate pallet-child-bounties benchmark to v2 +doc: +- audience: Runtime Dev + description: |- + Part of: + + - #6202. +crates: +- name: pallet-utility + bump: patch +- name: pallet-child-bounties + bump: patch diff --git a/prdoc/pr_6311.prdoc b/prdoc/pr_6311.prdoc new file mode 100644 index 000000000000..a63876f4e4ac --- /dev/null +++ b/prdoc/pr_6311.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: Migrate pallet-fast-unstake and pallet-babe benchmark to v2 +doc: +- audience: Runtime Dev + description: |- + Migrate pallet-fast-unstake and pallet-babe benchmark to v2 +crates: +- name: pallet-babe + bump: patch +- name: pallet-fast-unstake + bump: patch diff --git a/prdoc/pr_6349.prdoc b/prdoc/pr_6349.prdoc new file mode 100644 index 000000000000..40f02712c99a --- /dev/null +++ b/prdoc/pr_6349.prdoc @@ -0,0 +1,44 @@ +title: "runtimes: presets are provided as config patches" + +doc: + - audience: Runtime Dev + description: | + This PR introduces usage of build_struct_json_patch macro in all + runtimes (also guides) within the code base. It also fixes macro to support + field init shorthand, and Struct Update syntax which were missing in original + implementation. + +crates: + - name: frame-support + bump: major + + - name: westend-runtime + bump: patch + + - name: rococo-runtime + bump: patch + + - name: asset-hub-westend-runtime + bump: patch + + - name: bridge-hub-rococo-runtime + bump: patch + + - name: bridge-hub-westend-runtime + bump: patch + + - name: collectives-westend-runtime + bump: patch + + - name: minimal-template-runtime + bump: patch + + - name: solochain-template-runtime + bump: patch + + - name: parachain-template-runtime + bump: patch + + - name: polkadot-sdk-docs-first-runtime + bump: patch + diff --git a/prdoc/pr_6367.prdoc b/prdoc/pr_6367.prdoc new file mode 100644 index 000000000000..fd1e6bb4196d --- /dev/null +++ b/prdoc/pr_6367.prdoc @@ -0,0 +1,14 @@ +# 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: Refactor pallet society + +doc: + - audience: Runtime Dev + description: | + Derives `MaxEncodedLen` implementation for stored types and removes `without_storage_info` attribute. + Migrates benchmarks from v1 to v2 API. + +crates: + - name: pallet-society + bump: minor diff --git a/prdoc/pr_6368.prdoc b/prdoc/pr_6368.prdoc new file mode 100644 index 000000000000..4fd3963eb05e --- /dev/null +++ b/prdoc/pr_6368.prdoc @@ -0,0 +1,7 @@ +title: Migrate inclusion benchmark to v2 +doc: +- audience: Runtime Dev + description: Migrate inclusion benchmark to v2. +crates: +- name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/pr_6393.prdoc b/prdoc/pr_6393.prdoc new file mode 100644 index 000000000000..fc8fe9bd8576 --- /dev/null +++ b/prdoc/pr_6393.prdoc @@ -0,0 +1,16 @@ +title: '[pallet-revive] adjust fee dry-run calculation' +doc: +- audience: Runtime Dev + description: |- + - Fix bare_eth_transact so that it estimate more precisely the transaction fee + - Add some context to the build.rs to make it easier to troubleshoot errors + - Add TransactionBuilder for the RPC tests. + - Tweaked some error message, We will need to wait for the next subxt release to properly downcast some errors and + adopt MM error code (https://eips.ethereum.org/EIPS/eip-1474#error-codes) +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor +- name: pallet-revive-fixtures + bump: minor diff --git a/prdoc/pr_6400.prdoc b/prdoc/pr_6400.prdoc new file mode 100644 index 000000000000..a29ad49b4e51 --- /dev/null +++ b/prdoc/pr_6400.prdoc @@ -0,0 +1,41 @@ +title: Remove network starter that is no longer needed +doc: +- audience: Node Dev + description: |- + # Description + + This seems to be an old artifact of the long closed https://github.com/paritytech/substrate/issues/6827 that I noticed when working on related code earlier. + + ## Integration + + `NetworkStarter` was removed, simply remove its usage: + ```diff + -let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + +let (network, system_rpc_tx, tx_handler_controller, sync_service) = + build_network(BuildNetworkParams { + ... + -start_network.start_network(); + ``` + + ## Review Notes + + Changes are trivial, the only reason for this to not be accepted is if it is desired to not start network automatically for whatever reason, in which case the description of network starter needs to change. + + # Checklist + + * [x] My PR includes a detailed description as outlined in the "Description" and its two subsections above. + * [ ] My PR follows the [labeling requirements]( + https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md#Process + ) of this project (at minimum one label for `T` required) + * External contributors: ask maintainers to put the right label on your PR. +crates: +- name: cumulus-relay-chain-minimal-node + bump: major +- name: cumulus-client-service + bump: major +- name: polkadot-omni-node-lib + bump: major +- name: polkadot-service + bump: major +- name: sc-service + bump: major diff --git a/prdoc/pr_6405.prdoc b/prdoc/pr_6405.prdoc new file mode 100644 index 000000000000..9e4e0b3c6c20 --- /dev/null +++ b/prdoc/pr_6405.prdoc @@ -0,0 +1,9 @@ +title: '`fatxpool`: handling limits and priorities improvements' +doc: +- audience: Node Dev + description: |- + This PR provides a number of improvements and fixes around handling limits and priorities in the fork-aware transaction pool. + +crates: +- name: sc-transaction-pool + bump: major diff --git a/prdoc/pr_6411.prdoc b/prdoc/pr_6411.prdoc new file mode 100644 index 000000000000..3d8c2219e90e --- /dev/null +++ b/prdoc/pr_6411.prdoc @@ -0,0 +1,10 @@ +title: "Support more types in TypeWithDefault" + +doc: + - audience: Runtime Dev + description: | + This PR supports more integer types to be used with `TypeWithDefault` and makes `TypeWithDefault: BaseArithmetic` satisfied + +crates: + - name: sp-runtime + bump: patch diff --git a/prdoc/pr_6417.prdoc b/prdoc/pr_6417.prdoc new file mode 100644 index 000000000000..dfbc8c0d311b --- /dev/null +++ b/prdoc/pr_6417.prdoc @@ -0,0 +1,9 @@ +title: fix prospective-parachains best backable chain reversion bug +doc: + - audience: Node Dev + description: | + Fixes a bug in the prospective-parachains subsystem that prevented proper best backable chain reorg. + +crates: +- name: polkadot-node-core-prospective-parachains + bump: patch diff --git a/prdoc/pr_6419.prdoc b/prdoc/pr_6419.prdoc new file mode 100644 index 000000000000..6cc155d64b91 --- /dev/null +++ b/prdoc/pr_6419.prdoc @@ -0,0 +1,12 @@ +# 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: Use the custom target riscv32emac-unknown-none-polkavm +doc: + - audience: Runtime Dev + description: | + Closes: https://github.com/paritytech/polkadot-sdk/issues/6335 + +crates: +- name: substrate-wasm-builder + bump: patch diff --git a/prdoc/pr_6425.prdoc b/prdoc/pr_6425.prdoc new file mode 100644 index 000000000000..57e759bf3376 --- /dev/null +++ b/prdoc/pr_6425.prdoc @@ -0,0 +1,27 @@ +title: Introduce `ConstUint` to make dependent types in `DefaultConfig` more adaptable +author: conr2d +topic: runtime + +doc: +- audience: Runtime Dev + description: |- + Introduce `ConstUint` that is a unified alternative to `ConstU8`, `ConstU16`, and + similar types, particularly useful for configuring `DefaultConfig` in pallets. + It enables configuring the underlying integer for a specific type without the need + to update all dependent types, offering enhanced flexibility in type management. + +crates: + - name: frame-support + bump: patch + - name: frame-system + bump: none + - name: pallet-assets + bump: none + - name: pallet-balances + bump: none + - name: pallet-timestamp + bump: none + - name: sp-core + bump: patch + - name: sp-runtime + bump: patch diff --git a/prdoc/pr_6435.prdoc b/prdoc/pr_6435.prdoc new file mode 100644 index 000000000000..025c666d9115 --- /dev/null +++ b/prdoc/pr_6435.prdoc @@ -0,0 +1,16 @@ +title: 'frame-benchmarking: Use correct components for pallet instances' +doc: +- audience: Runtime Dev + description: |- + When benchmarking multiple instances of the same pallet, each instance was executed with the components of all instances. While actually each instance should only be executed with the components generated for the particular instance. The problem here was that in the runtime only the pallet-name was used to determine if a certain pallet should be benchmarked. When using instances, the pallet name is the same for both of these instances. The solution is to also take the instance name into account. + + The fix requires to change the `Benchmark` runtime api to also take the `instance`. The node side is written in a backwards compatible way to also support runtimes which do not yet support the `instance` parameter. +crates: +- name: frame-benchmarking + bump: major +- name: frame-benchmarking-cli + bump: major +- name: sc-client-db + bump: none +- name: pallet-referenda + bump: none diff --git a/prdoc/pr_6439.prdoc b/prdoc/pr_6439.prdoc new file mode 100644 index 000000000000..fb3b62523576 --- /dev/null +++ b/prdoc/pr_6439.prdoc @@ -0,0 +1,10 @@ +title: 'pallet-membership: Do not verify the `MembershipChanged` in bechmarks' +doc: +- audience: Runtime Dev + description: |- + There is no need to verify in the `pallet-membership` benchmark that the `MemembershipChanged` implementation works as the pallet thinks it should work. If you for example set it to `()`, `get_prime()` will always return `None`. + + TLDR: Remove the checks of `MembershipChanged` in the benchmarks to support any kind of implementation. +crates: +- name: pallet-membership + bump: patch diff --git a/prdoc/pr_6440.prdoc b/prdoc/pr_6440.prdoc new file mode 100644 index 000000000000..376e59fa752e --- /dev/null +++ b/prdoc/pr_6440.prdoc @@ -0,0 +1,8 @@ +title: Remove debug message about pruning active leaves +doc: +- audience: Node Dev + description: |- + Removed useless debug message +crates: +- name: polkadot-node-core-pvf + validate: false diff --git a/prdoc/pr_6446.prdoc b/prdoc/pr_6446.prdoc new file mode 100644 index 000000000000..3bfe7d0c7a60 --- /dev/null +++ b/prdoc/pr_6446.prdoc @@ -0,0 +1,16 @@ +title: Make pallet-recovery supports `BlockNumberProvider` +doc: +- audience: Runtime Dev + description: |- + pallet-recovery now allows configuring the block provider to be utilized within this pallet. This block is employed for the delay in the recovery process. + + A new associated type has been introduced in the `Config` trait: `BlockNumberProvider`. This can be assigned to `System` to maintain the previous behavior, or it can be set to another block number provider, such as `RelayChain`. + + If the block provider is configured with a value different from `System`, a migration will be necessary for the `Recoverable` and `ActiveRecoveries` storage items. +crates: +- name: rococo-runtime + bump: major +- name: westend-runtime + bump: major +- name: pallet-recovery + bump: major diff --git a/prdoc/pr_6450.prdoc b/prdoc/pr_6450.prdoc new file mode 100644 index 000000000000..a9e927e45106 --- /dev/null +++ b/prdoc/pr_6450.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: Add omni-node checks for runtime parachain compatibility + +doc: + - audience: [ Node Dev, Runtime Dev ] + description: | + OmniNode parses runtime metadata and checks against the existence of `cumulus-pallet-parachain-system` + and `frame-system`, by filtering pallets by names: `ParachainSystem` and `System`. It also checks the + `frame-system` pallet storage `Number` type, and then uses it to configure AURA if `u32` or `u64`. + +crates: + - name: polkadot-omni-node-lib + bump: minor + - name: polkadot-sdk + bump: minor + - name: sc-runtime-utilities + bump: patch + - name: frame-benchmarking-cli + bump: major diff --git a/prdoc/pr_6452.prdoc b/prdoc/pr_6452.prdoc new file mode 100644 index 000000000000..f2cb69875e95 --- /dev/null +++ b/prdoc/pr_6452.prdoc @@ -0,0 +1,16 @@ +title: "elastic scaling RFC 103 end-to-end tests" + +doc: + - audience: [Node Dev, Runtime Dev] + description: | + Adds end-to-end zombienet-sdk tests for elastic scaling using the RFC103 implementation. + Only notable user-facing change is that the default chain configurations of westend and rococo + now enable by default the CandidateReceiptV2 node feature. + +crates: + - name: westend-runtime + bump: patch + - name: rococo-runtime + bump: patch + - name: rococo-parachain-runtime + bump: patch diff --git a/prdoc/pr_6453.prdoc b/prdoc/pr_6453.prdoc new file mode 100644 index 000000000000..5df44f11296d --- /dev/null +++ b/prdoc/pr_6453.prdoc @@ -0,0 +1,7 @@ +title: '[pallet-revive] breakdown integration tests' +doc: +- audience: Runtime Dev + description: Break down the single integration tests into multiple tests, use keccak-256 for tx.hash +crates: +- name: pallet-revive-eth-rpc + bump: minor diff --git a/prdoc/pr_6455.prdoc b/prdoc/pr_6455.prdoc new file mode 100644 index 000000000000..9a83048e2fd2 --- /dev/null +++ b/prdoc/pr_6455.prdoc @@ -0,0 +1,8 @@ +title: Add litep2p network protocol benches +doc: +- audience: Node Dev + description: |- + Adds networking protocol benchmarks with litep2p backend +crates: +- name: sc-network + validate: false diff --git a/prdoc/pr_6459.prdoc b/prdoc/pr_6459.prdoc new file mode 100644 index 000000000000..592ba4c6b29d --- /dev/null +++ b/prdoc/pr_6459.prdoc @@ -0,0 +1,22 @@ +# 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: Fix version conversion in XcmPaymentApi::query_weight_to_asset_fee. + +doc: + - audience: Runtime Dev + description: | + The `query_weight_to_asset_fee` function of the `XcmPaymentApi` was trying + to convert versions in the wrong way. + This resulted in all calls made with lower versions failing. + The version conversion is now done correctly and these same calls will now succeed. + +crates: + - name: asset-hub-westend-runtime + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: xcm-runtime-apis + bump: patch + - name: assets-common + bump: patch diff --git a/prdoc/pr_6460.prdoc b/prdoc/pr_6460.prdoc new file mode 100644 index 000000000000..e1fd1a740228 --- /dev/null +++ b/prdoc/pr_6460.prdoc @@ -0,0 +1,9 @@ +title: '[pallet-revive] set logs_bloom' +doc: +- audience: Runtime Dev + description: Set the logs_bloom in the transaction receipt +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor diff --git a/prdoc/pr_6461.prdoc b/prdoc/pr_6461.prdoc new file mode 100644 index 000000000000..1b3d1e8b0364 --- /dev/null +++ b/prdoc/pr_6461.prdoc @@ -0,0 +1,12 @@ +# 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: '[pallet-revive] add support for all eth tx types' +doc: +- audience: Runtime Dev + description: Add support for 1559, 4844, and 2930 transaction types +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor + diff --git a/prdoc/pr_6463.prdoc b/prdoc/pr_6463.prdoc new file mode 100644 index 000000000000..9c4787540a49 --- /dev/null +++ b/prdoc/pr_6463.prdoc @@ -0,0 +1,8 @@ +title: Fix staking benchmark +doc: +- audience: Runtime Dev + description: 'Fix staking benchmark, error was introduced when migrating to v2: + https://github.com/paritytech/polkadot-sdk/pull/6025' +crates: +- name: pallet-staking + bump: patch diff --git a/prdoc/pr_6466.prdoc b/prdoc/pr_6466.prdoc new file mode 100644 index 000000000000..0faa6afc8005 --- /dev/null +++ b/prdoc/pr_6466.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] add piggy-bank sol example' +doc: +- audience: Runtime Dev + description: |- + This PR update the pallet to use the EVM 18 decimal balance in contracts call and host functions instead of the native balance. + + It also updates the js example to add the piggy-bank solidity contract that expose the problem +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor diff --git a/prdoc/pr_6481.prdoc b/prdoc/pr_6481.prdoc new file mode 100644 index 000000000000..83ba0a32eb24 --- /dev/null +++ b/prdoc/pr_6481.prdoc @@ -0,0 +1,10 @@ +title: 'slot-based-collator: Implement dedicated block import' +doc: +- audience: Node Dev + description: |- + The `SlotBasedBlockImport` job is to collect the storage proofs of all blocks getting imported. These storage proofs alongside the block are being forwarded to the collation task. Right now they are just being thrown away. More logic will follow later. Basically this will be required to include multiple blocks into one `PoV` which will then be done by the collation task. +crates: +- name: cumulus-client-consensus-aura + bump: major +- name: polkadot-omni-node-lib + bump: major diff --git a/prdoc/pr_6486.prdoc b/prdoc/pr_6486.prdoc new file mode 100644 index 000000000000..e401d3f9a887 --- /dev/null +++ b/prdoc/pr_6486.prdoc @@ -0,0 +1,10 @@ +title: "sp-trie: minor fix to avoid panic on badly-constructed proof" + +doc: + - audience: ["Runtime Dev", "Runtime User"] + description: | + "Added a check when decoding encoded proof nodes in `sp-trie` to avoid panicking when receiving a badly constructed proof, instead erroring out." + +crates: +- name: sp-trie + bump: patch diff --git a/prdoc/pr_6502.prdoc b/prdoc/pr_6502.prdoc new file mode 100644 index 000000000000..3e2467ed5524 --- /dev/null +++ b/prdoc/pr_6502.prdoc @@ -0,0 +1,10 @@ +title: "sp-trie: correctly avoid panicking when decoding bad compact proofs" + +doc: + - audience: "Runtime Dev" + description: | + "Fixed the check introduced in [PR #6486](https://github.com/paritytech/polkadot-sdk/pull/6486). Now `sp-trie` correctly avoids panicking when decoding bad compact proofs." + +crates: +- name: sp-trie + bump: patch diff --git a/prdoc/pr_6503.prdoc b/prdoc/pr_6503.prdoc new file mode 100644 index 000000000000..dc296a93f0eb --- /dev/null +++ b/prdoc/pr_6503.prdoc @@ -0,0 +1,10 @@ +title: "xcm: minor fix for compatibility with V4" + +doc: + - audience: ["Runtime Dev", "Runtime User"] + description: | + Following the removal of `Rococo`, `Westend` and `Wococo` from `NetworkId`, fixed `xcm::v5::NetworkId` encoding/decoding to be compatible with `xcm::v4::NetworkId` + +crates: +- name: staging-xcm + bump: patch diff --git a/prdoc/pr_6506.prdoc b/prdoc/pr_6506.prdoc new file mode 100644 index 000000000000..7c6164a9959a --- /dev/null +++ b/prdoc/pr_6506.prdoc @@ -0,0 +1,10 @@ +title: Zero refund check for FungibleAdapter +doc: +- audience: Runtime User + description: |- + `FungibleAdapter` will now check if the _refund amount_ is zero before calling deposit & emitting an event. + + Fixes https://github.com/paritytech/polkadot-sdk/issues/6469. +crates: +- name: pallet-transaction-payment + bump: patch diff --git a/prdoc/pr_6509.prdoc b/prdoc/pr_6509.prdoc new file mode 100644 index 000000000000..74215fe0084c --- /dev/null +++ b/prdoc/pr_6509.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: Migrate pallet-democracy benchmark to v2 + +doc: + - audience: Runtime Dev + description: | + "Part of issue #6202." + +crates: +- name: pallet-democracy + bump: patch diff --git a/prdoc/pr_6521.prdoc b/prdoc/pr_6521.prdoc new file mode 100644 index 000000000000..6f4acf8d028b --- /dev/null +++ b/prdoc/pr_6521.prdoc @@ -0,0 +1,10 @@ +title: Pure state sync refactoring (part-2) + +doc: +- audience: Node Dev + description: | + This is the last part of the pure refactoring of state sync, focusing on encapsulating `StateSyncMetadata` as a separate entity. + +crates: +- name: sc-network-sync + bump: none diff --git a/prdoc/pr_6522.prdoc b/prdoc/pr_6522.prdoc new file mode 100644 index 000000000000..bd59e9cb08dc --- /dev/null +++ b/prdoc/pr_6522.prdoc @@ -0,0 +1,18 @@ +title: Removes constraint in BlockNumberProvider from treasury + +doc: +- audience: Runtime Dev + description: |- + https://github.com/paritytech/polkadot-sdk/pull/3970 updated the treasury pallet to support + relay chain block number provider. However, it added a constraint to the `BlockNumberProvider` + trait to have the same block number type as `frame_system`: + + ```rust + type BlockNumberProvider: BlockNumberProvider>; + ``` + + This PR removes that constraint and allows the treasury pallet to use any block number type. + +crates: +- name: pallet-treasury + bump: major \ No newline at end of file diff --git a/prdoc/pr_6526.prdoc b/prdoc/pr_6526.prdoc new file mode 100644 index 000000000000..9ea1368ab10c --- /dev/null +++ b/prdoc/pr_6526.prdoc @@ -0,0 +1,8 @@ +title: 'sp-runtime: Be a little bit more functional :D' +doc: +- audience: Runtime Dev + description: + Some internal refactorings in the `Digest` code. +crates: +- name: sp-runtime + bump: patch diff --git a/prdoc/pr_6528.prdoc b/prdoc/pr_6528.prdoc new file mode 100644 index 000000000000..477ad76c947f --- /dev/null +++ b/prdoc/pr_6528.prdoc @@ -0,0 +1,18 @@ +title: 'TransactionPool API uses async_trait' +doc: +- audience: Node Dev + description: |- + This PR refactors `TransactionPool` API to use `async_trait`, replacing the` Pin>` pattern. This should improve readability and maintainability. + + The change is not altering any functionality. +crates: +- name: sc-rpc-spec-v2 + bump: minor +- name: sc-service + bump: minor +- name: sc-transaction-pool-api + bump: major +- name: sc-transaction-pool + bump: major +- name: sc-rpc + bump: minor diff --git a/prdoc/pr_6533.prdoc b/prdoc/pr_6533.prdoc new file mode 100644 index 000000000000..eb72a97db0f8 --- /dev/null +++ b/prdoc/pr_6533.prdoc @@ -0,0 +1,20 @@ +title: "Migrate executor into PolkaVM 0.18.0" +doc: + - audience: Runtime Dev + description: | + Bump `polkavm` to 0.18.0, and update `sc-polkavm-executor` to be + compatible with the API changes. In addition, bump also `polkavm-derive` + and `polkavm-linker` in order to make sure that the all parts of the + Polkadot SDK use the exact same ABI for `.polkavm` binaries. + + Purely relying on RV32E/RV64E ABI is not possible, as PolkaVM uses a + RISCV-V alike ISA, which is derived from RV32E/RV64E but it is still its + own microarchitecture, i.e. not fully binary compatible. + +crates: + - name: sc-executor-common + bump: major + - name: sc-executor-polkavm + bump: minor + - name: substrate-wasm-builder + bump: minor diff --git a/prdoc/pr_6534.prdoc b/prdoc/pr_6534.prdoc new file mode 100644 index 000000000000..7a92fe3c857b --- /dev/null +++ b/prdoc/pr_6534.prdoc @@ -0,0 +1,10 @@ +title: Forward logging directives to Polkadot workers +doc: +- audience: Node Dev + description: |- + This pull request forward all the logging directives given to the node via `RUST_LOG` or `-l` to the workers, instead of only forwarding `RUST_LOG`. +crates: +- name: polkadot-node-core-pvf + bump: patch +- name: sc-tracing + bump: patch diff --git a/prdoc/pr_6540.prdoc b/prdoc/pr_6540.prdoc new file mode 100644 index 000000000000..5e0305205521 --- /dev/null +++ b/prdoc/pr_6540.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: Only allow apply slash to be executed if the slash amount is atleast ED + +doc: + - audience: Runtime User + description: | + This change prevents `pools::apply_slash` from being executed when the pending slash amount of the member is lower + than the ED. With this change, such small slashes will still be applied but only when member funds are withdrawn. + +crates: +- name: pallet-nomination-pools-runtime-api + bump: patch +- name: pallet-nomination-pools + bump: major diff --git a/prdoc/pr_6544.prdoc b/prdoc/pr_6544.prdoc new file mode 100644 index 000000000000..f2bc9627697d --- /dev/null +++ b/prdoc/pr_6544.prdoc @@ -0,0 +1,14 @@ +# 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: Add and test events to conviction voting pallet + +doc: + - audience: Runtime Dev + description: | + Add event for the unlocking of an expired conviction vote's funds, and test recently added + voting events. + +crates: + - name: pallet-conviction-voting + bump: major diff --git a/prdoc/pr_6546.prdoc b/prdoc/pr_6546.prdoc new file mode 100644 index 000000000000..353578a7f58f --- /dev/null +++ b/prdoc/pr_6546.prdoc @@ -0,0 +1,13 @@ +title: Increase default trie cache size to 1GiB +doc: +- audience: Node Operator + description: "The default trie cache size before was set to `64MiB`, which is quite\ + \ low to achieve real speed ups. `1GiB` should be a reasonable number as the requirements\ + \ for validators/collators/full nodes are much higher when it comes to minimum\ + \ memory requirements. Also the cache will not use `1GiB` from the start and fills\ + \ over time. The setting can be changed by setting `--trie-cache-size BYTE_SIZE`.\ + The CLI option `--state-cache-size` is also removed, which was not having any effect anymore.\r\ + \n" +crates: +- name: sc-cli + bump: patch diff --git a/prdoc/pr_6549.prdoc b/prdoc/pr_6549.prdoc new file mode 100644 index 000000000000..61a64c724185 --- /dev/null +++ b/prdoc/pr_6549.prdoc @@ -0,0 +1,247 @@ +doc: [] + +crates: + - name: polkadot-sdk + bump: none + - name: asset-test-utils + bump: none + - name: cumulus-pallet-parachain-system + bump: none + - name: cumulus-pallet-parachain-system-proc-macro + bump: none + - name: cumulus-primitives-core + bump: none + - name: polkadot-core-primitives + bump: none + - name: polkadot-parachain-primitives + bump: none + - name: polkadot-primitives + bump: none + - name: staging-xcm + bump: none + - name: xcm-procedural + bump: none + - name: cumulus-primitives-parachain-inherent + bump: none + - name: cumulus-primitives-proof-size-hostfunction + bump: none + - name: polkadot-runtime-common + bump: none + - name: polkadot-runtime-parachains + bump: none + - name: polkadot-runtime-metrics + bump: none + - name: staging-xcm-executor + bump: none + - name: slot-range-helper + bump: none + - name: staging-xcm-builder + bump: none + - name: pallet-xcm + bump: none + - name: cumulus-primitives-storage-weight-reclaim + bump: none + - name: cumulus-pallet-aura-ext + bump: none + - name: cumulus-primitives-aura + bump: none + - name: staging-parachain-info + bump: none + - name: cumulus-test-relay-sproof-builder + bump: none + - name: cumulus-client-cli + bump: none + - name: cumulus-client-collator + bump: none + - name: cumulus-client-consensus-common + bump: none + - name: cumulus-client-pov-recovery + bump: none + - name: cumulus-relay-chain-interface + bump: none + - name: polkadot-overseer + bump: none + - name: tracing-gum + bump: none + - name: tracing-gum-proc-macro + bump: none + - name: polkadot-node-metrics + bump: none + - name: polkadot-node-primitives + bump: none + - name: polkadot-erasure-coding + bump: none + - name: polkadot-node-subsystem + bump: none + - name: polkadot-node-subsystem-types + bump: none + - name: polkadot-node-network-protocol + bump: none + - name: polkadot-statement-table + bump: none + - name: polkadot-rpc + bump: none + - name: polkadot-service + bump: none + - name: cumulus-client-parachain-inherent + bump: none + - name: westend-runtime + bump: none + - name: pallet-xcm-benchmarks + bump: none + - name: westend-runtime-constants + bump: none + - name: polkadot-approval-distribution + bump: none + - name: polkadot-node-subsystem-util + bump: none + - name: polkadot-availability-bitfield-distribution + bump: none + - name: polkadot-availability-distribution + bump: none + - name: polkadot-availability-recovery + bump: none + - name: polkadot-node-core-approval-voting + bump: none + - name: polkadot-node-core-approval-voting-parallel + bump: none + - name: polkadot-node-core-av-store + bump: none + - name: polkadot-node-core-chain-api + bump: none + - name: polkadot-statement-distribution + bump: none + - name: polkadot-collator-protocol + bump: none + - name: polkadot-dispute-distribution + bump: none + - name: polkadot-gossip-support + bump: none + - name: polkadot-network-bridge + bump: none + - name: polkadot-node-collation-generation + bump: none + - name: polkadot-node-core-backing + bump: none + - name: polkadot-node-core-bitfield-signing + bump: none + - name: polkadot-node-core-candidate-validation + bump: none + - name: polkadot-node-core-pvf + bump: none + - name: polkadot-node-core-pvf-common + bump: none + - name: polkadot-node-core-pvf-execute-worker + bump: none + - name: polkadot-node-core-pvf-prepare-worker + bump: none + - name: staging-tracking-allocator + bump: none + - name: rococo-runtime + bump: none + - name: rococo-runtime-constants + bump: none + - name: polkadot-node-core-chain-selection + bump: none + - name: polkadot-node-core-dispute-coordinator + bump: none + - name: polkadot-node-core-parachains-inherent + bump: none + - name: polkadot-node-core-prospective-parachains + bump: none + - name: polkadot-node-core-provisioner + bump: none + - name: polkadot-node-core-pvf-checker + bump: none + - name: polkadot-node-core-runtime-api + bump: none + - name: cumulus-client-network + bump: none + - name: cumulus-relay-chain-inprocess-interface + bump: none + - name: polkadot-cli + bump: none + - name: cumulus-client-consensus-aura + bump: none + - name: cumulus-client-consensus-proposer + bump: none + - name: cumulus-client-consensus-relay-chain + bump: none + - name: cumulus-client-service + bump: none + - name: cumulus-relay-chain-minimal-node + bump: none + - name: cumulus-relay-chain-rpc-interface + bump: none + - name: parachains-common + bump: none + - name: cumulus-primitives-utility + bump: none + - name: cumulus-pallet-xcmp-queue + bump: none + - name: parachains-runtimes-test-utils + bump: none + - name: assets-common + bump: none + - name: bridge-hub-common + bump: none + - name: bridge-hub-test-utils + bump: none + - name: cumulus-pallet-solo-to-para + bump: none + - name: cumulus-pallet-xcm + bump: none + - name: cumulus-ping + bump: none + - name: cumulus-primitives-timestamp + bump: none + - name: emulated-integration-tests-common + bump: none + - name: xcm-emulator + bump: none + - name: pallet-collective-content + bump: none + - name: xcm-simulator + bump: none + - name: pallet-revive-fixtures + bump: none + - name: polkadot-omni-node-lib + bump: none + - name: snowbridge-runtime-test-common + bump: none + - name: testnet-parachains-constants + bump: none + - name: asset-hub-rococo-runtime + bump: none + - name: asset-hub-westend-runtime + bump: none + - name: bridge-hub-rococo-runtime + bump: none + - name: bridge-hub-westend-runtime + bump: none + - name: collectives-westend-runtime + bump: none + - name: coretime-rococo-runtime + bump: none + - name: coretime-westend-runtime + bump: none + - name: people-rococo-runtime + bump: none + - name: people-westend-runtime + bump: none + - name: contracts-rococo-runtime + bump: none + - name: glutton-westend-runtime + bump: none + - name: rococo-parachain-runtime + bump: none + - name: polkadot-omni-node + bump: none + - name: polkadot-parachain-bin + bump: none + - name: polkadot + bump: none + - name: polkadot-voter-bags + bump: none + - name: xcm-simulator-example + bump: none diff --git a/prdoc/pr_6553.prdoc b/prdoc/pr_6553.prdoc new file mode 100644 index 000000000000..8692eba3a9f5 --- /dev/null +++ b/prdoc/pr_6553.prdoc @@ -0,0 +1,13 @@ +title: Ensure sync event is processed on unknown peer roles + +doc: + - audience: Node Dev + description: | + The GossipEngine::poll_next implementation polls both the notification_service and the sync_event_stream. + This PR ensures both events are processed gracefully. + +crates: + - name: sc-network-gossip + bump: patch + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_6561.prdoc b/prdoc/pr_6561.prdoc new file mode 100644 index 000000000000..714521925a6b --- /dev/null +++ b/prdoc/pr_6561.prdoc @@ -0,0 +1,11 @@ +title: 'slot-based-collator: Move spawning of the futures' +doc: +- audience: Node Dev + description: "Move spawning of the slot-based collator into the `run` function.\ + \ Also the tasks are being spawned as blocking task and not just as normal tasks.\r\ + \n" +crates: +- name: cumulus-client-consensus-aura + bump: major +- name: polkadot-omni-node-lib + bump: major diff --git a/prdoc/pr_6562.prdoc b/prdoc/pr_6562.prdoc new file mode 100644 index 000000000000..250b656aefb5 --- /dev/null +++ b/prdoc/pr_6562.prdoc @@ -0,0 +1,14 @@ +# 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: Hide nonce implementation details in metadata + +doc: + - audience: Runtime Dev + description: | + Use custom implementation of TypeInfo for TypeWithDefault to show inner value's type info. + This should bring back nonce to u64 in metadata. + +crates: +- name: sp-runtime + bump: minor \ No newline at end of file diff --git a/prdoc/pr_6565.prdoc b/prdoc/pr_6565.prdoc new file mode 100644 index 000000000000..f9a75a16a6a7 --- /dev/null +++ b/prdoc/pr_6565.prdoc @@ -0,0 +1,35 @@ +title: 'pallet_revive: Switch to 64bit RISC-V' +doc: +- audience: Runtime Dev + description: |- + This PR updates pallet_revive to the newest PolkaVM version and adapts the test fixtures and syscall interface to work under 64bit. + + Please note that after this PR no 32bit contracts can be deployed (they will be rejected at deploy time). Pre-deployed 32bit contracts are now considered defunct since we changes how parameters are passed for functions with more than 6 arguments. + + ## Fixtures + + The fixtures are now built for the 64bit target. I also removed the temporary directory mechanism that triggered a full rebuild every time. It also makes it easier to find the compiled fixtures since they are now always in `target/pallet-revive-fixtures`. + + ## Syscall interface + + ### Passing pointer + + Registers and pointers are now 64bit wide. This allows us to pass u64 arguments in a single register. Before we needed two registers to pass them. This means that just as before we need one register per pointer we pass. We keep pointers as `u32` argument by truncating the register. This is done since the memory space of PolkaVM is 32bit. + + ### Functions with more than 6 arguments + + We only have 6 registers to pass arguments. This is why we pass a pointer to a struct when we need more than 6. Before this PR we expected a packed struct and interpreted it as SCALE encoded tuple. However, this was buggy because the `MaxEncodedLen` returned something that was larger than the packed size of the structure. This wasn't a problem before. But now the memory space changed in a way that things were placed at the edges of the memory space and those extra bytes lead to an out of bound access. + + This is why this PR drops SCALE and expects the arguments to be passed as a pointer to a `C` aligned struct. This avoids unaligned accesses. However, revive needs to adapt its codegen to properly align the structure fields. + + ## TODO + - [ ] Add multi block migration that wipes all existing contracts as we made breaking changes to the syscall interface +crates: +- name: pallet-revive + bump: major +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive-proc-macro + bump: major +- name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6583.prdoc b/prdoc/pr_6583.prdoc new file mode 100644 index 000000000000..0e67ed33e27c --- /dev/null +++ b/prdoc/pr_6583.prdoc @@ -0,0 +1,7 @@ +title: Bump Westend AH +doc: +- audience: Runtime Dev + description: Bump Asset-Hub westend spec version +crates: +- name: asset-hub-westend-runtime + bump: minor diff --git a/prdoc/pr_6604.prdoc b/prdoc/pr_6604.prdoc new file mode 100644 index 000000000000..dc198287ff67 --- /dev/null +++ b/prdoc/pr_6604.prdoc @@ -0,0 +1,106 @@ +title: 'dmp: Check that the para exist before delivering a message' +doc: +- audience: Runtime Dev + description: | + Ensure that a para exists before trying to deliver a message to it. + Besides that `ensure_successful_delivery` function is added to `SendXcm`. This function + should be used by benchmarks to ensure that the delivery of a Xcm will work in the benchmark. +crates: +- name: polkadot-runtime-parachains + bump: major +- name: polkadot-runtime-common + bump: major +- name: polkadot-parachain-primitives + bump: major +- name: rococo-runtime + bump: major +- name: westend-runtime + bump: major +- name: pallet-xcm-benchmarks + bump: major +- name: pallet-xcm + bump: major +- name: cumulus-pallet-parachain-system + bump: major +- name: staging-xcm + bump: major +- name: staging-xcm-builder + bump: major +- name: bridge-runtime-common + bump: major +- name: pallet-xcm-bridge-hub-router + bump: major +- name: pallet-xcm-bridge-hub + bump: major +- name: snowbridge-pallet-inbound-queue + bump: major +- name: snowbridge-pallet-system + bump: major +- name: snowbridge-core + bump: major +- name: snowbridge-router-primitives + bump: major +- name: snowbridge-runtime-common + bump: major +- name: snowbridge-runtime-test-common + bump: major +- name: cumulus-pallet-dmp-queue + bump: major +- name: cumulus-pallet-xcmp-queue + bump: major +- name: parachains-common + bump: major +- name: asset-hub-rococo-runtime + bump: major +- name: asset-hub-westend-runtime + bump: major +- name: assets-common + bump: major +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: major +- name: bridge-hub-common + bump: major +- name: collectives-westend-runtime + bump: major +- name: contracts-rococo-runtime + bump: major +- name: coretime-rococo-runtime + bump: major +- name: coretime-westend-runtime + bump: major +- name: glutton-westend-runtime + bump: major +- name: people-rococo-runtime + bump: major +- name: people-westend-runtime + bump: major +- name: penpal-runtime + bump: major +- name: rococo-parachain-runtime + bump: major +- name: polkadot-parachain-bin + bump: major +- name: cumulus-primitives-core + bump: major +- name: cumulus-primitives-utility + bump: major +- name: polkadot-service + bump: major +- name: staging-xcm-executor + bump: major +- name: xcm-runtime-apis + bump: major +- name: xcm-simulator-example + bump: major +- name: pallet-contracts + bump: major +- name: pallet-contracts-mock-network + bump: major +- name: pallet-revive + bump: major +- name: pallet-revive-mock-network + bump: major +- name: polkadot-sdk + bump: major diff --git a/prdoc/pr_6605.prdoc b/prdoc/pr_6605.prdoc new file mode 100644 index 000000000000..2adb1d8aee35 --- /dev/null +++ b/prdoc/pr_6605.prdoc @@ -0,0 +1,10 @@ +title: Notify telemetry only every second about the tx pool status +doc: +- audience: Node Operator + description: |- + Before this was done for every imported transaction. When a lot of transactions got imported, the import notification channel was filled. The underlying problem was that the `status` call is read locking the `validated_pool` which will be write locked by the internal submitting logic. Thus, the submitting and status reading was interferring which each other. +crates: +- name: cumulus-client-service + bump: patch +- name: sc-service + bump: patch diff --git a/prdoc/pr_6608.prdoc b/prdoc/pr_6608.prdoc new file mode 100644 index 000000000000..b9cd7008de47 --- /dev/null +++ b/prdoc/pr_6608.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] eth-prc fix geth diff' +doc: +- audience: Runtime Dev + description: |- + * Add a bunch of differential tests to ensure that responses from eth-rpc matches the one from `geth` + * EVM RPC server will not fail gas_estimation if no gas is specified, I updated pallet-revive to add an extra `skip_transfer` boolean check to replicate this behavior in our pallet + * `eth_transact` and `bare_eth_transact` api have been updated to use `GenericTransaction` directly as this is what is used by `eth_estimateGas` and `eth_call` +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor +- name: asset-hub-westend-runtime + bump: minor diff --git a/prdoc/pr_6624.prdoc b/prdoc/pr_6624.prdoc new file mode 100644 index 000000000000..4db55a46e8df --- /dev/null +++ b/prdoc/pr_6624.prdoc @@ -0,0 +1,11 @@ +# 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: Use `cmd_lib` instead of `std::process::Command` when using `#[docify::export]` + +doc: + - audience: Runtime Dev + description: | + Simplified the display of commands and ensured they are tested for chain spec builder's `polkadot-sdk` reference docs. + +crates: [] \ No newline at end of file diff --git a/prdoc/pr_6628.prdoc b/prdoc/pr_6628.prdoc new file mode 100644 index 000000000000..7ea0c4968385 --- /dev/null +++ b/prdoc/pr_6628.prdoc @@ -0,0 +1,12 @@ +title: "Remove ReportCollator message" + +doc: + - audience: Node Dev + description: | + Remove unused message ReportCollator and test related to this message on the collator protocol validator side. + +crates: + - name: polkadot-node-subsystem-types + bump: patch + - name: polkadot-collator-protocol + bump: major \ No newline at end of file diff --git a/prdoc/pr_6636.prdoc b/prdoc/pr_6636.prdoc new file mode 100644 index 000000000000..1db5fd54d971 --- /dev/null +++ b/prdoc/pr_6636.prdoc @@ -0,0 +1,9 @@ +title: Optimize initialization of networking protocol benchmarks +doc: +- audience: Node Dev + description: |- + These changes should enhance the quality of benchmark results by excluding worker initialization time from the measurements and reducing the overall duration of the benchmarks. + +crates: +- name: sc-network + validate: false diff --git a/prdoc/pr_6665.prdoc b/prdoc/pr_6665.prdoc new file mode 100644 index 000000000000..b5aaf8a3b184 --- /dev/null +++ b/prdoc/pr_6665.prdoc @@ -0,0 +1,15 @@ +title: Fix runtime api impl detection by construct runtime +doc: +- audience: Runtime Dev + description: |- + Construct runtime uses autoref-based specialization to fetch the metadata about the implemented runtime apis. This is done to not fail to compile when there are no runtime apis implemented. However, there was an issue with detecting runtime apis when they were implemented in a different file. The problem is solved by moving the trait implemented by `impl_runtime_apis!` to the metadata ir crate. + + + Closes: https://github.com/paritytech/polkadot-sdk/issues/6659 +crates: +- name: frame-support-procedural + bump: patch +- name: sp-api-proc-macro + bump: patch +- name: sp-metadata-ir + bump: patch diff --git a/prdoc/pr_6673.prdoc b/prdoc/pr_6673.prdoc new file mode 100644 index 000000000000..d2ca3c61ff39 --- /dev/null +++ b/prdoc/pr_6673.prdoc @@ -0,0 +1,7 @@ +title: 'chain-spec-guide-runtime: path to wasm blob fixed' +doc: +- audience: Runtime Dev + description: In `chain-spec-guide-runtime` crate's tests, there was assumption that + release version of wasm blob exists. This PR uses `chain_spec_guide_runtime::runtime::WASM_BINARY_PATH` + const to use correct path to runtime blob. +crates: [] diff --git a/prdoc/pr_6681.prdoc b/prdoc/pr_6681.prdoc new file mode 100644 index 000000000000..93a967d4a66c --- /dev/null +++ b/prdoc/pr_6681.prdoc @@ -0,0 +1,406 @@ +# 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: update scale-info to 2.11.6 + +doc: + - audience: Runtime Dev + description: | + Updates scale-info to 2.11.1 from 2.11.5. + Updated version of scale-info annotates generated code with `allow(deprecated)` + +crates: + - name: bridge-runtime-common + bump: none + - name: bp-header-chain + bump: none + - name: bp-runtime + bump: none + - name: frame-support + bump: none + - name: sp-core + bump: none + - name: sp-trie + bump: none + - name: sp-runtime + bump: none + - name: sp-application-crypto + bump: none + - name: sp-arithmetic + bump: none + - name: sp-weights + bump: none + - name: sp-api + bump: none + - name: sp-metadata-ir + bump: none + - name: sp-version + bump: none + - name: sp-inherents + bump: none + - name: frame-executive + bump: none + - name: frame-system + bump: none + - name: pallet-balances + bump: none + - name: frame-benchmarking + bump: none + - name: pallet-migrations + bump: none + - name: cumulus-pallet-parachain-system + bump: none + - name: cumulus-primitives-core + bump: none + - name: polkadot-core-primitives + bump: none + - name: polkadot-parachain-primitives + bump: none + - name: polkadot-primitives + bump: none + - name: sp-authority-discovery + bump: none + - name: sp-consensus-slots + bump: none + - name: sp-staking + bump: none + - name: staging-xcm + bump: none + - name: cumulus-primitives-parachain-inherent + bump: none + - name: pallet-message-queue + bump: none + - name: polkadot-runtime-common + bump: none + - name: frame-election-provider-support + bump: none + - name: sp-npos-elections + bump: none + - name: sp-consensus-grandpa + bump: none + - name: polkadot-primitives + bump: none + - name: sp-authority-discovery + bump: none + - name: sp-consensus-grandpa + bump: none + - name: sp-genesis-builder + bump: none + - name: sp-consensus-babe + bump: none + - name: sp-mixnet + bump: none + - name: sc-rpc-api + bump: none + - name: sp-session + bump: none + - name: sp-statement-store + bump: none + - name: sp-transaction-storage-proof + bump: none + - name: pallet-asset-rate + bump: none + - name: pallet-authorship + bump: none + - name: pallet-babe + bump: none + - name: pallet-session + bump: none + - name: pallet-timestamp + bump: none + - name: pallet-offences + bump: none + - name: pallet-staking + bump: none + - name: pallet-bags-list + bump: none + - name: pallet-broker + bump: none + - name: pallet-election-provider-multi-phase + bump: none + - name: pallet-fast-unstake + bump: none + - name: pallet-identity + bump: none + - name: pallet-transaction-payment + bump: none + - name: pallet-treasury + bump: none + - name: pallet-utility + bump: none + - name: pallet-collective + bump: none + - name: pallet-root-testing + bump: none + - name: pallet-vesting + bump: none + - name: polkadot-runtime-parachains + bump: none + - name: pallet-authority-discovery + bump: none + - name: pallet-mmr + bump: none + - name: sp-mmr-primitives + bump: none + - name: staging-xcm-executor + bump: none + - name: staging-xcm-builder + bump: none + - name: pallet-asset-conversion + bump: none + - name: pallet-assets + bump: none + - name: pallet-salary + bump: none + - name: pallet-ranked-collective + bump: none + - name: pallet-xcm + bump: none + - name: xcm-runtime-apis + bump: none + - name: pallet-grandpa + bump: none + - name: pallet-indices + bump: none + - name: pallet-sudo + bump: none + - name: sp-consensus-beefy + bump: none + - name: cumulus-primitives-storage-weight-reclaim + bump: none + - name: cumulus-pallet-aura-ext + bump: none + - name: pallet-aura + bump: none + - name: sp-consensus-aura + bump: none + - name: pallet-collator-selection + bump: none + - name: pallet-glutton + bump: none + - name: staging-parachain-info + bump: none + - name: westend-runtime + bump: none + - name: frame-metadata-hash-extension + bump: none + - name: frame-system-benchmarking + bump: none + - name: pallet-beefy + bump: none + - name: pallet-beefy-mmr + bump: none + - name: pallet-conviction-voting + bump: none + - name: pallet-scheduler + bump: none + - name: pallet-preimage + bump: none + - name: pallet-delegated-staking + bump: none + - name: pallet-nomination-pools + bump: none + - name: pallet-democracy + bump: none + - name: pallet-elections-phragmen + bump: none + - name: pallet-membership + bump: none + - name: pallet-multisig + bump: none + - name: polkadot-sdk-frame + bump: none + - name: pallet-dev-mode + bump: none + - name: pallet-verify-signature + bump: none + - name: pallet-nomination-pools-benchmarking + bump: none + - name: pallet-offences-benchmarking + bump: none + - name: pallet-im-online + bump: none + - name: pallet-parameters + bump: none + - name: pallet-proxy + bump: none + - name: pallet-recovery + bump: none + - name: pallet-referenda + bump: none + - name: pallet-society + bump: none + - name: pallet-state-trie-migration + bump: none + - name: pallet-whitelist + bump: none + - name: pallet-xcm-benchmarks + bump: none + - name: rococo-runtime + bump: none + - name: pallet-bounties + bump: none + - name: pallet-child-bounties + bump: none + - name: pallet-nis + bump: none + - name: pallet-tips + bump: none + - name: parachains-common + bump: none + - name: pallet-asset-tx-payment + bump: none + - name: cumulus-pallet-xcmp-queue + bump: none + - name: bp-xcm-bridge-hub-router + bump: none + - name: pallet-xcm-bridge-hub-router + bump: none + - name: assets-common + bump: none + - name: bp-messages + bump: none + - name: bp-parachains + bump: none + - name: bp-polkadot-core + bump: none + - name: bp-relayers + bump: none + - name: bp-xcm-bridge-hub + bump: none + - name: bridge-hub-common + bump: none + - name: snowbridge-core + bump: none + - name: snowbridge-beacon-primitives + bump: none + - name: snowbridge-ethereum + bump: none + - name: pallet-bridge-grandpa + bump: none + - name: pallet-bridge-messages + bump: none + - name: pallet-bridge-parachains + bump: none + - name: pallet-bridge-relayers + bump: none + - name: pallet-xcm-bridge-hub + bump: none + - name: cumulus-pallet-dmp-queue + bump: none + - name: cumulus-pallet-solo-to-para + bump: none + - name: cumulus-pallet-xcm + bump: none + - name: cumulus-ping + bump: none + - name: frame-benchmarking-pallet-pov + bump: none + - name: pallet-alliance + bump: none + - name: pallet-asset-conversion-ops + bump: none + - name: pallet-asset-conversion-tx-payment + bump: none + - name: pallet-assets-freezer + bump: none + - name: pallet-atomic-swap + bump: none + - name: pallet-collective-content + bump: none + - name: pallet-contracts + bump: none + - name: pallet-contracts-uapi + bump: none + - name: pallet-insecure-randomness-collective-flip + bump: none + - name: pallet-contracts-mock-network + bump: none + - name: xcm-simulator + bump: none + - name: pallet-core-fellowship + bump: none + - name: pallet-lottery + bump: none + - name: pallet-mixnet + bump: none + - name: pallet-nft-fractionalization + bump: none + - name: pallet-nfts + bump: none + - name: pallet-node-authorization + bump: none + - name: pallet-paged-list + bump: none + - name: pallet-remark + bump: none + - name: pallet-revive + bump: none + - name: pallet-revive-uapi + bump: none + - name: pallet-revive-eth-rpc + bump: none + - name: pallet-skip-feeless-payment + bump: none + - name: pallet-revive-mock-network + bump: none + - name: pallet-root-offences + bump: none + - name: pallet-safe-mode + bump: none + - name: pallet-scored-pool + bump: none + - name: pallet-statement + bump: none + - name: pallet-transaction-storage + bump: none + - name: pallet-tx-pause + bump: none + - name: pallet-uniques + bump: none + - name: snowbridge-outbound-queue-merkle-tree + bump: none + - name: snowbridge-pallet-ethereum-client + bump: none + - name: snowbridge-pallet-inbound-queue + bump: none + - name: snowbridge-router-primitives + bump: none + - name: snowbridge-pallet-outbound-queue + bump: none + - name: snowbridge-pallet-system + bump: none + - name: bp-asset-hub-rococo + bump: none + - name: bp-asset-hub-westend + bump: none + - name: bp-polkadot-bulletin + bump: none + - name: asset-hub-rococo-runtime + bump: none + - name: asset-hub-westend-runtime + bump: none + - name: bridge-hub-rococo-runtime + bump: none + - name: bridge-hub-westend-runtime + bump: none + - name: collectives-westend-runtime + bump: none + - name: coretime-rococo-runtime + bump: none + - name: coretime-westend-runtime + bump: none + - name: people-rococo-runtime + bump: none + - name: people-westend-runtime + bump: none + - name: penpal-runtime + bump: none + - name: contracts-rococo-runtime + bump: none + - name: glutton-westend-runtime + bump: none + - name: rococo-parachain-runtime + bump: none + - name: xcm-simulator-example + bump: none \ No newline at end of file diff --git a/prdoc/pr_6695.prdoc b/prdoc/pr_6695.prdoc new file mode 100644 index 000000000000..7a950e8546cd --- /dev/null +++ b/prdoc/pr_6695.prdoc @@ -0,0 +1,8 @@ +title: '[pallet-revive] bugfix decoding 64bit args in the decoder' +doc: +- audience: Runtime Dev + description: The argument index of the next argument is dictated by the size of + the current one. +crates: +- name: pallet-revive-proc-macro + bump: patch diff --git a/prdoc/pr_6703.prdoc b/prdoc/pr_6703.prdoc new file mode 100644 index 000000000000..2dd0962a3eea --- /dev/null +++ b/prdoc/pr_6703.prdoc @@ -0,0 +1,7 @@ +title: 'network/libp2p-backend: Suppress warning adding already reserved node as reserved' +doc: +- audience: Node Dev + description: Fixes https://github.com/paritytech/polkadot-sdk/issues/6598. +crates: +- name: sc-network + bump: patch diff --git a/prdoc/pr_6711.prdoc b/prdoc/pr_6711.prdoc new file mode 100644 index 000000000000..ec09035e1356 --- /dev/null +++ b/prdoc/pr_6711.prdoc @@ -0,0 +1,13 @@ +title: Expose DHT content providers API from `sc-network` +doc: +- audience: Node Dev + description: |- + Expose the Kademlia content providers API for the use by `sc-network` client code: + 1. Extend the `NetworkDHTProvider` trait with functions to start/stop providing content and query the DHT for the list of content providers for a given key. + 2. Extend the `DhtEvent` enum with events reporting the found providers or query failures. + 3. Implement the above for libp2p & litep2p network backends. +crates: +- name: sc-network + bump: major +- name: sc-authority-discovery + bump: major diff --git a/prdoc/pr_6728.prdoc b/prdoc/pr_6728.prdoc new file mode 100644 index 000000000000..68f61190d947 --- /dev/null +++ b/prdoc/pr_6728.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] eth-rpc add missing tests' +doc: +- audience: Runtime Dev + description: |- + Add tests for #6608 + + fix https://github.com/paritytech/contract-issues/issues/12 +crates: +- name: pallet-revive-eth-rpc + bump: minor +- name: pallet-revive + bump: minor diff --git a/prdoc/pr_6741.prdoc b/prdoc/pr_6741.prdoc new file mode 100644 index 000000000000..d4b795038bcd --- /dev/null +++ b/prdoc/pr_6741.prdoc @@ -0,0 +1,16 @@ +title: 'pallet-revive: Adjust error handling of sub calls' +doc: +- audience: Runtime Dev + description: |- + We were trapping the host context in case a sub call was exhausting the storage deposit limit set for this sub call. This prevents the caller from handling this error. In this PR we added a new error code that is returned when either gas or storage deposit limit is exhausted by the sub call. + + We also remove the longer used `NotCallable` error. No longer used because this is no longer an error: It will just be a balance transfer. + + We also make `set_code_hash` infallible to be consistent with other host functions which just trap on any error condition. +crates: +- name: pallet-revive + bump: major +- name: pallet-revive-uapi + bump: major +- name: pallet-revive-fixtures + bump: major diff --git a/prdoc/pr_6743.prdoc b/prdoc/pr_6743.prdoc new file mode 100644 index 000000000000..4c35ff46ca67 --- /dev/null +++ b/prdoc/pr_6743.prdoc @@ -0,0 +1,10 @@ +title: 'umbrella: Remove `pallet-revive-fixtures`' +doc: +- audience: Runtime Dev + description: |- + No need to have them in the umbrella crate also by having them in the umbrella crate they are bleeding into the normal build. +crates: +- name: pallet-revive-fixtures + bump: major +- name: polkadot-sdk + bump: major diff --git a/prdoc/pr_6759.prdoc b/prdoc/pr_6759.prdoc new file mode 100644 index 000000000000..3dff12d740d4 --- /dev/null +++ b/prdoc/pr_6759.prdoc @@ -0,0 +1,16 @@ +title: 'pallet-revive: Statically verify imports on code deployment' +doc: +- audience: Runtime Dev + description: |- + Previously, we failed at runtime if an unknown or unstable host function was called. This requires us to keep track of when a host function was added and when a code was deployed. We used the `api_version` to track at which API version each code was deployed. This made sure that when a new host function was added that old code won't have access to it. This is necessary as otherwise the behavior of a contract that made calls to this previously non existent host function would change from "trap" to "do something". + + In this PR we remove the API version. Instead, we statically verify on upload that no non-existent host function is ever used in the code. This will allow us to add new host function later without needing to keep track when they were added. + + This simplifies the code and also gives an immediate feedback if unknown host functions are used. +crates: +- name: pallet-revive-proc-macro + bump: major +- name: pallet-revive + bump: major +- name: pallet-revive-fixtures + bump: major diff --git a/prdoc/pr_6768.prdoc b/prdoc/pr_6768.prdoc new file mode 100644 index 000000000000..3e194078df26 --- /dev/null +++ b/prdoc/pr_6768.prdoc @@ -0,0 +1,14 @@ +title: '`basic-authorship`: debug level is now less spammy' +doc: +- audience: Node Dev + description: |- + The `debug` level in `sc-basic-authorship` is now less spammy. Previously it was outputing logs per individual transactions. It made quite hard to follow the logs (and also generates unneeded traffic in grafana). + + Now debug level only show some internal details, without spamming output with per-transaction logs. They were moved to `trace` level. + + I also added the `EndProposingReason` to the summary INFO message. This allows us to know what was the block limit (which is very useful for debugging). +crates: +- name: sc-basic-authorship + bump: major +- name: sc-proposer-metrics + bump: major diff --git a/prdoc/pr_6792.prdoc b/prdoc/pr_6792.prdoc new file mode 100644 index 000000000000..80982a34b3e8 --- /dev/null +++ b/prdoc/pr_6792.prdoc @@ -0,0 +1,11 @@ +title: Add fallback_max_weight to snowbridge Transact +doc: +- audience: Runtime Dev + description: |- + We removed the `require_weight_at_most` field and later changed it to `fallback_max_weight`. + This was to have a fallback when sending a message to v4 chains, which happens in the small time window when chains are upgrading. + We originally put no fallback for a message in snowbridge's inbound queue but we should have one. + This PR adds it. +crates: +- name: snowbridge-router-primitives + bump: patch diff --git a/prdoc/pr_6796.prdoc b/prdoc/pr_6796.prdoc new file mode 100644 index 000000000000..aeb305847bf8 --- /dev/null +++ b/prdoc/pr_6796.prdoc @@ -0,0 +1,9 @@ +title: 'pallet-revive: Remove unused dependencies' +doc: +- audience: Runtime Dev + description: The dependency on `pallet_balances` doesn't seem to be necessary. At + least everything compiles for me without it. Removed this dependency and a few + others that seem to be left overs. +crates: +- name: pallet-revive + bump: major diff --git a/prdoc/pr_6832.prdoc b/prdoc/pr_6832.prdoc new file mode 100644 index 000000000000..bd0abbfba853 --- /dev/null +++ b/prdoc/pr_6832.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: "Remove collation-generation subsystem from validator nodes" + +doc: + - audience: Node Dev + description: | + Collation-generation is only needed for Collators, and therefore not needed for validators + +crates: + - name: polkadot-service + bump: patch \ No newline at end of file diff --git a/prdoc/pr_6835.prdoc b/prdoc/pr_6835.prdoc new file mode 100644 index 000000000000..73d1a81e761c --- /dev/null +++ b/prdoc/pr_6835.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] implement the call data load API' +doc: +- audience: Runtime Dev + description: |- + This PR implements the call data load API akin to [how it works on ethereum](https://www.evm.codes/?fork=cancun#35). +crates: +- name: pallet-revive-fixtures + bump: minor +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_6844.prdoc b/prdoc/pr_6844.prdoc new file mode 100644 index 000000000000..32901bf04df9 --- /dev/null +++ b/prdoc/pr_6844.prdoc @@ -0,0 +1,8 @@ +title: 'pallet-revive: disable host functions unused in solidity PolkaVM compiler' +doc: +- audience: Runtime Dev + description: Disables host functions in contracts that are not enabled + in solidity PolkaVM compiler to reduce surface of possible attack vectors. +crates: +- name: pallet-revive + bump: major diff --git a/prdoc/pr_6857.prdoc b/prdoc/pr_6857.prdoc new file mode 100644 index 000000000000..3930f5910487 --- /dev/null +++ b/prdoc/pr_6857.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] implement the call data size API' +doc: +- audience: Runtime Dev + description: |- + This PR adds an API method to query the contract call data input size. + + Part of #6770 +crates: +- name: pallet-revive-fixtures + bump: minor +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_6865.prdoc b/prdoc/pr_6865.prdoc new file mode 100644 index 000000000000..c0581f2af24f --- /dev/null +++ b/prdoc/pr_6865.prdoc @@ -0,0 +1,9 @@ +title: Rename PanicInfo to PanicHookInfo +doc: +- audience: Node Dev + description: Starting with Rust 1.82 `PanicInfo` is deprecated and will throw warnings + when used. The new type is available since Rust 1.81 and should be available on + our CI. +crates: +- name: sp-panic-handler + bump: patch diff --git a/prdoc/pr_6866.prdoc b/prdoc/pr_6866.prdoc new file mode 100644 index 000000000000..fac40dc103d7 --- /dev/null +++ b/prdoc/pr_6866.prdoc @@ -0,0 +1,13 @@ +title: Refactor `pallet-revive-uapi` pallet +doc: +- audience: Runtime Dev + description: Puts unstable host functions in `uapi` under + `unstable-api` feature while moving those functions after + stable functions. +crates: +- name: pallet-revive + bump: patch +- name: pallet-revive-fixtures + bump: patch +- name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6880.prdoc b/prdoc/pr_6880.prdoc new file mode 100644 index 000000000000..9d59382f0e0b --- /dev/null +++ b/prdoc/pr_6880.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] implement the call data copy API' +doc: +- audience: Runtime Dev + description: |- + This PR implements the call data copy API by adjusting the input method. + + Closes #6770 +crates: +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive + bump: major +- name: pallet-revive-uapi + bump: major \ No newline at end of file diff --git a/prdoc/pr_6889.prdoc b/prdoc/pr_6889.prdoc new file mode 100644 index 000000000000..01edd49b685a --- /dev/null +++ b/prdoc/pr_6889.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: Remove polkadot-omni-node-lib unused dependency + +doc: + - audience: Node Dev + description: + Removed an unused dependency for `polkadot-omni-node-lib`. + +crates: + - name: polkadot-omni-node-lib + bump: patch diff --git a/prdoc/pr_6896.prdoc b/prdoc/pr_6896.prdoc new file mode 100644 index 000000000000..a56e4303d9af --- /dev/null +++ b/prdoc/pr_6896.prdoc @@ -0,0 +1,16 @@ +title: 'pallet-revive: Fix docs.rs' +doc: +- audience: Runtime Dev + description: |- + - Fixed failing docs.rs build for `pallet-revive-uapi` by fixing a writing attribute in the manifest (we were using `default-target` instead of `targets`) + - Removed the macros defining host functions because the cfg attributes introduced in #6866 won't work on them + - Added an docs.rs specific attribute so that the `unstable-hostfn` feature tag will show up on the functions that are guarded behind it. +crates: +- name: pallet-contracts-uapi + bump: major +- name: pallet-revive-uapi + bump: major +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive-proc-macro + bump: major diff --git a/prdoc/pr_6908.prdoc b/prdoc/pr_6908.prdoc new file mode 100644 index 000000000000..0be9e613f88a --- /dev/null +++ b/prdoc/pr_6908.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] implement the ref_time_left API' +doc: +- audience: Runtime Dev + description: This PR implements the ref_time_left API method. Solidity knows only + a single "gas" dimension; Solidity contracts will use this to query the gas left. +crates: +- name: pallet-revive-fixtures + bump: minor +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_6917.prdoc b/prdoc/pr_6917.prdoc new file mode 100644 index 000000000000..dd7f59b95126 --- /dev/null +++ b/prdoc/pr_6917.prdoc @@ -0,0 +1,14 @@ +title: Remove unused dependencies from pallet_revive +doc: +- audience: Runtime Dev + description: Removing apparently unused dependencies from `pallet_revive` and related + crates. +crates: +- name: pallet-revive + bump: major +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive-mock-network + bump: major +- name: pallet-revive-eth-rpc + bump: major diff --git a/prdoc/pr_6920.prdoc b/prdoc/pr_6920.prdoc new file mode 100644 index 000000000000..d80a77e0a71f --- /dev/null +++ b/prdoc/pr_6920.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] change some getter APIs to return value in register' +doc: +- audience: Runtime Dev + description: Call data, return data and code sizes can never exceed `u32::MAX`; + they are also not generic. Hence we know that they are guaranteed to always fit + into a 64bit register and `revive` can just zero extend them into a 256bit integer + value. Which is slightly more efficient than passing them on the stack. +crates: +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive + bump: major +- name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6923.prdoc b/prdoc/pr_6923.prdoc new file mode 100644 index 000000000000..5d88d7158e7f --- /dev/null +++ b/prdoc/pr_6923.prdoc @@ -0,0 +1,12 @@ +title: 'omni-node: Tolerate failing metadata check' +doc: +- audience: Node Operator + description: |- + #6450 introduced metadata checks. Supported are metadata v14 and higher. + + However, of course old chain-specs have a genesis code blob that might be on older version. This needs to be tolerated. We should just skip the checks in that case. + + Fixes #6921 +crates: +- name: polkadot-omni-node-lib + bump: patch diff --git a/prdoc/pr_6926.prdoc b/prdoc/pr_6926.prdoc new file mode 100644 index 000000000000..788d6c110873 --- /dev/null +++ b/prdoc/pr_6926.prdoc @@ -0,0 +1,13 @@ +title: '[pallet-revive] implement the gas limit API' +doc: +- audience: Runtime Dev + description: This PR implements the gas limit API, returning the maximum ref_time + per block. Solidity contracts only know a single weight dimension and can use + this method to get the block ref_time limit. +crates: +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive + bump: major +- name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6928.prdoc b/prdoc/pr_6928.prdoc new file mode 100644 index 000000000000..4b9023ab03a6 --- /dev/null +++ b/prdoc/pr_6928.prdoc @@ -0,0 +1,34 @@ +title: '[Backport] Version bumps and `prdocs` reordering form 2412' +doc: +- audience: Runtime Dev + description: This PR includes backport of the regular version bumps and `prdocs` + reordering from the `stable2412` branch back ro master +crates: +- name: polkadot-node-primitives + bump: none +- name: asset-hub-rococo-runtime + bump: none +- name: bridge-hub-rococo-runtime + bump: none +- name: bridge-hub-westend-runtime + bump: none +- name: collectives-westend-runtime + bump: none +- name: contracts-rococo-runtime + bump: none +- name: coretime-rococo-runtime + bump: none +- name: coretime-westend-runtime + bump: none +- name: glutton-westend-runtime + bump: none +- name: people-rococo-runtime + bump: none +- name: people-westend-runtime + bump: none +- name: rococo-runtime + bump: none +- name: westend-runtime + bump: none +- name: asset-hub-westend-runtime + bump: none diff --git a/prdoc/pr_6937.prdoc b/prdoc/pr_6937.prdoc new file mode 100644 index 000000000000..5c6806df0b5c --- /dev/null +++ b/prdoc/pr_6937.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] bump polkavm to 0.18' +doc: +- audience: Runtime Dev + description: Update to the latest polkavm version, containing a linker fix I need + for revive. +crates: +- name: pallet-revive + bump: patch +- name: pallet-revive-fixtures + bump: patch +- name: pallet-revive-uapi + bump: patch diff --git a/prdoc/pr_6954.prdoc b/prdoc/pr_6954.prdoc new file mode 100644 index 000000000000..8e8faf5fffd2 --- /dev/null +++ b/prdoc/pr_6954.prdoc @@ -0,0 +1,13 @@ +title: '[pallet-revive] implement the gas price API' +doc: +- audience: Runtime Dev + description: This PR implements the EVM gas price syscall API method. Currently + this is a compile time constant in revive, but in the EVM it is an opcode. Thus + we should provide an opcode for this in the pallet. +crates: +- name: pallet-revive-fixtures + bump: minor +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_6963.prdoc b/prdoc/pr_6963.prdoc new file mode 100644 index 000000000000..7657349277b3 --- /dev/null +++ b/prdoc/pr_6963.prdoc @@ -0,0 +1,10 @@ +title: 'grandpa: Ensure `WarpProof` stays in its limits' +doc: +- audience: Node Dev + description: |- + There was the chance that a `WarpProof` was bigger than the maximum warp sync proof size. This could have happened when inserting the last justification, which then may pushed the total proof size above the maximum. The solution is simply to ensure that the last justfication also fits into the limits. + + Close: https://github.com/paritytech/polkadot-sdk/issues/6957 +crates: +- name: sc-consensus-grandpa + bump: patch diff --git a/prdoc/pr_6964.prdoc b/prdoc/pr_6964.prdoc new file mode 100644 index 000000000000..3a88fa72e963 --- /dev/null +++ b/prdoc/pr_6964.prdoc @@ -0,0 +1,15 @@ +title: '[pallet-revive] implement the base fee API' +doc: +- audience: Runtime Dev + description: This PR implements the base fee syscall API method. Currently this + is implemented as a compile time constant in the revive compiler, returning 0. + However, since this is an opocde, if we ever need to implement it for compatibility + reasons with [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md), + it would break already deployed contracts. Thus we provide a syscall method instead. +crates: +- name: pallet-revive-fixtures + bump: minor +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_6979.prdoc b/prdoc/pr_6979.prdoc new file mode 100644 index 000000000000..fae7feeec2df --- /dev/null +++ b/prdoc/pr_6979.prdoc @@ -0,0 +1,8 @@ +title: Update prometheus binding failure logging format +doc: +- audience: Node Dev + description: |- + Using `{:#?}` for the error details is a bit annoying, this change makes a more consistent formatting style for error messages. +crates: +- name: substrate-prometheus-endpoint + bump: patch diff --git a/prdoc/pr_6989.prdoc b/prdoc/pr_6989.prdoc new file mode 100644 index 000000000000..86c56698d41e --- /dev/null +++ b/prdoc/pr_6989.prdoc @@ -0,0 +1,10 @@ +title: 'paras-registrar: Improve error reporting' +doc: +- audience: Runtime User + description: |- + This pr improves the error reporting by paras registrar when an owner wants to access a locked parachain. + + Closes: https://github.com/paritytech/polkadot-sdk/issues/6745 +crates: +- name: polkadot-runtime-common + bump: patch diff --git a/prdoc/pr_7005.prdoc b/prdoc/pr_7005.prdoc new file mode 100644 index 000000000000..a61f7c5b9b71 --- /dev/null +++ b/prdoc/pr_7005.prdoc @@ -0,0 +1,7 @@ +title: Log peerset set ID -> protocol name mapping +doc: +- audience: Node Dev + description: To simplify debugging of peerset related issues like https://github.com/paritytech/polkadot-sdk/issues/6573#issuecomment-2563091343. +crates: +- name: sc-network + bump: patch diff --git a/prdoc/pr_7011.prdoc b/prdoc/pr_7011.prdoc new file mode 100644 index 000000000000..55fe0c73ca09 --- /dev/null +++ b/prdoc/pr_7011.prdoc @@ -0,0 +1,16 @@ +title: 'sync: Send already connected peers to new subscribers' +doc: +- audience: Node Dev + description: |- + Introduce `SyncEvent::InitialPeers` message sent to new subscribers to allow them correctly tracking sync peers. This resolves a race condition described in https://github.com/paritytech/polkadot-sdk/issues/6573#issuecomment-2563091343. + + Fixes https://github.com/paritytech/polkadot-sdk/issues/6573. +crates: +- name: sc-network-gossip + bump: major +- name: sc-network-statement + bump: patch +- name: sc-network-sync + bump: major +- name: sc-network-transactions + bump: patch diff --git a/prdoc/pr_7013.prdoc b/prdoc/pr_7013.prdoc new file mode 100644 index 000000000000..138fa7f23102 --- /dev/null +++ b/prdoc/pr_7013.prdoc @@ -0,0 +1,7 @@ +title: 'pallet-bounties: Fix benchmarks for 0 ED' +doc: +- audience: Runtime Dev + description: 'Closes: https://github.com/paritytech/polkadot-sdk/issues/7009' +crates: +- name: pallet-bounties + bump: patch diff --git a/prdoc/pr_3151.prdoc b/prdoc/stable2412/pr_3151.prdoc similarity index 100% rename from prdoc/pr_3151.prdoc rename to prdoc/stable2412/pr_3151.prdoc diff --git a/prdoc/pr_3685.prdoc b/prdoc/stable2412/pr_3685.prdoc similarity index 100% rename from prdoc/pr_3685.prdoc rename to prdoc/stable2412/pr_3685.prdoc diff --git a/prdoc/pr_3881.prdoc b/prdoc/stable2412/pr_3881.prdoc similarity index 100% rename from prdoc/pr_3881.prdoc rename to prdoc/stable2412/pr_3881.prdoc diff --git a/prdoc/pr_3970.prdoc b/prdoc/stable2412/pr_3970.prdoc similarity index 100% rename from prdoc/pr_3970.prdoc rename to prdoc/stable2412/pr_3970.prdoc diff --git a/prdoc/stable2412/pr_4012.prdoc b/prdoc/stable2412/pr_4012.prdoc new file mode 100644 index 000000000000..3a53e31a7fc6 --- /dev/null +++ b/prdoc/stable2412/pr_4012.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: "`impl_runtime_apis!`: replace the use of `Self` with `Runtime`" + +doc: + - audience: Runtime Dev + description: | + Currently, if there is a type alias similar to `type HeaderFor` in the scope, it makes sense to expect that + `HeaderFor` and `HeaderFor` are equivalent. However, this is not the case. It currently leads to + a compilation error that `Self is not in scope`, which is confusing. This PR introduces a visitor, similar to + `CheckTraitDecl` in `decl_runtime_apis!`, `ReplaceSelfImpl`. It identifies usage of `Self` as a type argument in + `impl_runtime_apis!` and replaces `Self` with an explicit `Runtime` type. + + For example, the following example code will be transformed before expansion: + ```rust + impl apis::Core for Runtime { + fn initialize_block(header: &HeaderFor) -> ExtrinsicInclusionMode { + let _: HeaderFor = header.clone(); + RuntimeExecutive::initialize_block(header) + } + } + ``` + Instead, it will be passed to macro as: + ```rust + impl apis::Core for Runtime { + fn initialize_block(header: &HeaderFor) -> ExtrinsicInclusionMode { + let _: HeaderFor = header.clone(); + RuntimeExecutive::initialize_block(header) + } + } + ``` +crates: + - name: sp-api + bump: none + - name: sp-api-proc-macro + bump: none \ No newline at end of file diff --git a/prdoc/pr_4251.prdoc b/prdoc/stable2412/pr_4251.prdoc similarity index 100% rename from prdoc/pr_4251.prdoc rename to prdoc/stable2412/pr_4251.prdoc diff --git a/prdoc/pr_4257.prdoc b/prdoc/stable2412/pr_4257.prdoc similarity index 100% rename from prdoc/pr_4257.prdoc rename to prdoc/stable2412/pr_4257.prdoc diff --git a/prdoc/pr_4639.prdoc b/prdoc/stable2412/pr_4639.prdoc similarity index 100% rename from prdoc/pr_4639.prdoc rename to prdoc/stable2412/pr_4639.prdoc diff --git a/prdoc/stable2412/pr_4826.prdoc b/prdoc/stable2412/pr_4826.prdoc new file mode 100644 index 000000000000..daa4a77e3e8f --- /dev/null +++ b/prdoc/stable2412/pr_4826.prdoc @@ -0,0 +1,69 @@ +# 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: XCMv5 + +doc: + - audience: [Runtime User, Runtime Dev] + description: | + Added XCMv5. + + This PR brings a new XCM version. + It's an amalgamation of multiple individual PRs: + - https://github.com/paritytech/polkadot-sdk/pull/6228 + - https://github.com/paritytech/polkadot-sdk/pull/6148 + - https://github.com/paritytech/polkadot-sdk/pull/5971 + - https://github.com/paritytech/polkadot-sdk/pull/5876 + - https://github.com/paritytech/polkadot-sdk/pull/5420 + - https://github.com/paritytech/polkadot-sdk/pull/5585 + + XCMv5 reduces the potential for bugs by: + - Removing the need to specify weight in Transact. + - Handling fees in a better way with `PayFees` instead of `BuyExecution`. + - Improves asset claiming with `SetAssetClaimer`. + + It also allows some new use-cases like: + - Sending both teleported and reserve asset transferred assets in the same cross-chain + transfer. + - Preserving the origin when doing cross-chain transfers. Allowing the use of Transact + in the same message as a cross-chain transfer. + + In version 5, it's expected to change usage of `BuyExecution` to `PayFees`. + While `BuyExecution` returns all leftover assets to holding, `PayFees` doesn't. + The only way to get funds back from those sent to `PayFees` is by using `RefundSurplus`. + Because of this, it's meant to be used alongside the new DryRunApi and XcmPaymentApi. + You first dry-run the XCM, get the fees needed, and put them in `PayFees`. + +crates: + - name: staging-xcm + bump: major + - name: staging-xcm-builder + bump: major + - name: staging-xcm-executor + bump: major + - 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: 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: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-xcm-benchmarks + bump: minor + - name: pallet-multisig + bump: minor diff --git a/prdoc/stable2412/pr_4834.prdoc b/prdoc/stable2412/pr_4834.prdoc new file mode 100644 index 000000000000..b7c8b15cb073 --- /dev/null +++ b/prdoc/stable2412/pr_4834.prdoc @@ -0,0 +1,15 @@ +title: "xcm-executor: take delivery fee from transferred assets if necessary" + +doc: + - audience: Runtime Dev + description: | + In asset transfers, as a last resort, XCM delivery fees are taken from + transferred assets rather than failing the transfer. + +crates: + - name: staging-xcm-executor + bump: patch + - name: snowbridge-router-primitives + bump: patch + - name: snowbridge-pallet-inbound-queue + bump: patch diff --git a/prdoc/pr_4837.prdoc b/prdoc/stable2412/pr_4837.prdoc similarity index 100% rename from prdoc/pr_4837.prdoc rename to prdoc/stable2412/pr_4837.prdoc diff --git a/prdoc/pr_4846.prdoc b/prdoc/stable2412/pr_4846.prdoc similarity index 100% rename from prdoc/pr_4846.prdoc rename to prdoc/stable2412/pr_4846.prdoc diff --git a/prdoc/pr_4849.prdoc b/prdoc/stable2412/pr_4849.prdoc similarity index 100% rename from prdoc/pr_4849.prdoc rename to prdoc/stable2412/pr_4849.prdoc diff --git a/prdoc/pr_4851.prdoc b/prdoc/stable2412/pr_4851.prdoc similarity index 100% rename from prdoc/pr_4851.prdoc rename to prdoc/stable2412/pr_4851.prdoc diff --git a/prdoc/pr_4889.prdoc b/prdoc/stable2412/pr_4889.prdoc similarity index 100% rename from prdoc/pr_4889.prdoc rename to prdoc/stable2412/pr_4889.prdoc diff --git a/prdoc/pr_4974.prdoc b/prdoc/stable2412/pr_4974.prdoc similarity index 100% rename from prdoc/pr_4974.prdoc rename to prdoc/stable2412/pr_4974.prdoc diff --git a/prdoc/pr_4982.prdoc b/prdoc/stable2412/pr_4982.prdoc similarity index 100% rename from prdoc/pr_4982.prdoc rename to prdoc/stable2412/pr_4982.prdoc diff --git a/prdoc/pr_5038.prdoc b/prdoc/stable2412/pr_5038.prdoc similarity index 100% rename from prdoc/pr_5038.prdoc rename to prdoc/stable2412/pr_5038.prdoc diff --git a/prdoc/pr_5194.prdoc b/prdoc/stable2412/pr_5194.prdoc similarity index 100% rename from prdoc/pr_5194.prdoc rename to prdoc/stable2412/pr_5194.prdoc diff --git a/prdoc/pr_5198.prdoc b/prdoc/stable2412/pr_5198.prdoc similarity index 100% rename from prdoc/pr_5198.prdoc rename to prdoc/stable2412/pr_5198.prdoc diff --git a/prdoc/pr_5201.prdoc b/prdoc/stable2412/pr_5201.prdoc similarity index 100% rename from prdoc/pr_5201.prdoc rename to prdoc/stable2412/pr_5201.prdoc diff --git a/prdoc/pr_5274.prdoc b/prdoc/stable2412/pr_5274.prdoc similarity index 100% rename from prdoc/pr_5274.prdoc rename to prdoc/stable2412/pr_5274.prdoc diff --git a/prdoc/stable2412/pr_5311.prdoc b/prdoc/stable2412/pr_5311.prdoc new file mode 100644 index 000000000000..07affa5cb2ee --- /dev/null +++ b/prdoc/stable2412/pr_5311.prdoc @@ -0,0 +1,16 @@ +title: No-op Impl Polling Trait + +doc: + - audience: Runtime Dev + description: | + Provide a NoOp implementation of the Polling trait for unit where the trait is defined and skiping benchmarks that necessitate it's definition. + +crates: + - name: pallet-core-fellowship + bump: minor + - name: pallet-ranked-collective + bump: minor + - name: pallet-salary + bump: minor + - name: frame-support + bump: minor diff --git a/prdoc/pr_5322.prdoc b/prdoc/stable2412/pr_5322.prdoc similarity index 100% rename from prdoc/pr_5322.prdoc rename to prdoc/stable2412/pr_5322.prdoc diff --git a/prdoc/pr_5343.prdoc b/prdoc/stable2412/pr_5343.prdoc similarity index 100% rename from prdoc/pr_5343.prdoc rename to prdoc/stable2412/pr_5343.prdoc diff --git a/prdoc/pr_5372.prdoc b/prdoc/stable2412/pr_5372.prdoc similarity index 100% rename from prdoc/pr_5372.prdoc rename to prdoc/stable2412/pr_5372.prdoc diff --git a/prdoc/stable2412/pr_5390.prdoc b/prdoc/stable2412/pr_5390.prdoc new file mode 100644 index 000000000000..cfe6894324aa --- /dev/null +++ b/prdoc/stable2412/pr_5390.prdoc @@ -0,0 +1,55 @@ +# 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 NetworkIds for testnets Rococo and Westend + +doc: + - audience: [Runtime Dev, Runtime User] + description: | + Implemetation of https://github.com/polkadot-fellows/RFCs/pull/108, in the version 5 of XCM, + Remove `Westend` and `Rococo` from the included `NetworkId`s to improve the stability of the language. + + `NetworkId::Rococo` and `NetworkId::Westend` can just use `NetworkId::ByGenesis` by importing their genesis + block hash + +crates: + - name: staging-xcm + bump: major + - name: pallet-xcm-bridge-hub + bump: patch + - name: snowbridge-pallet-system + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: contracts-rococo-runtime + bump: patch + - name: coretime-rococo-runtime + bump: patch + - name: coretime-westend-runtime + bump: patch + - name: glutton-westend-runtime + bump: patch + - name: people-rococo-runtime + bump: patch + - name: people-westend-runtime + bump: patch + - name: penpal-runtime + bump: patch + - name: rococo-parachain-runtime + bump: patch + - name: xcm-runtime-apis + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: assets-common + bump: patch diff --git a/prdoc/stable2412/pr_5420.prdoc b/prdoc/stable2412/pr_5420.prdoc new file mode 100644 index 000000000000..bf8a34569077 --- /dev/null +++ b/prdoc/stable2412/pr_5420.prdoc @@ -0,0 +1,62 @@ +# 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: XCMv5 - Better fee mechanism + +doc: + - audience: + - Runtime User + - Runtime Dev + description: | + In XCMv5, there's a new instruction, `PayFees`, which is meant to be a replacement for `BuyExecution`. + This instruction takes only one parameter, the `asset` that you are willing to use for fee payment. + There's no parameter for limiting the weight, the amount of the `asset` you put in is the limit of + how much you're willing to pay. + This instruction works much better with delivery fees. + `BuyExecution` will still be around to ensure backwards-compatibility, however, the benefits of the new + instruction are a good incentive to switch. + The proposed workflow is to estimate fees using the `XcmPaymentApi` and `DryRunApi`, then to put those + values in `PayFees` and watch your message go knowing you covered all the necessary fees. + You can add a little bit more just in case if you want. + `RefundSurplus` now gets back all of the assets that were destined for fee payment so you can deposit + them somewhere. + BEWARE, make sure you're not sending any other message after you call `RefundSurplus`, if not, it will + error. + +crates: + - name: staging-xcm-executor + bump: minor + - name: staging-xcm-builder + bump: minor + - name: staging-xcm + bump: major + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: xcm-emulator + bump: major + - name: people-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: bridge-hub-westend-runtime + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: emulated-integration-tests-common + bump: minor + - name: xcm-procedural + bump: minor + - name: pallet-xcm-benchmarks + bump: minor + - name: snowbridge-pallet-system + bump: patch diff --git a/prdoc/pr_5423.prdoc b/prdoc/stable2412/pr_5423.prdoc similarity index 100% rename from prdoc/pr_5423.prdoc rename to prdoc/stable2412/pr_5423.prdoc diff --git a/prdoc/pr_5435.prdoc b/prdoc/stable2412/pr_5435.prdoc similarity index 100% rename from prdoc/pr_5435.prdoc rename to prdoc/stable2412/pr_5435.prdoc diff --git a/prdoc/pr_5461.prdoc b/prdoc/stable2412/pr_5461.prdoc similarity index 100% rename from prdoc/pr_5461.prdoc rename to prdoc/stable2412/pr_5461.prdoc diff --git a/prdoc/pr_5469.prdoc b/prdoc/stable2412/pr_5469.prdoc similarity index 100% rename from prdoc/pr_5469.prdoc rename to prdoc/stable2412/pr_5469.prdoc diff --git a/prdoc/pr_5502.prdoc b/prdoc/stable2412/pr_5502.prdoc similarity index 100% rename from prdoc/pr_5502.prdoc rename to prdoc/stable2412/pr_5502.prdoc diff --git a/prdoc/pr_5515.prdoc b/prdoc/stable2412/pr_5515.prdoc similarity index 100% rename from prdoc/pr_5515.prdoc rename to prdoc/stable2412/pr_5515.prdoc diff --git a/prdoc/pr_5521.prdoc b/prdoc/stable2412/pr_5521.prdoc similarity index 100% rename from prdoc/pr_5521.prdoc rename to prdoc/stable2412/pr_5521.prdoc diff --git a/prdoc/pr_5526.prdoc b/prdoc/stable2412/pr_5526.prdoc similarity index 100% rename from prdoc/pr_5526.prdoc rename to prdoc/stable2412/pr_5526.prdoc diff --git a/prdoc/pr_5540.prdoc b/prdoc/stable2412/pr_5540.prdoc similarity index 100% rename from prdoc/pr_5540.prdoc rename to prdoc/stable2412/pr_5540.prdoc diff --git a/prdoc/pr_5548.prdoc b/prdoc/stable2412/pr_5548.prdoc similarity index 100% rename from prdoc/pr_5548.prdoc rename to prdoc/stable2412/pr_5548.prdoc diff --git a/prdoc/pr_5554.prdoc b/prdoc/stable2412/pr_5554.prdoc similarity index 100% rename from prdoc/pr_5554.prdoc rename to prdoc/stable2412/pr_5554.prdoc diff --git a/prdoc/pr_5555.prdoc b/prdoc/stable2412/pr_5555.prdoc similarity index 100% rename from prdoc/pr_5555.prdoc rename to prdoc/stable2412/pr_5555.prdoc diff --git a/prdoc/pr_5556.prdoc b/prdoc/stable2412/pr_5556.prdoc similarity index 100% rename from prdoc/pr_5556.prdoc rename to prdoc/stable2412/pr_5556.prdoc diff --git a/prdoc/pr_5572.prdoc b/prdoc/stable2412/pr_5572.prdoc similarity index 100% rename from prdoc/pr_5572.prdoc rename to prdoc/stable2412/pr_5572.prdoc diff --git a/prdoc/stable2412/pr_5585.prdoc b/prdoc/stable2412/pr_5585.prdoc new file mode 100644 index 000000000000..d4b115413d4d --- /dev/null +++ b/prdoc/stable2412/pr_5585.prdoc @@ -0,0 +1,47 @@ +# 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: Added SetAssetClaimer instruction to XCM v5. + +doc: + - audience: Runtime Dev + description: | + Added SetAssetClaimer implementation to XCM v5. With asset_claimer set users can retrieve their trapped assets + at any point in time without the need to go through OpenGov reclaim process. + +crates: +- name: bridge-hub-westend-emulated-chain + bump: minor +- name: asset-hub-westend-integration-tests + bump: minor +- 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: 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: rococo-runtime + bump: minor +- name: westend-runtime + bump: minor +- name: staging-xcm + bump: minor +- name: staging-xcm-executor + bump: minor +- name: pallet-xcm-benchmarks + bump: minor +- name: pallet-multisig + bump: minor + diff --git a/prdoc/pr_5592.prdoc b/prdoc/stable2412/pr_5592.prdoc similarity index 100% rename from prdoc/pr_5592.prdoc rename to prdoc/stable2412/pr_5592.prdoc diff --git a/prdoc/pr_5601.prdoc b/prdoc/stable2412/pr_5601.prdoc similarity index 100% rename from prdoc/pr_5601.prdoc rename to prdoc/stable2412/pr_5601.prdoc diff --git a/prdoc/pr_5606.prdoc b/prdoc/stable2412/pr_5606.prdoc similarity index 100% rename from prdoc/pr_5606.prdoc rename to prdoc/stable2412/pr_5606.prdoc diff --git a/prdoc/pr_5608.prdoc b/prdoc/stable2412/pr_5608.prdoc similarity index 100% rename from prdoc/pr_5608.prdoc rename to prdoc/stable2412/pr_5608.prdoc diff --git a/prdoc/pr_5609.prdoc b/prdoc/stable2412/pr_5609.prdoc similarity index 100% rename from prdoc/pr_5609.prdoc rename to prdoc/stable2412/pr_5609.prdoc diff --git a/prdoc/stable2412/pr_5616.prdoc b/prdoc/stable2412/pr_5616.prdoc new file mode 100644 index 000000000000..16d81c291c30 --- /dev/null +++ b/prdoc/stable2412/pr_5616.prdoc @@ -0,0 +1,25 @@ +# 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: "PVF: drop backing jobs if it is too late" + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + Introduces the removal of backing jobs that have been back pressured for longer than `allowedAncestryLen`, as these candidates are no longer viable. + +crates: + - name: polkadot-overseer + bump: major + - name: polkadot-node-core-pvf + bump: major + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-node-core-approval-voting + bump: patch + - name: polkadot-node-core-backing + bump: patch + - name: polkadot-node-core-candidate-validation + bump: patch + - name: polkadot-node-core-dispute-coordinator + bump: patch diff --git a/prdoc/pr_5623.prdoc b/prdoc/stable2412/pr_5623.prdoc similarity index 100% rename from prdoc/pr_5623.prdoc rename to prdoc/stable2412/pr_5623.prdoc diff --git a/prdoc/pr_5630.prdoc b/prdoc/stable2412/pr_5630.prdoc similarity index 100% rename from prdoc/pr_5630.prdoc rename to prdoc/stable2412/pr_5630.prdoc diff --git a/prdoc/pr_5635.prdoc b/prdoc/stable2412/pr_5635.prdoc similarity index 100% rename from prdoc/pr_5635.prdoc rename to prdoc/stable2412/pr_5635.prdoc diff --git a/prdoc/pr_5640.prdoc b/prdoc/stable2412/pr_5640.prdoc similarity index 100% rename from prdoc/pr_5640.prdoc rename to prdoc/stable2412/pr_5640.prdoc diff --git a/prdoc/pr_5664.prdoc b/prdoc/stable2412/pr_5664.prdoc similarity index 100% rename from prdoc/pr_5664.prdoc rename to prdoc/stable2412/pr_5664.prdoc diff --git a/prdoc/pr_5665.prdoc b/prdoc/stable2412/pr_5665.prdoc similarity index 100% rename from prdoc/pr_5665.prdoc rename to prdoc/stable2412/pr_5665.prdoc diff --git a/prdoc/pr_5666.prdoc b/prdoc/stable2412/pr_5666.prdoc similarity index 100% rename from prdoc/pr_5666.prdoc rename to prdoc/stable2412/pr_5666.prdoc diff --git a/prdoc/pr_5675.prdoc b/prdoc/stable2412/pr_5675.prdoc similarity index 100% rename from prdoc/pr_5675.prdoc rename to prdoc/stable2412/pr_5675.prdoc diff --git a/prdoc/pr_5676.prdoc b/prdoc/stable2412/pr_5676.prdoc similarity index 100% rename from prdoc/pr_5676.prdoc rename to prdoc/stable2412/pr_5676.prdoc diff --git a/prdoc/pr_5679.prdoc b/prdoc/stable2412/pr_5679.prdoc similarity index 100% rename from prdoc/pr_5679.prdoc rename to prdoc/stable2412/pr_5679.prdoc diff --git a/prdoc/pr_5682.prdoc b/prdoc/stable2412/pr_5682.prdoc similarity index 100% rename from prdoc/pr_5682.prdoc rename to prdoc/stable2412/pr_5682.prdoc diff --git a/prdoc/pr_5684.prdoc b/prdoc/stable2412/pr_5684.prdoc similarity index 100% rename from prdoc/pr_5684.prdoc rename to prdoc/stable2412/pr_5684.prdoc diff --git a/prdoc/pr_5686.prdoc b/prdoc/stable2412/pr_5686.prdoc similarity index 100% rename from prdoc/pr_5686.prdoc rename to prdoc/stable2412/pr_5686.prdoc diff --git a/prdoc/pr_5687.prdoc b/prdoc/stable2412/pr_5687.prdoc similarity index 100% rename from prdoc/pr_5687.prdoc rename to prdoc/stable2412/pr_5687.prdoc diff --git a/prdoc/stable2412/pr_5693.prdoc b/prdoc/stable2412/pr_5693.prdoc new file mode 100644 index 000000000000..d8afae7ba0bc --- /dev/null +++ b/prdoc/stable2412/pr_5693.prdoc @@ -0,0 +1,84 @@ +title: Remove `sp_runtime::RuntimeString` and replace with `Cow<'static, str>` or + `String` depending on use case +doc: + - audience: Runtime Dev + description: | + Deprecate `RuntimeString`, replace with `String` or `Cow<'static, str>` where appropriate. + + For downstream projects the upgrade will primarily consist of following two changes: + ```diff + #[sp_version::runtime_version] + pub const VERSION: RuntimeVersion = RuntimeVersion { + - spec_name: create_runtime_str!("statemine"), + - impl_name: create_runtime_str!("statemine"), + + spec_name: alloc::borrow::Cow::Borrowed("statemine"), + + impl_name: alloc::borrow::Cow::Borrowed("statemine"), + ``` + ```diff + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + - ) -> Result, sp_runtime::RuntimeString> { + + ) -> Result, alloc::string::String> { + ``` + SCALE encoding/decoding remains the same as before, but serde encoding in runtime has changed from bytes to string (it was like this in `std` environment already). +crates: +- name: cumulus-client-network + bump: major +- name: cumulus-client-pov-recovery + bump: major +- name: cumulus-pallet-parachain-system + bump: major +- name: asset-hub-rococo-runtime + bump: major +- name: asset-hub-westend-runtime + bump: major +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: major +- name: collectives-westend-runtime + bump: major +- name: contracts-rococo-runtime + bump: major +- name: coretime-rococo-runtime + bump: major +- name: coretime-westend-runtime + bump: major +- name: glutton-westend-runtime + bump: major +- name: people-rococo-runtime + bump: major +- name: people-westend-runtime + bump: major +- name: penpal-runtime + bump: major +- name: rococo-parachain-runtime + bump: major +- name: rococo-runtime + bump: major +- name: westend-runtime + bump: major +- name: staging-chain-spec-builder + bump: major +- name: sc-consensus-pow + bump: major +- name: sc-executor + bump: major +- name: frame-benchmarking + bump: major +- name: polkadot-sdk-frame + bump: major +- name: frame-support + bump: major +- name: frame-system + bump: major +- name: sp-api + bump: major +- name: sp-genesis-builder + bump: major +- name: sp-runtime + bump: major +- name: sp-version-proc-macro + bump: major +- name: sp-version + bump: major diff --git a/prdoc/pr_5701.prdoc b/prdoc/stable2412/pr_5701.prdoc similarity index 100% rename from prdoc/pr_5701.prdoc rename to prdoc/stable2412/pr_5701.prdoc diff --git a/prdoc/pr_5707.prdoc b/prdoc/stable2412/pr_5707.prdoc similarity index 100% rename from prdoc/pr_5707.prdoc rename to prdoc/stable2412/pr_5707.prdoc diff --git a/prdoc/pr_5716.prdoc b/prdoc/stable2412/pr_5716.prdoc similarity index 100% rename from prdoc/pr_5716.prdoc rename to prdoc/stable2412/pr_5716.prdoc diff --git a/prdoc/pr_5726.prdoc b/prdoc/stable2412/pr_5726.prdoc similarity index 100% rename from prdoc/pr_5726.prdoc rename to prdoc/stable2412/pr_5726.prdoc diff --git a/prdoc/stable2412/pr_5732.prdoc b/prdoc/stable2412/pr_5732.prdoc new file mode 100644 index 000000000000..6f3f9b8a1668 --- /dev/null +++ b/prdoc/stable2412/pr_5732.prdoc @@ -0,0 +1,29 @@ +title: Expose the unstable metadata v16 +doc: +- audience: Node Dev + description: | + This PR exposes the *unstable* metadata V16. The metadata is exposed under the unstable u32::MAX number. + Developers can start experimenting with the new features of the metadata v16. *Please note that this metadata is under development and expect breaking changes until stabilization.* + The `ExtrinsicMetadata` trait receives a breaking change. Its associated type `VERSION` is rename to `VERSIONS` and now supports a constant static list of metadata versions. + The versions implemented for `UncheckedExtrinsic` are v4 (legacy version) and v5 (new version). + For metadata collection, it is assumed that all `TransactionExtensions` are under version 0. + +crates: + - name: sp-metadata-ir + bump: major + - name: frame-support-procedural + bump: patch + - name: frame-support + bump: minor + - name: frame-support-test + bump: major + - name: frame-metadata-hash-extension + bump: patch + - name: substrate-wasm-builder + bump: minor + - name: pallet-revive + bump: minor + - name: sp-runtime + bump: major + - name: frame-benchmarking-cli + bump: patch diff --git a/prdoc/stable2412/pr_5737.prdoc b/prdoc/stable2412/pr_5737.prdoc new file mode 100644 index 000000000000..a122e4574a9c --- /dev/null +++ b/prdoc/stable2412/pr_5737.prdoc @@ -0,0 +1,25 @@ +title: Make syncing service an argument of `build_network` + +doc: + - audience: Node Dev + description: | + `build_network` is accompanied with lower-level `build_network_advanced` with simpler API that does not create + syncing engine internally, but instead takes a handle to syncing service as an argument. In most cases typical + syncing engine with polkadot syncing strategy and default block downloader can be created with newly introduced + `sc_service::build_default_syncing_engine()` function, but lower-level `build_default_block_downloader` also + exists for those needing more customization. + + These changes allow developers higher than ever control over syncing implementation, but `build_network` is still + available for easier high-level usage. + +crates: + - name: cumulus-client-service + bump: patch + - name: polkadot-service + bump: patch + - name: sc-consensus + bump: major + - name: sc-service + bump: major + - name: sc-network-sync + bump: major diff --git a/prdoc/pr_5741.prdoc b/prdoc/stable2412/pr_5741.prdoc similarity index 100% rename from prdoc/pr_5741.prdoc rename to prdoc/stable2412/pr_5741.prdoc diff --git a/prdoc/pr_5743.prdoc b/prdoc/stable2412/pr_5743.prdoc similarity index 100% rename from prdoc/pr_5743.prdoc rename to prdoc/stable2412/pr_5743.prdoc diff --git a/prdoc/pr_5745.prdoc b/prdoc/stable2412/pr_5745.prdoc similarity index 100% rename from prdoc/pr_5745.prdoc rename to prdoc/stable2412/pr_5745.prdoc diff --git a/prdoc/pr_5756.prdoc b/prdoc/stable2412/pr_5756.prdoc similarity index 100% rename from prdoc/pr_5756.prdoc rename to prdoc/stable2412/pr_5756.prdoc diff --git a/prdoc/pr_5762.prdoc b/prdoc/stable2412/pr_5762.prdoc similarity index 100% rename from prdoc/pr_5762.prdoc rename to prdoc/stable2412/pr_5762.prdoc diff --git a/prdoc/pr_5765.prdoc b/prdoc/stable2412/pr_5765.prdoc similarity index 100% rename from prdoc/pr_5765.prdoc rename to prdoc/stable2412/pr_5765.prdoc diff --git a/prdoc/pr_5768.prdoc b/prdoc/stable2412/pr_5768.prdoc similarity index 100% rename from prdoc/pr_5768.prdoc rename to prdoc/stable2412/pr_5768.prdoc diff --git a/prdoc/pr_5774.prdoc b/prdoc/stable2412/pr_5774.prdoc similarity index 100% rename from prdoc/pr_5774.prdoc rename to prdoc/stable2412/pr_5774.prdoc diff --git a/prdoc/pr_5779.prdoc b/prdoc/stable2412/pr_5779.prdoc similarity index 100% rename from prdoc/pr_5779.prdoc rename to prdoc/stable2412/pr_5779.prdoc diff --git a/prdoc/pr_5787.prdoc b/prdoc/stable2412/pr_5787.prdoc similarity index 100% rename from prdoc/pr_5787.prdoc rename to prdoc/stable2412/pr_5787.prdoc diff --git a/prdoc/pr_5789.prdoc b/prdoc/stable2412/pr_5789.prdoc similarity index 100% rename from prdoc/pr_5789.prdoc rename to prdoc/stable2412/pr_5789.prdoc diff --git a/prdoc/pr_5796.prdoc b/prdoc/stable2412/pr_5796.prdoc similarity index 100% rename from prdoc/pr_5796.prdoc rename to prdoc/stable2412/pr_5796.prdoc diff --git a/prdoc/pr_5804.prdoc b/prdoc/stable2412/pr_5804.prdoc similarity index 100% rename from prdoc/pr_5804.prdoc rename to prdoc/stable2412/pr_5804.prdoc diff --git a/prdoc/pr_5807.prdoc b/prdoc/stable2412/pr_5807.prdoc similarity index 100% rename from prdoc/pr_5807.prdoc rename to prdoc/stable2412/pr_5807.prdoc diff --git a/prdoc/pr_5811.prdoc b/prdoc/stable2412/pr_5811.prdoc similarity index 100% rename from prdoc/pr_5811.prdoc rename to prdoc/stable2412/pr_5811.prdoc diff --git a/prdoc/pr_5813.prdoc b/prdoc/stable2412/pr_5813.prdoc similarity index 100% rename from prdoc/pr_5813.prdoc rename to prdoc/stable2412/pr_5813.prdoc diff --git a/prdoc/pr_5824.prdoc b/prdoc/stable2412/pr_5824.prdoc similarity index 100% rename from prdoc/pr_5824.prdoc rename to prdoc/stable2412/pr_5824.prdoc diff --git a/prdoc/pr_5830.prdoc b/prdoc/stable2412/pr_5830.prdoc similarity index 100% rename from prdoc/pr_5830.prdoc rename to prdoc/stable2412/pr_5830.prdoc diff --git a/prdoc/pr_5838.prdoc b/prdoc/stable2412/pr_5838.prdoc similarity index 100% rename from prdoc/pr_5838.prdoc rename to prdoc/stable2412/pr_5838.prdoc diff --git a/prdoc/pr_5839.prdoc b/prdoc/stable2412/pr_5839.prdoc similarity index 100% rename from prdoc/pr_5839.prdoc rename to prdoc/stable2412/pr_5839.prdoc diff --git a/prdoc/pr_5845.prdoc b/prdoc/stable2412/pr_5845.prdoc similarity index 100% rename from prdoc/pr_5845.prdoc rename to prdoc/stable2412/pr_5845.prdoc diff --git a/prdoc/pr_5847.prdoc b/prdoc/stable2412/pr_5847.prdoc similarity index 100% rename from prdoc/pr_5847.prdoc rename to prdoc/stable2412/pr_5847.prdoc diff --git a/prdoc/pr_5856.prdoc b/prdoc/stable2412/pr_5856.prdoc similarity index 100% rename from prdoc/pr_5856.prdoc rename to prdoc/stable2412/pr_5856.prdoc diff --git a/prdoc/pr_5857.prdoc b/prdoc/stable2412/pr_5857.prdoc similarity index 100% rename from prdoc/pr_5857.prdoc rename to prdoc/stable2412/pr_5857.prdoc diff --git a/prdoc/pr_5859.prdoc b/prdoc/stable2412/pr_5859.prdoc similarity index 100% rename from prdoc/pr_5859.prdoc rename to prdoc/stable2412/pr_5859.prdoc diff --git a/prdoc/pr_5861.prdoc b/prdoc/stable2412/pr_5861.prdoc similarity index 100% rename from prdoc/pr_5861.prdoc rename to prdoc/stable2412/pr_5861.prdoc diff --git a/prdoc/pr_5866.prdoc b/prdoc/stable2412/pr_5866.prdoc similarity index 100% rename from prdoc/pr_5866.prdoc rename to prdoc/stable2412/pr_5866.prdoc diff --git a/prdoc/pr_5872.prdoc b/prdoc/stable2412/pr_5872.prdoc similarity index 100% rename from prdoc/pr_5872.prdoc rename to prdoc/stable2412/pr_5872.prdoc diff --git a/prdoc/pr_5875.prdoc b/prdoc/stable2412/pr_5875.prdoc similarity index 100% rename from prdoc/pr_5875.prdoc rename to prdoc/stable2412/pr_5875.prdoc diff --git a/prdoc/stable2412/pr_5876.prdoc b/prdoc/stable2412/pr_5876.prdoc new file mode 100644 index 000000000000..4e2b8a5c8aad --- /dev/null +++ b/prdoc/stable2412/pr_5876.prdoc @@ -0,0 +1,99 @@ +# 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: (XCMv5) implement RFC#100, add new InitiateTransfer instruction + +doc: + - audience: Runtime Dev + description: | + There's a new XCM instruction in v5: InitiateTransfer. + It's meant as a general instruction that will do everything (and more) currently + done by InitiateTeleport, InitiateReserveWithdraw and DepositReserveAsset. + Its main feature is the ability to do cross-chains transfers mixing teleported and + reserve transferred assets. + ```rust + /// Specify which type of asset transfer is required for a particular `(asset, dest)` combination. + pub enum AssetTransferFilter { + /// teleport assets matching `AssetFilter` to `dest` + Teleport(AssetFilter), + /// reserve-transfer assets matching `AssetFilter` to `dest`, using the local chain as reserve + ReserveDeposit(AssetFilter), + /// reserve-transfer assets matching `AssetFilter` to `dest`, using `dest` as reserve + ReserveWithdraw(AssetFilter), + } + /// Cross-chain transfer matching `assets` in the holding register as follows: + /// + /// Assets in the holding register are matched using the given list of `AssetTransferFilter`s, + /// they are then transferred based on their specified transfer type: + /// + /// - teleport: burn local assets and append a `ReceiveTeleportedAsset` XCM instruction to + /// the XCM program to be sent onward to the `dest` location, + /// + /// - reserve deposit: place assets under the ownership of `dest` within this consensus system + /// (i.e. its sovereign account), and append a `ReserveAssetDeposited` XCM instruction + /// to the XCM program to be sent onward to the `dest` location, + /// + /// - reserve withdraw: burn local assets and append a `WithdrawAsset` XCM instruction + /// to the XCM program to be sent onward to the `dest` location, + /// + /// The onward XCM is then appended a `ClearOrigin` to allow safe execution of any following + /// custom XCM instructions provided in `remote_xcm`. + /// + /// The onward XCM also potentially contains a `BuyExecution` instruction based on the presence + /// of the `remote_fees` parameter (see below). + /// + /// If a transfer requires going through multiple hops, an XCM program can compose this instruction + /// to be used at every chain along the path, describing that specific leg of the transfer. + /// + /// Parameters: + /// - `dest`: The location of the transfer next hop. + /// - `remote_fees`: If set to `Some(asset_xfer_filter)`, the single asset matching + /// `asset_xfer_filter` in the holding register will be transferred first in the remote XCM + /// program, followed by a `BuyExecution(fee)`, then rest of transfers follow. + /// This guarantees `remote_xcm` will successfully pass a `AllowTopLevelPaidExecutionFrom` barrier. + /// - `remote_xcm`: Custom instructions that will be executed on the `dest` chain. Note that + /// these instructions will be executed after a `ClearOrigin` so their origin will be `None`. + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + InitiateTransfer { + destination: Location, + remote_fees: Option, + assets: Vec, + remote_xcm: Xcm<()>, + } + ``` + +crates: + - name: emulated-integration-tests-common + bump: major + - 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: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: people-westend-runtime + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-xcm-benchmarks + bump: minor + - name: staging-xcm + bump: major + - name: staging-xcm-executor + bump: major diff --git a/prdoc/pr_5880.prdoc b/prdoc/stable2412/pr_5880.prdoc similarity index 100% rename from prdoc/pr_5880.prdoc rename to prdoc/stable2412/pr_5880.prdoc diff --git a/prdoc/stable2412/pr_5883.prdoc b/prdoc/stable2412/pr_5883.prdoc new file mode 100644 index 000000000000..96225a89bc99 --- /dev/null +++ b/prdoc/stable2412/pr_5883.prdoc @@ -0,0 +1,15 @@ +title: 'statement-distribution RFC103 implementation' + +doc: + - audience: Node Dev + description: | + Introduces checks for the new candidate descriptor fields: `core_index` and `session_index`. + +crates: + - name: polkadot-statement-distribution + bump: minor + - name: polkadot-primitives + bump: major + - name: polkadot-primitives-test-helpers + bump: major + diff --git a/prdoc/pr_5886.prdoc b/prdoc/stable2412/pr_5886.prdoc similarity index 100% rename from prdoc/pr_5886.prdoc rename to prdoc/stable2412/pr_5886.prdoc diff --git a/prdoc/pr_5888.prdoc b/prdoc/stable2412/pr_5888.prdoc similarity index 100% rename from prdoc/pr_5888.prdoc rename to prdoc/stable2412/pr_5888.prdoc diff --git a/prdoc/pr_5891.prdoc b/prdoc/stable2412/pr_5891.prdoc similarity index 100% rename from prdoc/pr_5891.prdoc rename to prdoc/stable2412/pr_5891.prdoc diff --git a/prdoc/pr_5892.prdoc b/prdoc/stable2412/pr_5892.prdoc similarity index 100% rename from prdoc/pr_5892.prdoc rename to prdoc/stable2412/pr_5892.prdoc diff --git a/prdoc/pr_5901.prdoc b/prdoc/stable2412/pr_5901.prdoc similarity index 100% rename from prdoc/pr_5901.prdoc rename to prdoc/stable2412/pr_5901.prdoc diff --git a/prdoc/pr_5908.prdoc b/prdoc/stable2412/pr_5908.prdoc similarity index 100% rename from prdoc/pr_5908.prdoc rename to prdoc/stable2412/pr_5908.prdoc diff --git a/prdoc/pr_5911.prdoc b/prdoc/stable2412/pr_5911.prdoc similarity index 100% rename from prdoc/pr_5911.prdoc rename to prdoc/stable2412/pr_5911.prdoc diff --git a/prdoc/pr_5915.prdoc b/prdoc/stable2412/pr_5915.prdoc similarity index 100% rename from prdoc/pr_5915.prdoc rename to prdoc/stable2412/pr_5915.prdoc diff --git a/prdoc/pr_5917.prdoc b/prdoc/stable2412/pr_5917.prdoc similarity index 100% rename from prdoc/pr_5917.prdoc rename to prdoc/stable2412/pr_5917.prdoc diff --git a/prdoc/pr_5919.prdoc b/prdoc/stable2412/pr_5919.prdoc similarity index 100% rename from prdoc/pr_5919.prdoc rename to prdoc/stable2412/pr_5919.prdoc diff --git a/prdoc/pr_5924.prdoc b/prdoc/stable2412/pr_5924.prdoc similarity index 100% rename from prdoc/pr_5924.prdoc rename to prdoc/stable2412/pr_5924.prdoc diff --git a/prdoc/pr_5939.prdoc b/prdoc/stable2412/pr_5939.prdoc similarity index 100% rename from prdoc/pr_5939.prdoc rename to prdoc/stable2412/pr_5939.prdoc diff --git a/prdoc/pr_5941.prdoc b/prdoc/stable2412/pr_5941.prdoc similarity index 100% rename from prdoc/pr_5941.prdoc rename to prdoc/stable2412/pr_5941.prdoc diff --git a/prdoc/pr_5946.prdoc b/prdoc/stable2412/pr_5946.prdoc similarity index 100% rename from prdoc/pr_5946.prdoc rename to prdoc/stable2412/pr_5946.prdoc diff --git a/prdoc/pr_5954.prdoc b/prdoc/stable2412/pr_5954.prdoc similarity index 100% rename from prdoc/pr_5954.prdoc rename to prdoc/stable2412/pr_5954.prdoc diff --git a/prdoc/stable2412/pr_5961.prdoc b/prdoc/stable2412/pr_5961.prdoc new file mode 100644 index 000000000000..46a5be8e49d5 --- /dev/null +++ b/prdoc/stable2412/pr_5961.prdoc @@ -0,0 +1,15 @@ +# 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: "Bounties Pallet: add `approve_bounty_with_curator` call" + +doc: + - audience: [Runtime Dev, Runtime User] + description: | + Adds `approve_bounty_with_curator` call to the bounties pallet to combine `approve_bounty` and `propose_curator` into one call. If `unassign_curator` is called after `approve_bounty_with_curator` the process falls back to the previous flow of calling `propose_curator` separately. Introduces a new `ApprovedWithCurator` bounty status when bounty is approved with curator. + +crates: + - name: pallet-bounties + bump: major + - name: rococo-runtime + bump: minor diff --git a/prdoc/stable2412/pr_5971.prdoc b/prdoc/stable2412/pr_5971.prdoc new file mode 100644 index 000000000000..4b1afc4c268a --- /dev/null +++ b/prdoc/stable2412/pr_5971.prdoc @@ -0,0 +1,66 @@ +# 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: XCMv5 InitiateTransfer can preserve original origin across chains. + +doc: + - audience: Runtime User + description: | + The new InitiateTransfer instruction can preserve the original origin across chains by + setting `preserve_origin: true` in the instruction itself. + When it's set to true, it will append after the inner XCM, an `AliasOrigin` instruction + instead of the usual `ClearOrigin`. + This instruction will try to alias to the original origin, thus preserving it. + This only works if the chain receiving the transfer supports the aliasing operation. + If not, `preserve_origin: false` works as before and will never fail because of this. + - audience: Runtime Dev + description: | + The new InitiateTransfer instruction can preserve the original origin across chains by + setting `preserve_origin: true` in the instruction itself. + When it's set to true, it will append after the inner XCM, an `AliasOrigin` instruction + instead of the usual `ClearOrigin`. + This instruction will try to alias to the original origin, thus preserving it. + + Beware: This only works if the following two rules are followed by the chain receiving such + a message. + - Alias to interior locations is valid (the exact same behaviour as DescendOrigin) + - AssetHub can alias everything (most importantly sibling accounts and ethereum). + These can be set with the `Aliasers` configuration item, with the following adapters: + - AliasChildLocation + - AliasOriginRootUsingFilter with AssetHub and Everything + An example of the first one can be seen in `asset-hub-westend` and of the second one in + `penpal-runtime`. + +crates: + - name: staging-xcm + bump: minor + - name: staging-xcm-builder + bump: minor + - name: staging-xcm-executor + bump: minor + - name: pallet-xcm-benchmarks + bump: minor + - name: snowbridge-router-primitives + bump: minor + - 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: 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: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor diff --git a/prdoc/stable2412/pr_5984.prdoc b/prdoc/stable2412/pr_5984.prdoc new file mode 100644 index 000000000000..3b6651bac6b9 --- /dev/null +++ b/prdoc/stable2412/pr_5984.prdoc @@ -0,0 +1,14 @@ +# 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: Add page information to staking::PayoutStarted event + +doc: + - audience: Runtime User + description: | + Adds page index that is claimed, and optional next page that can be claimed. If next is none, then the page is the + last one. + +crates: + - name: pallet-staking + bump: major diff --git a/prdoc/pr_5994.prdoc b/prdoc/stable2412/pr_5994.prdoc similarity index 100% rename from prdoc/pr_5994.prdoc rename to prdoc/stable2412/pr_5994.prdoc diff --git a/prdoc/pr_5995.prdoc b/prdoc/stable2412/pr_5995.prdoc similarity index 100% rename from prdoc/pr_5995.prdoc rename to prdoc/stable2412/pr_5995.prdoc diff --git a/prdoc/stable2412/pr_5997.prdoc b/prdoc/stable2412/pr_5997.prdoc new file mode 100644 index 000000000000..6bac36a44586 --- /dev/null +++ b/prdoc/stable2412/pr_5997.prdoc @@ -0,0 +1,18 @@ +# 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: Implement archive_unstable_storageDiff method + +doc: + - audience: Node Dev + description: | + This PR implements the `archive_unstable_storageDiff` rpc-v2 method. + Developers can use this method to fetch the storage differences + between two blocks. This is useful for oracles and archive nodes. + For more details see: https://github.com/paritytech/json-rpc-interface-spec/blob/main/src/api/archive_unstable_storageDiff.md. + +crates: + - name: sc-rpc-spec-v2 + bump: major + - name: sc-service + bump: patch diff --git a/prdoc/pr_5998.prdoc b/prdoc/stable2412/pr_5998.prdoc similarity index 100% rename from prdoc/pr_5998.prdoc rename to prdoc/stable2412/pr_5998.prdoc diff --git a/prdoc/pr_5999.prdoc b/prdoc/stable2412/pr_5999.prdoc similarity index 100% rename from prdoc/pr_5999.prdoc rename to prdoc/stable2412/pr_5999.prdoc diff --git a/prdoc/stable2412/pr_6011.prdoc b/prdoc/stable2412/pr_6011.prdoc new file mode 100644 index 000000000000..e053b607085f --- /dev/null +++ b/prdoc/stable2412/pr_6011.prdoc @@ -0,0 +1,12 @@ +title: "collator protocol: validate descriptor version on the validator side" + +doc: + - audience: Node Dev + description: | + Implement checks needed for RFC 103 https://github.com/polkadot-fellows/rfcs/pull/103 in the validator + side of the collator protocol. + + +crates: + - name: polkadot-collator-protocol + bump: major diff --git a/prdoc/pr_6015.prdoc b/prdoc/stable2412/pr_6015.prdoc similarity index 100% rename from prdoc/pr_6015.prdoc rename to prdoc/stable2412/pr_6015.prdoc diff --git a/prdoc/stable2412/pr_6016.prdoc b/prdoc/stable2412/pr_6016.prdoc new file mode 100644 index 000000000000..967c3a766068 --- /dev/null +++ b/prdoc/stable2412/pr_6016.prdoc @@ -0,0 +1,15 @@ +title: Litep2p network backend do not disconnect all peers on SetReservedPeers command + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + Previously, when the `SetReservedPeers` was received, all peers except the new + reserved peers were disconnected. + This PR ensures that previously reserved nodes are kept connected as regular nodes if + enough slots are available. + While at it, this PR excludes reserved peers from the candidates of peers obtained from + the peerstore. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/pr_6022.prdoc b/prdoc/stable2412/pr_6022.prdoc similarity index 100% rename from prdoc/pr_6022.prdoc rename to prdoc/stable2412/pr_6022.prdoc diff --git a/prdoc/pr_6023.prdoc b/prdoc/stable2412/pr_6023.prdoc similarity index 100% rename from prdoc/pr_6023.prdoc rename to prdoc/stable2412/pr_6023.prdoc diff --git a/prdoc/pr_6025.prdoc b/prdoc/stable2412/pr_6025.prdoc similarity index 100% rename from prdoc/pr_6025.prdoc rename to prdoc/stable2412/pr_6025.prdoc diff --git a/prdoc/pr_6027.prdoc b/prdoc/stable2412/pr_6027.prdoc similarity index 100% rename from prdoc/pr_6027.prdoc rename to prdoc/stable2412/pr_6027.prdoc diff --git a/prdoc/pr_6032.prdoc b/prdoc/stable2412/pr_6032.prdoc similarity index 100% rename from prdoc/pr_6032.prdoc rename to prdoc/stable2412/pr_6032.prdoc diff --git a/prdoc/pr_6039.prdoc b/prdoc/stable2412/pr_6039.prdoc similarity index 100% rename from prdoc/pr_6039.prdoc rename to prdoc/stable2412/pr_6039.prdoc diff --git a/prdoc/pr_6045.prdoc b/prdoc/stable2412/pr_6045.prdoc similarity index 100% rename from prdoc/pr_6045.prdoc rename to prdoc/stable2412/pr_6045.prdoc diff --git a/prdoc/pr_6058.prdoc b/prdoc/stable2412/pr_6058.prdoc similarity index 100% rename from prdoc/pr_6058.prdoc rename to prdoc/stable2412/pr_6058.prdoc diff --git a/prdoc/pr_6061.prdoc b/prdoc/stable2412/pr_6061.prdoc similarity index 100% rename from prdoc/pr_6061.prdoc rename to prdoc/stable2412/pr_6061.prdoc diff --git a/prdoc/pr_6073.prdoc b/prdoc/stable2412/pr_6073.prdoc similarity index 100% rename from prdoc/pr_6073.prdoc rename to prdoc/stable2412/pr_6073.prdoc diff --git a/prdoc/stable2412/pr_6077.prdoc b/prdoc/stable2412/pr_6077.prdoc new file mode 100644 index 000000000000..f222fb27ce07 --- /dev/null +++ b/prdoc/stable2412/pr_6077.prdoc @@ -0,0 +1,9 @@ +title: Add networking benchmarks for libp2p +doc: +- audience: node_dev + description: |- + Adds benchmarks for Notifications and RequestResponse protocols with libp2p implementation + +crates: +- name: sc-network + validate: false diff --git a/prdoc/pr_6080.prdoc b/prdoc/stable2412/pr_6080.prdoc similarity index 100% rename from prdoc/pr_6080.prdoc rename to prdoc/stable2412/pr_6080.prdoc diff --git a/prdoc/pr_6087.prdoc b/prdoc/stable2412/pr_6087.prdoc similarity index 100% rename from prdoc/pr_6087.prdoc rename to prdoc/stable2412/pr_6087.prdoc diff --git a/prdoc/pr_6088.prdoc b/prdoc/stable2412/pr_6088.prdoc similarity index 100% rename from prdoc/pr_6088.prdoc rename to prdoc/stable2412/pr_6088.prdoc diff --git a/prdoc/pr_6094.prdoc b/prdoc/stable2412/pr_6094.prdoc similarity index 100% rename from prdoc/pr_6094.prdoc rename to prdoc/stable2412/pr_6094.prdoc diff --git a/prdoc/pr_6096.prdoc b/prdoc/stable2412/pr_6096.prdoc similarity index 100% rename from prdoc/pr_6096.prdoc rename to prdoc/stable2412/pr_6096.prdoc diff --git a/prdoc/pr_6104.prdoc b/prdoc/stable2412/pr_6104.prdoc similarity index 100% rename from prdoc/pr_6104.prdoc rename to prdoc/stable2412/pr_6104.prdoc diff --git a/prdoc/pr_6105.prdoc b/prdoc/stable2412/pr_6105.prdoc similarity index 100% rename from prdoc/pr_6105.prdoc rename to prdoc/stable2412/pr_6105.prdoc diff --git a/prdoc/pr_6129.prdoc b/prdoc/stable2412/pr_6129.prdoc similarity index 100% rename from prdoc/pr_6129.prdoc rename to prdoc/stable2412/pr_6129.prdoc diff --git a/prdoc/pr_6141.prdoc b/prdoc/stable2412/pr_6141.prdoc similarity index 100% rename from prdoc/pr_6141.prdoc rename to prdoc/stable2412/pr_6141.prdoc diff --git a/prdoc/pr_6147.prdoc b/prdoc/stable2412/pr_6147.prdoc similarity index 100% rename from prdoc/pr_6147.prdoc rename to prdoc/stable2412/pr_6147.prdoc diff --git a/prdoc/pr_6148.prdoc b/prdoc/stable2412/pr_6148.prdoc similarity index 100% rename from prdoc/pr_6148.prdoc rename to prdoc/stable2412/pr_6148.prdoc diff --git a/prdoc/pr_6156.prdoc b/prdoc/stable2412/pr_6156.prdoc similarity index 100% rename from prdoc/pr_6156.prdoc rename to prdoc/stable2412/pr_6156.prdoc diff --git a/prdoc/stable2412/pr_6169.prdoc b/prdoc/stable2412/pr_6169.prdoc new file mode 100644 index 000000000000..0416fe008051 --- /dev/null +++ b/prdoc/stable2412/pr_6169.prdoc @@ -0,0 +1,63 @@ +title: "[Deprecation] deprecate treasury `spend_local` call and related items" + +doc: + - audience: Runtime Dev + description: | + Deprecates `spend_local` from the treasury pallet and items associated with it. + + ### Migration + + #### For users who were using only `spend_local` before + + To replace `spend_local` functionality configure `Paymaster` pallet configuration to be `PayFromAccount` and configure `AssetKind` to be `()` and use `spend` call instead. + This way `spend` call will function as deprecated `spend_local`. + + Example: + ``` + impl pallet_treasury::Config for Runtime { + .. + type AssetKind = (); + type Paymaster = PayFromAccount; + // convert balance 1:1 ratio with native currency + type BalanceConverter = UnityAssetBalanceConversion; + .. + } + ``` + + #### For users who were already using `spend` with all other assets, except the native asset + + Use `NativeOrWithId` type for `AssetKind` and have a `UnionOf` for native and non-native assets, then use that with `PayAssetFromAccount`. + + Example from `kitchensink-runtime`: + ``` + // Union of native currency and assets + pub type NativeAndAssets = + UnionOf, AccountId>; + + impl pallet_treasury::Config for Runtime { + .. + type AssetKind = NativeOrWithId; + type Paymaster = PayAssetFromAccount; + type BalanceConverter = AssetRate; + .. + } + + // AssetRate pallet configuration + impl pallet_asset_rate::Config for Runtime { + .. + type Currency = Balances; + type AssetKind = NativeOrWithId; + .. + } + ``` + + +crates: +- name: pallet-treasury + bump: patch +- name: pallet-bounties + bump: patch +- name: pallet-child-bounties + bump: patch +- name: pallet-tips + bump: patch diff --git a/prdoc/pr_6171.prdoc b/prdoc/stable2412/pr_6171.prdoc similarity index 100% rename from prdoc/pr_6171.prdoc rename to prdoc/stable2412/pr_6171.prdoc diff --git a/prdoc/pr_6174.prdoc b/prdoc/stable2412/pr_6174.prdoc similarity index 100% rename from prdoc/pr_6174.prdoc rename to prdoc/stable2412/pr_6174.prdoc diff --git a/prdoc/stable2412/pr_6187.prdoc b/prdoc/stable2412/pr_6187.prdoc new file mode 100644 index 000000000000..92d801987969 --- /dev/null +++ b/prdoc/stable2412/pr_6187.prdoc @@ -0,0 +1,16 @@ +title: '[pallet-revive] rework balance transfers' +doc: +- audience: Runtime Dev + description: |- + This PR removes the `transfer` syscall and changes balance transfers to make the existential deposit (ED) fully transparent for contracts. + + The `transfer` API is removed since there is no corresponding EVM opcode and transferring via a call introduces barely any overhead. + + We make the ED transparent to contracts by transferring the ED from the call origin to nonexistent accounts. Without this change, transfers to nonexistant accounts will transfer the supplied value minus the ED from the contracts viewpoint, and consequentially fail if the supplied value lies below the ED. Changing this behavior removes the need for contract code to handle this rather annoying corner case and aligns better with the EVM. The EVM charges a similar deposit from the gas meter, so transferring the ED from the call origin is practically the same as the call origin pays for gas. +crates: +- name: pallet-revive + bump: major +- name: pallet-revive-fixtures + bump: patch +- name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6192.prdoc b/prdoc/stable2412/pr_6192.prdoc similarity index 100% rename from prdoc/pr_6192.prdoc rename to prdoc/stable2412/pr_6192.prdoc diff --git a/prdoc/pr_6205.prdoc b/prdoc/stable2412/pr_6205.prdoc similarity index 100% rename from prdoc/pr_6205.prdoc rename to prdoc/stable2412/pr_6205.prdoc diff --git a/prdoc/pr_6212.prdoc b/prdoc/stable2412/pr_6212.prdoc similarity index 100% rename from prdoc/pr_6212.prdoc rename to prdoc/stable2412/pr_6212.prdoc diff --git a/prdoc/pr_6214.prdoc b/prdoc/stable2412/pr_6214.prdoc similarity index 100% rename from prdoc/pr_6214.prdoc rename to prdoc/stable2412/pr_6214.prdoc diff --git a/prdoc/stable2412/pr_6217.prdoc b/prdoc/stable2412/pr_6217.prdoc new file mode 100644 index 000000000000..2fa800b58d2c --- /dev/null +++ b/prdoc/stable2412/pr_6217.prdoc @@ -0,0 +1,24 @@ +title: 'Unify and harden UMP signal checks in check_core_index' +doc: +- audience: [Runtime Dev, Node Dev] + description: | + Refactors and hardens the core index checks on the candidate commitments. + Also adds a utility for skipping the ump signals + +crates: +- name: cumulus-client-consensus-aura + bump: patch +- name: cumulus-pallet-parachain-system + bump: patch +- name: cumulus-primitives-core + bump: major +- name: polkadot-node-collation-generation + bump: major +- name: polkadot-node-core-candidate-validation + bump: patch +- name: polkadot-node-subsystem-util + bump: patch +- name: polkadot-primitives + bump: major +- name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/pr_6218.prdoc b/prdoc/stable2412/pr_6218.prdoc similarity index 100% rename from prdoc/pr_6218.prdoc rename to prdoc/stable2412/pr_6218.prdoc diff --git a/prdoc/stable2412/pr_6221.prdoc b/prdoc/stable2412/pr_6221.prdoc new file mode 100644 index 000000000000..57c81b322f92 --- /dev/null +++ b/prdoc/stable2412/pr_6221.prdoc @@ -0,0 +1,10 @@ +title: "snowbridge: allow account conversion for Ethereum accounts" + +doc: + - audience: Runtime Dev + description: | + Replaced `GlobalConsensusEthereumConvertsFor` with `EthereumLocationsConverterFor` that allows `Location` + to `AccountId` conversion for the Ethereum network root as before, but also for Ethereum contracts and accounts. +crates: + - name: snowbridge-router-primitives + bump: major diff --git a/prdoc/stable2412/pr_6228.prdoc b/prdoc/stable2412/pr_6228.prdoc new file mode 100644 index 000000000000..4512adf01bbb --- /dev/null +++ b/prdoc/stable2412/pr_6228.prdoc @@ -0,0 +1,50 @@ +# 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: Transact without having to specify weight + +doc: + - audience: [Runtime User, Runtime Dev] + description: | + In XCMv5, it's no longer required to pass in the expected weight when using + `Transact`. + This was made to remove a whole class of bugs where the weight specified + was not enough. + +crates: + - name: staging-xcm + bump: major + - name: staging-xcm-executor + bump: major + - name: snowbridge-router-primitives + bump: minor + - name: emulated-integration-tests-common + bump: minor + - name: cumulus-ping + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: parachains-runtimes-test-utils + bump: minor + - name: bridge-hub-westend-runtime + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: people-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-xcm-benchmarks + bump: minor + - name: xcm-simulator-example + bump: minor diff --git a/prdoc/pr_6246.prdoc b/prdoc/stable2412/pr_6246.prdoc similarity index 100% rename from prdoc/pr_6246.prdoc rename to prdoc/stable2412/pr_6246.prdoc diff --git a/prdoc/stable2412/pr_6255.prdoc b/prdoc/stable2412/pr_6255.prdoc new file mode 100644 index 000000000000..7b69717b5c2d --- /dev/null +++ b/prdoc/stable2412/pr_6255.prdoc @@ -0,0 +1,34 @@ +title: '[pallet-child-bounties] Index child bounties by parent bounty' +doc: +- audience: Runtime Dev + description: | + Index child bounties by their parent bounty, ensuring that their indexes are independent of + child bounties from other parent bounties. This will allow for predictable indexes and the + ability to batch creation and approval calls together. + + ### Migration for Runtime Pallet Instance + Use `migration::v1::MigrateToV1Impl` storage migration type to translate ids for the active + child bounties and migrate the state to the new schema. + + ### Migration for Clients + - Use new `ParentTotalChildBounties` storage item to iterate over child bounties for a certain + parent bounty; + - Use new `ChildBountyDescriptionsV1` storage item to get the bounty description instead of + removed `ChildBountyDescriptions`; + - Use `V0ToV1ChildBountyIds` storage item to look up the new child bounty id for a given + old child bounty id; + - Update the child bounty account id derivation from `PalletId + "cb" + child_id` to + `PalletId + "cb" + bounty_id + child_id`. + + ### Additional Notes + - The `ChildBountyCount` storage item is deprecated and will be remove in May 2025. + +crates: +- name: pallet-child-bounties + bump: major +- name: pallet-bounties + bump: major +- name: rococo-runtime + bump: major +- name: sp-core + bump: minor diff --git a/prdoc/stable2412/pr_6257.prdoc b/prdoc/stable2412/pr_6257.prdoc new file mode 100644 index 000000000000..45f9810108ef --- /dev/null +++ b/prdoc/stable2412/pr_6257.prdoc @@ -0,0 +1,10 @@ +title: 'fix claim queue size when validator groups count is smaller' +doc: +- audience: Runtime Dev + description: 'Fixes a bug introduced in https://github.com/paritytech/polkadot-sdk/pull/5461, where the claim queue + would contain entries even if the validator groups storage is empty (which happens during the first session). + This PR sets the claim queue core count to be the minimum between the num_cores param and the number of validator groups.' + +crates: +- name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/pr_6260.prdoc b/prdoc/stable2412/pr_6260.prdoc similarity index 100% rename from prdoc/pr_6260.prdoc rename to prdoc/stable2412/pr_6260.prdoc diff --git a/prdoc/stable2412/pr_6261.prdoc b/prdoc/stable2412/pr_6261.prdoc new file mode 100644 index 000000000000..20ee5563bcfd --- /dev/null +++ b/prdoc/stable2412/pr_6261.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: Add missing events to identity pallet + +doc: + - audience: Runtime Dev + description: | + Extrinsics from `pallet_identity` that were missing an event emission on success now emit one. + +crates: + - name: pallet-identity + bump: major diff --git a/prdoc/pr_6263.prdoc b/prdoc/stable2412/pr_6263.prdoc similarity index 100% rename from prdoc/pr_6263.prdoc rename to prdoc/stable2412/pr_6263.prdoc diff --git a/prdoc/pr_6264.prdoc b/prdoc/stable2412/pr_6264.prdoc similarity index 100% rename from prdoc/pr_6264.prdoc rename to prdoc/stable2412/pr_6264.prdoc diff --git a/prdoc/pr_6268.prdoc b/prdoc/stable2412/pr_6268.prdoc similarity index 100% rename from prdoc/pr_6268.prdoc rename to prdoc/stable2412/pr_6268.prdoc diff --git a/prdoc/pr_6278.prdoc b/prdoc/stable2412/pr_6278.prdoc similarity index 100% rename from prdoc/pr_6278.prdoc rename to prdoc/stable2412/pr_6278.prdoc diff --git a/prdoc/pr_6288.prdoc b/prdoc/stable2412/pr_6288.prdoc similarity index 100% rename from prdoc/pr_6288.prdoc rename to prdoc/stable2412/pr_6288.prdoc diff --git a/prdoc/stable2412/pr_6291.prdoc b/prdoc/stable2412/pr_6291.prdoc new file mode 100644 index 000000000000..73053c9d47bd --- /dev/null +++ b/prdoc/stable2412/pr_6291.prdoc @@ -0,0 +1,9 @@ +title: migrate pallet-remarks to v2 bench syntax +doc: +- audience: Runtime Dev + description: |- + Part of: + * #6202 +crates: +- name: pallet-remark + bump: patch diff --git a/prdoc/stable2412/pr_6295.prdoc b/prdoc/stable2412/pr_6295.prdoc new file mode 100644 index 000000000000..c7e4282208ee --- /dev/null +++ b/prdoc/stable2412/pr_6295.prdoc @@ -0,0 +1,10 @@ +title: Migrate pallet-im-online benchmark to v2 +doc: +- audience: Runtime Dev + description: |- + Part of: + + - #6202. +crates: +- name: pallet-im-online + bump: patch diff --git a/prdoc/pr_6296.prdoc b/prdoc/stable2412/pr_6296.prdoc similarity index 100% rename from prdoc/pr_6296.prdoc rename to prdoc/stable2412/pr_6296.prdoc diff --git a/prdoc/stable2412/pr_6298.prdoc b/prdoc/stable2412/pr_6298.prdoc new file mode 100644 index 000000000000..fa8d73b11943 --- /dev/null +++ b/prdoc/stable2412/pr_6298.prdoc @@ -0,0 +1,25 @@ +title: Populate authority DHT records with public listen addresses + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + This PR populates the authority DHT records with public listen addresses if any. + The change effectively ensures that addresses are added to the DHT record in the + following order: + 1. Public addresses provided by CLI `--public-addresses` + 2. Maximum of 4 public (global) listen addresses (if any) + 3. Any external addresses discovered from the network (ie from `/identify` protocol) + + While at it, this PR adds the following constraints on the number of addresses: + - Total number of addresses cached is bounded at 16 (increased from 10). + - A maximum number of 32 addresses are published to DHT records (previously unbounded). + - A maximum of 4 global listen addresses are utilized. + + This PR replaces the following warning: + `WARNING: No public address specified, validator node may not be reachable.` + with a more descriptive one originated from the authority-discovery + mechanism itself: `No public addresses configured and no global listen addresses found`. + +crates: + - name: sc-authority-discovery + bump: patch diff --git a/prdoc/stable2412/pr_6299.prdoc b/prdoc/stable2412/pr_6299.prdoc new file mode 100644 index 000000000000..fe8906f6e153 --- /dev/null +++ b/prdoc/stable2412/pr_6299.prdoc @@ -0,0 +1,8 @@ +title: migrate pallet-recovery to benchmark V2 syntax +doc: +- audience: Runtime Dev + description: |- + migrate pallet-recovery to benchmark V2 syntax +crates: +- name: pallet-recovery + bump: patch diff --git a/prdoc/stable2412/pr_6304.prdoc b/prdoc/stable2412/pr_6304.prdoc new file mode 100644 index 000000000000..1c8f1bb25deb --- /dev/null +++ b/prdoc/stable2412/pr_6304.prdoc @@ -0,0 +1,45 @@ +# 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: XCMv5 - Add ExecuteWithOrigin instruction + +doc: + - audience: [Runtime User, Runtime Dev] + description: | + Added a new instruction to XCMv5, ExecuteWithOrigin, that allows you to specify an interior origin + and a set of instructions that will be executed using that origin. + The origins you can choose are `None` to clear it during the execution of the inner instructions, + or `Some(InteriorLocation)` to descend into an interior location. + These two options mimic the behaviour of `ClearOrigin` and `DescendOrigin` respectively. + Crucially, this instruction goes back to the previous origin once the execution of those inner + instructions end. + This allows use-cases like a parent location paying fees with one interior location, fetching funds + with another, claiming assets on behalf of many different ones, etc. + +crates: + - name: staging-xcm + bump: major + - name: staging-xcm-executor + bump: minor + - name: staging-xcm-builder + bump: minor + - 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: people-rococo-runtime + bump: minor + - name: people-westend-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor diff --git a/prdoc/pr_6305.prdoc b/prdoc/stable2412/pr_6305.prdoc similarity index 100% rename from prdoc/pr_6305.prdoc rename to prdoc/stable2412/pr_6305.prdoc diff --git a/prdoc/stable2412/pr_6314.prdoc b/prdoc/stable2412/pr_6314.prdoc new file mode 100644 index 000000000000..2ebbc68158d5 --- /dev/null +++ b/prdoc/stable2412/pr_6314.prdoc @@ -0,0 +1,10 @@ +title: Migrate pallet-elections-phragmen benchmark to v2 and improve doc +doc: +- audience: Runtime Dev + description: |- + Part of: + + - #6202. +crates: +- name: pallet-elections-phragmen + bump: patch diff --git a/prdoc/stable2412/pr_6315.prdoc b/prdoc/stable2412/pr_6315.prdoc new file mode 100644 index 000000000000..6fc070b43b35 --- /dev/null +++ b/prdoc/stable2412/pr_6315.prdoc @@ -0,0 +1,8 @@ +title: Migrate pallet-election-provider-support-benchmarking benchmark to v2 +doc: +- audience: Runtime Dev + description: |- + Migrate pallet-election-provider-support-benchmarking benchmark to v2 +crates: +- name: pallet-election-provider-support-benchmarking + bump: patch diff --git a/prdoc/pr_6316.prdoc b/prdoc/stable2412/pr_6316.prdoc similarity index 100% rename from prdoc/pr_6316.prdoc rename to prdoc/stable2412/pr_6316.prdoc diff --git a/prdoc/pr_6317.prdoc b/prdoc/stable2412/pr_6317.prdoc similarity index 100% rename from prdoc/pr_6317.prdoc rename to prdoc/stable2412/pr_6317.prdoc diff --git a/prdoc/pr_6318.prdoc b/prdoc/stable2412/pr_6318.prdoc similarity index 100% rename from prdoc/pr_6318.prdoc rename to prdoc/stable2412/pr_6318.prdoc diff --git a/prdoc/stable2412/pr_6323.prdoc b/prdoc/stable2412/pr_6323.prdoc new file mode 100644 index 000000000000..ec632a14f946 --- /dev/null +++ b/prdoc/stable2412/pr_6323.prdoc @@ -0,0 +1,32 @@ +title: add `TransactionSource` to `TransactionExtension::validate` +doc: +- audience: Runtime Dev + description: | + Add a the source of the extrinsic as an argument in `TransactionExtension::validate`. + The transaction source can be useful for transactions that should only be valid if it comes from the node. For example from offchain worker. + To update the current code. The transaction source can simply be ignored: `_source: TransactionSource` + + +crates: +- name: sp-runtime + bump: major +- name: bridge-runtime-common + bump: patch +- name: frame-system + bump: patch +- name: pallet-transaction-payment + bump: patch +- name: polkadot-runtime-common + bump: patch +- name: pallet-sudo + bump: patch +- name: pallet-verify-signature + bump: patch +- name: pallet-asset-tx-payment + bump: patch +- name: pallet-bridge-relayers + bump: patch +- name: pallet-asset-conversion-tx-payment + bump: patch +- name: pallet-skip-feeless-payment + bump: patch diff --git a/prdoc/stable2412/pr_6337.prdoc b/prdoc/stable2412/pr_6337.prdoc new file mode 100644 index 000000000000..aeab61cdf933 --- /dev/null +++ b/prdoc/stable2412/pr_6337.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: Don't expose metadata for Runtime APIs that haven't been implemented + +doc: + - audience: Runtime User + description: | + Prior to this PR, the metadata for runtime APIs would contain all methods for the + latest version of each API, regardless of which version a runtime implements. This + PR fixes that, so that the runtime API metadata reflects what is actually implemented. + +crates: + - name: sp-api-proc-macro + bump: major + - name: sp-consensus-babe + bump: patch \ No newline at end of file diff --git a/prdoc/stable2412/pr_6353.prdoc b/prdoc/stable2412/pr_6353.prdoc new file mode 100644 index 000000000000..8a5a152628a0 --- /dev/null +++ b/prdoc/stable2412/pr_6353.prdoc @@ -0,0 +1,10 @@ +title: Update litep2p network backend to version 0.8.0 + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + Release 0.8.0 of litep2p includes several improvements and memory leak fixes enhancing the stability and performance of the litep2p network backend. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/stable2412/pr_6357.prdoc b/prdoc/stable2412/pr_6357.prdoc new file mode 100644 index 000000000000..b3155b1a6050 --- /dev/null +++ b/prdoc/stable2412/pr_6357.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: New runtime api that returns the associated pool accounts with a nomination pool. + +doc: + - audience: Runtime User + description: | + Each nomination pool has two associated pot accounts: the bonded account, where funds are pooled for staking, and + the reward account. This update introduces a runtime api that clients can query to retrieve these accounts. + +crates: + - name: westend-runtime + bump: minor + - name: kitchensink-runtime + bump: minor + - name: pallet-nomination-pools + bump: minor + - name: pallet-nomination-pools-runtime-api + bump: minor diff --git a/prdoc/stable2412/pr_6360.prdoc b/prdoc/stable2412/pr_6360.prdoc new file mode 100644 index 000000000000..270af29e37af --- /dev/null +++ b/prdoc/stable2412/pr_6360.prdoc @@ -0,0 +1,9 @@ +title: '[eth-rpc] proxy /health' +doc: +- audience: Runtime Dev + description: |- + make the eth-rpc proxy /health and /health/readiness from the proxied substrate chain + see #4802 +crates: +- name: pallet-revive-eth-rpc + bump: minor diff --git a/prdoc/stable2412/pr_6365.prdoc b/prdoc/stable2412/pr_6365.prdoc new file mode 100644 index 000000000000..b99a7ae4035e --- /dev/null +++ b/prdoc/stable2412/pr_6365.prdoc @@ -0,0 +1,10 @@ +title: 'pallet-revive: Use `RUSTUP_TOOLCHAIN` if set' +doc: +- audience: Runtime Dev + description: We were not passing through the `RUSTUP_TOOLCHAIN` variable to the + `build.rs` script of our fixtures. This means that setting the toolchain like + `cargo +1.81 build` had no effect on the fixture build. It would always fall back + to the default toolchain. +crates: +- name: pallet-revive-fixtures + bump: major diff --git a/prdoc/stable2412/pr_6373.prdoc b/prdoc/stable2412/pr_6373.prdoc new file mode 100644 index 000000000000..04758d9dd41f --- /dev/null +++ b/prdoc/stable2412/pr_6373.prdoc @@ -0,0 +1,8 @@ +title: '`chain-spec-builder`: info about patch/full files added' +doc: +- audience: Runtime User + description: There was no good example of what is patch and full genesis config + file. Some explanation and example were added to the `chain-spec-builder` doc. +crates: +- name: staging-chain-spec-builder + bump: patch diff --git a/prdoc/stable2412/pr_6380.prdoc b/prdoc/stable2412/pr_6380.prdoc new file mode 100644 index 000000000000..72853bcf230c --- /dev/null +++ b/prdoc/stable2412/pr_6380.prdoc @@ -0,0 +1,11 @@ +title: Do not propagate external addr with different peerIDs + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + External addresses that belong to a different peerID are no longer + propagated to the higher layers of the networking backends. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/stable2412/pr_6382.prdoc b/prdoc/stable2412/pr_6382.prdoc new file mode 100644 index 000000000000..ac6821c1100a --- /dev/null +++ b/prdoc/stable2412/pr_6382.prdoc @@ -0,0 +1,12 @@ +title: 'gensis-config: patching default `RuntimeGenesisConfig` fixed' +doc: +- audience: Node Dev + description: |- + This PR fixes issue reported in #6306. + It changes the behavior of `sc_chain_spec::json_patch::merge` function which no longer removes any keys from the base JSON object. + +crates: +- name: staging-chain-spec-builder + bump: major +- name: sc-chain-spec + bump: major diff --git a/prdoc/stable2412/pr_6384.prdoc b/prdoc/stable2412/pr_6384.prdoc new file mode 100644 index 000000000000..2ea0bc1043c3 --- /dev/null +++ b/prdoc/stable2412/pr_6384.prdoc @@ -0,0 +1,12 @@ +title: Relax requirements on `assign_core`. +doc: +- audience: Runtime Dev + description: |- + Relax requirements for `assign_core` so that it accepts updates for the last scheduled entry. + This will allow the coretime chain to split up assignments into multiple + messages, which allows for interlacing down to single block granularity. + + Fixes: https://github.com/paritytech/polkadot-sdk/issues/6102 +crates: +- name: polkadot-runtime-parachains + bump: major diff --git a/prdoc/stable2412/pr_6406.prdoc b/prdoc/stable2412/pr_6406.prdoc new file mode 100644 index 000000000000..9da4462263b9 --- /dev/null +++ b/prdoc/stable2412/pr_6406.prdoc @@ -0,0 +1,9 @@ +title: 'make prospective-parachains debug logs less spammy' +doc: +- audience: [Node Dev, Node Operator] + description: | + Demote some of the frequent prospective-parachains debug logs to trace level and prefer printing aggregate debug logs. + +crates: +- name: polkadot-node-core-prospective-parachains + bump: patch diff --git a/prdoc/stable2412/pr_6418.prdoc b/prdoc/stable2412/pr_6418.prdoc new file mode 100644 index 000000000000..6696b54024b9 --- /dev/null +++ b/prdoc/stable2412/pr_6418.prdoc @@ -0,0 +1,151 @@ +# 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: Follow up work on TransactionExtension - fix weights and clean up UncheckedExtrinsic + +doc: + - audience: Runtime Dev + description: | + This PR removes the redundant extension version byte from the signed v4 extrinsic, previously + unused and defaulted to 0. The extension version byte is also made to be part of the inherited + implication handed to extensions in General transactions. Also, some system extensions + benchmarks were adjusted through whitelisting to not count the reads for frequently read + storage keys. + +crates: + - name: node-testing + bump: patch + - name: pallet-example-offchain-worker + bump: patch + - name: sp-runtime + bump: major + - name: substrate-test-utils + bump: patch + - name: pallet-alliance + bump: patch + - name: pallet-asset-conversion + bump: patch + - name: pallet-asset-conversion-ops + bump: patch + - name: pallet-asset-rate + bump: patch + - name: pallet-assets + bump: patch + - name: pallet-authorship + bump: patch + - name: pallet-bags-list + bump: patch + - name: pallet-balances + bump: patch + - name: pallet-beefy-mmr + bump: patch + - name: frame-benchmarking + bump: patch + - name: pallet-bounties + bump: patch + - name: pallet-broker + bump: patch + - name: pallet-child-bounties + bump: patch + - name: pallet-collective + bump: patch + - name: pallet-contracts + bump: patch + - name: pallet-conviction-voting + bump: patch + - name: pallet-core-fellowship + bump: patch + - name: pallet-democracy + bump: patch + - name: pallet-election-provider-multi-phase + bump: patch + - name: pallet-elections-phragmen + bump: patch + - name: pallet-fast-unstake + bump: patch + - name: pallet-glutton + bump: patch + - name: pallet-identity + bump: patch + - name: pallet-im-online + bump: patch + - name: pallet-indices + bump: patch + - name: pallet-lottery + bump: patch + - name: pallet-membership + bump: patch + - name: pallet-message-queue + bump: patch + - name: pallet-migrations + bump: patch + - name: pallet-multisig + bump: patch + - name: pallet-nft-fractionalization + bump: patch + - name: pallet-nfts + bump: patch + - name: pallet-nis + bump: patch + - name: pallet-nomination-pools + bump: patch + - name: pallet-parameters + bump: patch + - name: pallet-preimage + bump: patch + - name: pallet-proxy + bump: patch + - name: pallet-ranked-collective + bump: patch + - name: pallet-recovery + bump: patch + - name: pallet-referenda + bump: patch + - name: pallet-remark + bump: patch + - name: pallet-revive + bump: patch + - name: pallet-safe-mode + bump: patch + - name: pallet-salary + bump: patch + - name: pallet-scheduler + bump: patch + - name: pallet-session + bump: patch + - name: pallet-society + bump: patch + - name: pallet-staking + bump: patch + - name: pallet-state-trie-migration + bump: patch + - name: pallet-sudo + bump: patch + - name: frame-support + bump: patch + - name: pallet-timestamp + bump: patch + - name: pallet-tips + bump: patch + - name: pallet-asset-conversion-tx-payment + bump: patch + - name: pallet-transaction-payment + bump: patch + - name: pallet-transaction-storage + bump: patch + - name: pallet-treasury + bump: patch + - name: pallet-tx-pause + bump: patch + - name: pallet-uniques + bump: patch + - name: pallet-utility + bump: patch + - name: pallet-verify-signature + bump: patch + - name: pallet-vesting + bump: patch + - name: pallet-whitelist + bump: patch + - name: sp-runtime + bump: major diff --git a/prdoc/stable2412/pr_6454.prdoc b/prdoc/stable2412/pr_6454.prdoc new file mode 100644 index 000000000000..3fd3e39db604 --- /dev/null +++ b/prdoc/stable2412/pr_6454.prdoc @@ -0,0 +1,7 @@ +title: 'rpc server: fix ipv6 host filter for localhost' +doc: +- audience: Node Operator + description: "This PR fixes that ipv6 connections to localhost was faulty rejected by the host filter because only [::1] was allowed" +crates: +- name: sc-rpc-server + bump: minor diff --git a/prdoc/stable2412/pr_6484.prdoc b/prdoc/stable2412/pr_6484.prdoc new file mode 100644 index 000000000000..c212692e6ab4 --- /dev/null +++ b/prdoc/stable2412/pr_6484.prdoc @@ -0,0 +1,10 @@ +title: Update litep2p network backend to version 0.8.1 + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + Release 0.8.1 of litep2p includes critical fixes to further enhance the stability and performance of the litep2p network backend. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/stable2412/pr_6505.prdoc b/prdoc/stable2412/pr_6505.prdoc new file mode 100644 index 000000000000..ae00dd17fed5 --- /dev/null +++ b/prdoc/stable2412/pr_6505.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-broker] Fix auto renew benchmarks' +doc: +- audience: Runtime Dev + description: |- + Fix the broker pallet auto-renew benchmarks which have been broken since #4424, yielding `Weightless` due to some prices being set too low, as reported in #6474. + + Upon further investigation it turned out that the auto-renew contribution to `rotate_sale` was always failing but the error was mapped. This is also fixed at the cost of a bit of setup overhead. +crates: +- name: pallet-broker + bump: patch +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch diff --git a/prdoc/stable2412/pr_6536.prdoc b/prdoc/stable2412/pr_6536.prdoc new file mode 100644 index 000000000000..676b5c131f17 --- /dev/null +++ b/prdoc/stable2412/pr_6536.prdoc @@ -0,0 +1,24 @@ +title: Bridges testing improvements +doc: +- audience: Runtime Dev + description: |- + This PR includes: + - Refactored integrity tests to support standalone deployment of `pallet-bridge-messages`. + - Refactored the `open_and_close_bridge_works` test case to support multiple scenarios, such as: + 1. A local chain opening a bridge. + 2. Sibling parachains opening a bridge. + 3. The relay chain opening a bridge. + - Previously, we added instance support for `pallet-bridge-relayer` but overlooked updating the `DeliveryConfirmationPaymentsAdapter`. +crates: +- name: bridge-runtime-common + bump: patch +- name: pallet-bridge-relayers + bump: patch +- name: bridge-hub-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch +- name: bridge-hub-test-utils + bump: major +- name: parachains-runtimes-test-utils + bump: major diff --git a/prdoc/stable2412/pr_6566.prdoc b/prdoc/stable2412/pr_6566.prdoc new file mode 100644 index 000000000000..bbd48b799538 --- /dev/null +++ b/prdoc/stable2412/pr_6566.prdoc @@ -0,0 +1,45 @@ +# 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: XCMv5 - SetHints instruction + +doc: + - audience: Runtime Dev + description: | + Implementation of fellowship RFC 107. + The new SetHints instruction is a repackaging of SetAssetClaimer that also allows future + "hints" which alter the default behaviour of the executor. + The AllowTopLevelPaidExecutionFrom barrier allows this instruction between WithdrawAsset and + BuyExecution/PayFees to configure things before the actual meat of the program. + +crates: + - name: asset-hub-rococo-runtime + bump: major + - name: asset-hub-westend-runtime + bump: major + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: pallet-xcm-benchmarks + bump: major + - name: xcm-procedural + bump: minor + - name: staging-xcm + bump: major + - name: staging-xcm-builder + bump: major + - name: staging-xcm-executor + bump: major diff --git a/prdoc/stable2412/pr_6588.prdoc b/prdoc/stable2412/pr_6588.prdoc new file mode 100644 index 000000000000..bf44b2ed3784 --- /dev/null +++ b/prdoc/stable2412/pr_6588.prdoc @@ -0,0 +1,14 @@ +# 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: "rpc server: fix subscription id_provider being reset to default one" + +doc: + - audience: Node Dev + description: | + The modification ensures that the id_provider variable is cloned instead of taken, which can help prevent issues related id provider being reset to the default. + + +crates: + - name: sc-rpc-server + bump: patch \ No newline at end of file diff --git a/prdoc/stable2412/pr_6603.prdoc b/prdoc/stable2412/pr_6603.prdoc new file mode 100644 index 000000000000..20c5e7294dfa --- /dev/null +++ b/prdoc/stable2412/pr_6603.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: Always provide main protocol name in litep2p responses + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + This PR aligns litep2p behavior with libp2p. Previously, litep2p network backend + would provide the actual negotiated request-response protocol that produced a + response message. After this PR, only the main protocol name is reported to other + subsystems. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/stable2412/pr_6643.prdoc b/prdoc/stable2412/pr_6643.prdoc new file mode 100644 index 000000000000..c111f6356519 --- /dev/null +++ b/prdoc/stable2412/pr_6643.prdoc @@ -0,0 +1,47 @@ +title: Added fallback_max_weight to Transact for sending messages to V4 chains +doc: +- audience: Runtime Dev + description: |- + Removing the `require_weight_at_most` parameter in V5 Transact introduced a problem when converting a message from V5 to V4 to send to chains that didn't upgrade yet. + The local chain doesn't know how to decode calls for remote chains so it can't automatically populate `require_weight_at_most` required by V4 Transact. + To fix this, XCM v5 Transact now also takes a `fallback_max_weight: Option` parameter. + This can be set to `None` if the instruction is not meant to be sent to chains running XCM versions lower than V5. + If set to `Some(weight)`, a subsequent conversion to V4 will result in `Transact { require_weight_at_most: weight, .. }`. + The plan is to remove this workaround in V6 since there will be a good conversion path from V6 to V5. +crates: +- name: snowbridge-router-primitives + bump: major +- name: emulated-integration-tests-common + bump: major +- name: asset-hub-rococo-runtime + bump: major +- name: asset-hub-westend-runtime + bump: major +- name: asset-test-utils + bump: major +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: major +- name: coretime-rococo-runtime + bump: major +- name: coretime-westend-runtime + bump: major +- name: people-rococo-runtime + bump: major +- name: people-westend-runtime + bump: major +- name: parachains-runtimes-test-utils + bump: major +- name: polkadot-runtime-parachains + bump: major +- name: rococo-runtime + bump: major +- name: westend-runtime + bump: major +- name: staging-xcm + bump: major +- name: staging-xcm-builder + bump: major +- name: staging-xcm-executor + bump: major diff --git a/prdoc/stable2412/pr_6645.prdoc b/prdoc/stable2412/pr_6645.prdoc new file mode 100644 index 000000000000..f033cadc0b6e --- /dev/null +++ b/prdoc/stable2412/pr_6645.prdoc @@ -0,0 +1,14 @@ +title: 'xcm: fix local/remote exports when inner routers return `NotApplicable`' +doc: +- audience: Runtime Dev + description: |- + Resolved a bug in the `local/remote exporters` used for bridging. Previously, they consumed `dest` and `msg` without returning them when inner routers/exporters failed with `NotApplicable`. This PR ensures compliance with the [`SendXcm`](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/src/v5/traits.rs#L449-L450) and [`ExportXcm`](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/xcm-executor/src/traits/export.rs#L44-L45) traits. +crates: +- name: staging-xcm-builder + bump: patch +- name: polkadot + bump: none +- name: staging-xcm + bump: none +- name: staging-xcm-executor + bump: none diff --git a/prdoc/stable2412/pr_6646.prdoc b/prdoc/stable2412/pr_6646.prdoc new file mode 100644 index 000000000000..4dcda8d41bda --- /dev/null +++ b/prdoc/stable2412/pr_6646.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: OmniNode --dev flag starts node with manual seal + +doc: + - audience: [ Runtime Dev, Node Dev ] + description: | + `polkadot-omni-node` lib supports `--dev` flag now by allowing also to pass over a chain spec, + and starts the node with manual seal. It will seal the node at each `dev_block_time` milliseconds, + which can be set via `--dev-block-time`, and if not set will default to `3000ms`. + +crates: + - name: sc-cli + bump: patch + - name: polkadot-omni-node-lib + bump: patch + - name: polkadot-omni-node + bump: patch diff --git a/prdoc/stable2412/pr_6652.prdoc b/prdoc/stable2412/pr_6652.prdoc new file mode 100644 index 000000000000..a303311e138f --- /dev/null +++ b/prdoc/stable2412/pr_6652.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: "rpc server: re-use server builder per rpc interface" + +doc: + - audience: Node Dev + description: | + This changes that the RPC server builder is re-used for each RPC interface which is more efficient than to build it for every connection. + +crates: + - name: sc-rpc-server + bump: patch diff --git a/prdoc/stable2412/pr_6677.prdoc b/prdoc/stable2412/pr_6677.prdoc new file mode 100644 index 000000000000..c6766889e68d --- /dev/null +++ b/prdoc/stable2412/pr_6677.prdoc @@ -0,0 +1,11 @@ +title: 'chore: Update litep2p to v0.8.2' +doc: +- audience: Node Dev + description: |- + This includes a critical fix for debug release versions of litep2p (which are running in Kusama as validators). + + While at it, have stopped the oncall pain of alerts around `incoming_connections_total`. We can rethink the metric expose of litep2p in Q1. + +crates: +- name: sc-network + bump: minor diff --git a/prdoc/stable2412/pr_6690.prdoc b/prdoc/stable2412/pr_6690.prdoc new file mode 100644 index 000000000000..0e4a2437ef96 --- /dev/null +++ b/prdoc/stable2412/pr_6690.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: Fix Possible bug, Vote import failed after aggression is enabled + +doc: + - audience: Node Dev + description: | + Fix the appearance of Possible bug: Vote import failed after aggression is enabled, the log itself is + harmless because approval gets imported anyway and aggression is able to distribute it, nevertheless + is something that can be easily be fixed by picking the highest required routing possible. + +crates: + - name: polkadot-node-network-protocol + bump: minor + - name: polkadot-approval-distribution + bump: minor diff --git a/prdoc/stable2412/pr_6696.prdoc b/prdoc/stable2412/pr_6696.prdoc new file mode 100644 index 000000000000..c5c73f831886 --- /dev/null +++ b/prdoc/stable2412/pr_6696.prdoc @@ -0,0 +1,15 @@ +# 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: Make approval-distribution aggression a bit more robust and less spammy + +doc: + - audience: Node Dev + description: | + The problem with the current implementation of approval-distribution aggression is that is too spammy, + and can overload the nodes, so make it less spammy by moving back the moment we trigger L2 aggression + and make resend enable only for the latest unfinalized block. + +crates: + - name: polkadot-approval-distribution + bump: minor diff --git a/prdoc/stable2412/pr_6729.prdoc b/prdoc/stable2412/pr_6729.prdoc new file mode 100644 index 000000000000..9eaa67363c9a --- /dev/null +++ b/prdoc/stable2412/pr_6729.prdoc @@ -0,0 +1,15 @@ +# 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: Fix order of resending messages after restart + +doc: + - audience: Node Dev + description: | + At restart when dealing with a coalesced approval we might end up in a situation where we sent to + approval-distribution the approval before all assignments covering it, in that case, the approval + is ignored and never distribute, which will lead to no-shows. + +crates: + - name: polkadot-node-core-approval-voting + bump: minor diff --git a/prdoc/stable2412/pr_6742.prdoc b/prdoc/stable2412/pr_6742.prdoc new file mode 100644 index 000000000000..92c3755a3c28 --- /dev/null +++ b/prdoc/stable2412/pr_6742.prdoc @@ -0,0 +1,11 @@ +title: Update litep2p backend to v0.8.3 +doc: +- audience: Node Dev + description: |- + This release includes two fixes for small memory leaks on edge-cases in the notification and request-response protocols. + While at it, have downgraded a log message from litep2p. + +crates: +- name: sc-network + bump: patch + diff --git a/prdoc/stable2412/pr_6760.prdoc b/prdoc/stable2412/pr_6760.prdoc new file mode 100644 index 000000000000..8224b72fb0a4 --- /dev/null +++ b/prdoc/stable2412/pr_6760.prdoc @@ -0,0 +1,9 @@ +title: 'chainHead: Always report discarded items for storage operations' +doc: +- audience: [Node Dev, Node Operator] + description: |- + This PR ensures that substrate always reports discarded items as zero. + This is needed to align with the rpc-v2 spec +crates: +- name: sc-rpc-spec-v2 + bump: patch diff --git a/prdoc/stable2412/pr_6781.prdoc b/prdoc/stable2412/pr_6781.prdoc new file mode 100644 index 000000000000..8090be420341 --- /dev/null +++ b/prdoc/stable2412/pr_6781.prdoc @@ -0,0 +1,28 @@ +title: Bridges - revert-back congestion mechanism + +doc: +- audience: Runtime Dev + description: |- + With [permissionless lanes PR#4949](https://github.com/paritytech/polkadot-sdk/pull/4949), the congestion mechanism based on sending `Transact(report_bridge_status(is_congested))` from `pallet-xcm-bridge-hub` to `pallet-xcm-bridge-hub-router` was replaced with a congestion mechanism that relied on monitoring XCMP queues. However, this approach could cause issues, such as suspending the entire XCMP queue instead of isolating the affected bridge. This PR reverts back to using `report_bridge_status` as before. + +crates: +- name: pallet-xcm-bridge-hub-router + bump: patch +- name: pallet-xcm-bridge-hub + bump: patch +- name: bp-xcm-bridge-hub + bump: patch +- name: bp-asset-hub-rococo + bump: patch +- name: bp-asset-hub-westend + 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-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch diff --git a/prdoc/stable2412/pr_6814.prdoc b/prdoc/stable2412/pr_6814.prdoc new file mode 100644 index 000000000000..4edbf2f8ed28 --- /dev/null +++ b/prdoc/stable2412/pr_6814.prdoc @@ -0,0 +1,32 @@ +title: Add aliasers to westend chains +doc: +- audience: Runtime Dev + description: |- + `InitiateTransfer`, the new instruction introduced in XCMv5, allows preserving the origin after a cross-chain transfer via the usage of the `AliasOrigin` instruction. The receiving chain needs to be configured to allow such this instruction to have its intended effect and not just throw an error. + + In this PR, I add the alias rules specified in the [RFC for origin preservation](https://github.com/polkadot-fellows/RFCs/blob/main/text/0122-alias-origin-on-asset-transfers.md) to westend chains so we can test these scenarios in the testnet. + + The new scenarios include: + - Sending a cross-chain transfer from one system chain to another and doing a Transact on the same message (1 hop) + - Sending a reserve asset transfer from one chain to another going through asset hub and doing Transact on the same message (2 hops) + + The updated chains are: + - Relay: added `AliasChildLocation` + - Collectives: added `AliasChildLocation` and `AliasOriginRootUsingFilter` + - People: added `AliasChildLocation` and `AliasOriginRootUsingFilter` + - Coretime: added `AliasChildLocation` and `AliasOriginRootUsingFilter` + + AssetHub already has `AliasChildLocation` and doesn't need the other config item. + BridgeHub is not intended to be used by end users so I didn't add any config item. + Only added `AliasChildOrigin` to the relay since we intend for it to be used less. +crates: +- name: westend-runtime + bump: patch +- name: collectives-westend-runtime + bump: patch +- name: people-westend-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch +- name: pallet-xcm-benchmarks + bump: patch diff --git a/prdoc/stable2412/pr_6860.prdoc b/prdoc/stable2412/pr_6860.prdoc new file mode 100644 index 000000000000..76b460ce52dd --- /dev/null +++ b/prdoc/stable2412/pr_6860.prdoc @@ -0,0 +1,10 @@ +title: Update litep2p network backend to v0.8.4 + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + This PR updates the Litep2p network backend to version 0.8.4 + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/stable2412/pr_6863.prdoc b/prdoc/stable2412/pr_6863.prdoc new file mode 100644 index 000000000000..0dd416e5e438 --- /dev/null +++ b/prdoc/stable2412/pr_6863.prdoc @@ -0,0 +1,9 @@ +title: Update merkleized-metadata to 0.2.0 +doc: +- audience: Node Dev + description: |- + 0.1.2 was yanked as it was breaking semver. +crates: + - name: substrate-wasm-builder + bump: patch + validate: false diff --git a/prdoc/stable2412/pr_6864.prdoc b/prdoc/stable2412/pr_6864.prdoc new file mode 100644 index 000000000000..6d6c84e22da4 --- /dev/null +++ b/prdoc/stable2412/pr_6864.prdoc @@ -0,0 +1,18 @@ +# 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: Fix approval-voting canonicalize off by one + +doc: + - audience: Node Dev + description: | + The approval-voting canonicalize was off by one, which lead to blocks being + cleaned up every other 2 blocks. Normally, this is not an issue, but on restart + we might end up sending NewBlocks to approval-distribution with finalized blocks. + This would be problematic in the case were finalization was already lagging before + restart, so after restart approval-distribution will trigger aggression on the wrong + already finalized block. + +crates: + - name: polkadot-node-core-approval-voting + bump: minor diff --git a/prdoc/stable2412/pr_6885.prdoc b/prdoc/stable2412/pr_6885.prdoc new file mode 100644 index 000000000000..986d76962289 --- /dev/null +++ b/prdoc/stable2412/pr_6885.prdoc @@ -0,0 +1,11 @@ +title: 'Omni-node: Detect pending code in storage and send go ahead signal in dev-mode.' +doc: +- audience: Runtime Dev + description: |- + When using the polkadot-omni-node with manual seal (`--dev-block-time`), it is now possible to perform runtime + upgrades. The node will detect the pending validation code and send a go-ahead signal to the parachain. +crates: +- name: cumulus-client-parachain-inherent + bump: major +- name: polkadot-omni-node-lib + bump: patch diff --git a/scripts/generate-umbrella.py b/scripts/generate-umbrella.py index 8326909c3449..ae3873180553 100644 --- a/scripts/generate-umbrella.py +++ b/scripts/generate-umbrella.py @@ -120,6 +120,8 @@ def main(path, version): "edition": { "workspace": True }, "authors": { "workspace": True }, "description": "Polkadot SDK umbrella crate.", + "homepage": { "workspace": True }, + "repository": { "workspace": True }, "license": "Apache-2.0", "metadata": { "docs": { "rs": { "features": ["runtime-full", "node"], diff --git a/scripts/release/templates/audience.md.tera b/scripts/release/templates/audience.md.tera index 237643cfa392..d962030d0225 100644 --- a/scripts/release/templates/audience.md.tera +++ b/scripts/release/templates/audience.md.tera @@ -4,7 +4,7 @@ {% for file in prdoc -%} {% for doc_item in file.content.doc %} -{%- if doc_item.audience == env.TARGET_AUDIENCE %} +{%- if doc_item.audience is containing(env.TARGET_AUDIENCE) %} #### [#{{file.doc_filename.number}}]: {{ file.content.title }} {{ doc_item.description }} {% endif -%} diff --git a/substrate/.config/nextest.toml b/substrate/.config/nextest.toml deleted file mode 100644 index eb0ed09cad92..000000000000 --- a/substrate/.config/nextest.toml +++ /dev/null @@ -1,124 +0,0 @@ -# This is the default config used by nextest. It is embedded in the binary at -# build time. It may be used as a template for .config/nextest.toml. - -[store] -# The directory under the workspace root at which nextest-related files are -# written. Profile-specific storage is currently written to dir/. -dir = "target/nextest" - -# This section defines the default nextest profile. Custom profiles are layered -# on top of the default profile. -[profile.default] -# "retries" defines the number of times a test should be retried. If set to a -# non-zero value, tests that succeed on a subsequent attempt will be marked as -# non-flaky. Can be overridden through the `--retries` option. -# Examples -# * retries = 3 -# * retries = { backoff = "fixed", count = 2, delay = "1s" } -# * retries = { backoff = "exponential", count = 10, delay = "1s", jitter = true, max-delay = "10s" } -retries = 5 - -# The number of threads to run tests with. Supported values are either an integer or -# the string "num-cpus". Can be overridden through the `--test-threads` option. -test-threads = "num-cpus" - -# The number of threads required for each test. This is generally used in overrides to -# mark certain tests as heavier than others. However, it can also be set as a global parameter. -threads-required = 1 - -# Show these test statuses in the output. -# -# The possible values this can take are: -# * none: no output -# * fail: show failed (including exec-failed) tests -# * retry: show flaky and retried tests -# * slow: show slow tests -# * pass: show passed tests -# * skip: show skipped tests (most useful for CI) -# * all: all of the above -# -# Each value includes all the values above it; for example, "slow" includes -# failed and retried tests. -# -# Can be overridden through the `--status-level` flag. -status-level = "pass" - -# Similar to status-level, show these test statuses at the end of the run. -final-status-level = "flaky" - -# "failure-output" defines when standard output and standard error for failing tests are produced. -# Accepted values are -# * "immediate": output failures as soon as they happen -# * "final": output failures at the end of the test run -# * "immediate-final": output failures as soon as they happen and at the end of -# the test run; combination of "immediate" and "final" -# * "never": don't output failures at all -# -# For large test suites and CI it is generally useful to use "immediate-final". -# -# Can be overridden through the `--failure-output` option. -failure-output = "immediate" - -# "success-output" controls production of standard output and standard error on success. This should -# generally be set to "never". -success-output = "never" - -# Cancel the test run on the first failure. For CI runs, consider setting this -# to false. -fail-fast = true - -# Treat a test that takes longer than the configured 'period' as slow, and print a message. -# See for more information. -# -# Optional: specify the parameter 'terminate-after' with a non-zero integer, -# which will cause slow tests to be terminated after the specified number of -# periods have passed. -# Example: slow-timeout = { period = "60s", terminate-after = 2 } -slow-timeout = { period = "60s" } - -# Treat a test as leaky if after the process is shut down, standard output and standard error -# aren't closed within this duration. -# -# This usually happens in case of a test that creates a child process and lets it inherit those -# handles, but doesn't clean the child process up (especially when it fails). -# -# See for more information. -leak-timeout = "100ms" - -[profile.default.junit] -# Output a JUnit report into the given file inside 'store.dir/'. -# If unspecified, JUnit is not written out. - -path = "junit.xml" - -# The name of the top-level "report" element in JUnit report. If aggregating -# reports across different test runs, it may be useful to provide separate names -# for each report. -report-name = "substrate" - -# Whether standard output and standard error for passing tests should be stored in the JUnit report. -# Output is stored in the and elements of the element. -store-success-output = false - -# Whether standard output and standard error for failing tests should be stored in the JUnit report. -# Output is stored in the and elements of the element. -# -# Note that if a description can be extracted from the output, it is always stored in the -# element. -store-failure-output = true - -# This profile is activated if MIRI_SYSROOT is set. -[profile.default-miri] -# Miri tests take up a lot of memory, so only run 1 test at a time by default. -test-threads = 1 - -# Mutual exclusion of tests with `cargo build` invocation as a lock to avoid multiple -# simultaneous invocations clobbering each other. -[test-groups] -serial-integration = { max-threads = 1 } - -# Running UI tests sequentially -# More info can be found here: https://github.com/paritytech/ci_cd/issues/754 -[[profile.default.overrides]] -filter = 'test(/(^ui$|_ui|ui_)/)' -test-group = 'serial-integration' diff --git a/substrate/.maintain/frame-umbrella-weight-template.hbs b/substrate/.maintain/frame-umbrella-weight-template.hbs index 0f26fae1d8f1..b174823b3840 100644 --- a/substrate/.maintain/frame-umbrella-weight-template.hbs +++ b/substrate/.maintain/frame-umbrella-weight-template.hbs @@ -32,7 +32,7 @@ pub trait WeightInfo { /// Weights for `{{pallet}}` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); -{{#if (eq pallet "frame_system")}} +{{#if (or (eq pallet "frame_system") (eq pallet "frame_system_extensions"))}} impl WeightInfo for SubstrateWeight { {{else}} impl WeightInfo for SubstrateWeight { diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 8c6556da682c..83f7b82cd2b5 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -16,31 +16,32 @@ workspace = true [dependencies] array-bytes = { workspace = true, default-features = true } +async-trait = { workspace = true } clap = { features = ["derive"], workspace = true } +derive_more = { features = ["display"], workspace = true } +fs_extra = { workspace = true } +futures = { features = ["thread-pool"], workspace = true } +hash-db = { workspace = true, default-features = true } +kitchensink-runtime = { workspace = true } +kvdb = { workspace = true } +kvdb-rocksdb = { workspace = true } log = { workspace = true, default-features = true } node-primitives = { workspace = true, default-features = true } node-testing = { workspace = true } -kitchensink-runtime = { workspace = true } +parity-db = { workspace = true } +rand = { features = ["small_rng"], workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-state-machine = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -derive_more = { features = ["display"], workspace = true } -kvdb = { workspace = true } -kvdb-rocksdb = { workspace = true } -sp-trie = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } -sc-basic-authorship = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } sp-timestamp = { workspace = true } sp-tracing = { workspace = true, default-features = true } -hash-db = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } tempfile = { workspace = true } -fs_extra = { workspace = true } -rand = { features = ["small_rng"], workspace = true, default-features = true } -parity-db = { workspace = true } -sc-transaction-pool = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } -futures = { features = ["thread-pool"], workspace = true } diff --git a/substrate/bin/node/bench/src/construct.rs b/substrate/bin/node/bench/src/construct.rs index bed6e3d914c2..22129c6a1d69 100644 --- a/substrate/bin/node/bench/src/construct.rs +++ b/substrate/bin/node/bench/src/construct.rs @@ -24,14 +24,14 @@ //! DO NOT depend on user input). Thus transaction generation should be //! based on randomized data. -use futures::Future; use std::{borrow::Cow, collections::HashMap, pin::Pin, sync::Arc}; +use async_trait::async_trait; use node_primitives::Block; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes}; use sc_transaction_pool_api::{ - ImportNotificationStream, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, - TransactionSource, TransactionStatusStreamFor, TxHash, + ImportNotificationStream, PoolStatus, ReadyTransactions, TransactionFor, TransactionSource, + TransactionStatusStreamFor, TxHash, }; use sp_consensus::{Environment, Proposer}; use sp_inherents::InherentDataProvider; @@ -224,54 +224,47 @@ impl ReadyTransactions for TransactionsIterator { fn report_invalid(&mut self, _tx: &Self::Item) {} } +#[async_trait] impl sc_transaction_pool_api::TransactionPool for Transactions { type Block = Block; type Hash = node_primitives::Hash; type InPoolTransaction = PoolTransaction; type Error = sc_transaction_pool_api::error::Error; - /// Returns a future that imports a bunch of unverified transactions to the pool. - fn submit_at( + /// Asynchronously imports a bunch of unverified transactions to the pool. + async fn submit_at( &self, _at: Self::Hash, _source: TransactionSource, _xts: Vec>, - ) -> PoolFuture>, Self::Error> { + ) -> Result>, Self::Error> { unimplemented!() } - /// Returns a future that imports one unverified transaction to the pool. - fn submit_one( + /// Asynchronously imports one unverified transaction to the pool. + async fn submit_one( &self, _at: Self::Hash, _source: TransactionSource, _xt: TransactionFor, - ) -> PoolFuture, Self::Error> { + ) -> Result, Self::Error> { unimplemented!() } - fn submit_and_watch( + async fn submit_and_watch( &self, _at: Self::Hash, _source: TransactionSource, _xt: TransactionFor, - ) -> PoolFuture>>, Self::Error> { + ) -> Result>>, Self::Error> { unimplemented!() } - fn ready_at( + async fn ready_at( &self, _at: Self::Hash, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send, - >, - > { - let iter: Box> + Send> = - Box::new(TransactionsIterator(self.0.clone().into_iter())); - Box::pin(futures::future::ready(iter)) + ) -> Box> + Send> { + Box::new(TransactionsIterator(self.0.clone().into_iter())) } fn ready(&self) -> Box> + Send> { @@ -306,18 +299,11 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { unimplemented!() } - fn ready_at_with_timeout( + async fn ready_at_with_timeout( &self, _at: Self::Hash, _timeout: std::time::Duration, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send - + '_, - >, - > { + ) -> Box> + Send> { unimplemented!() } } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index c179579c1885..9e063ee3cde0 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -40,11 +40,11 @@ crate-type = ["cdylib", "rlib"] array-bytes = { workspace = true, default-features = true } clap = { features = ["derive"], optional = true, workspace = true } codec = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -jsonrpsee = { features = ["server"], workspace = true } futures = { workspace = true } +jsonrpsee = { features = ["server"], workspace = true } log = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } subxt-signer = { workspace = true, features = ["unstable-eth"] } @@ -135,32 +135,32 @@ polkadot-sdk = { features = [ # Shared code between the staging node and kitchensink runtime: kitchensink-runtime = { workspace = true } -node-rpc = { workspace = true } -node-primitives = { workspace = true, default-features = true } node-inspect = { optional = true, workspace = true, default-features = true } +node-primitives = { workspace = true, default-features = true } +node-rpc = { workspace = true } [dev-dependencies] -futures = { workspace = true } -tempfile = { workspace = true } assert_cmd = { workspace = true } +criterion = { features = ["async_tokio"], workspace = true, default-features = true } +futures = { workspace = true } nix = { features = ["signal"], workspace = true } -regex = { workspace = true } platforms = { workspace = true } +pretty_assertions.workspace = true +regex = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } soketto = { workspace = true } -criterion = { features = ["async_tokio"], workspace = true, default-features = true } +sp-keyring = { workspace = true } +tempfile = { workspace = true } tokio = { features = ["macros", "parking_lot", "time"], workspace = true, default-features = true } tokio-util = { features = ["compat"], workspace = true } wait-timeout = { workspace = true } wat = { workspace = true } -serde_json = { workspace = true, default-features = true } -scale-info = { features = ["derive", "serde"], workspace = true, default-features = true } -sp-keyring = { workspace = true } -pretty_assertions.workspace = true # These testing-only dependencies are not exported by the Polkadot-SDK crate: node-testing = { workspace = true } -substrate-cli-test-utils = { workspace = true } sc-service-test = { workspace = true } +substrate-cli-test-utils = { workspace = true } [build-dependencies] clap = { optional = true, workspace = true } diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 0c4a48a19260..038aa2f60928 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -427,7 +427,7 @@ fn props() -> Properties { fn eth_account(from: subxt_signer::eth::Keypair) -> AccountId32 { let mut account_id = AccountId32::new([0xEE; 32]); >::as_mut(&mut account_id)[..20] - .copy_from_slice(&from.account_id().0); + .copy_from_slice(&from.public_key().to_account_id().as_ref()); account_id } diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 057e0bbdcefc..5f6806c235f6 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -32,7 +32,6 @@ use frame_system_rpc_runtime_api::AccountNonceApi; use futures::prelude::*; use kitchensink_runtime::RuntimeApi; use node_primitives::Block; -use polkadot_sdk::sc_service::build_polkadot_syncing_strategy; use sc_client_api::{Backend, BlockBackend}; use sc_consensus_babe::{self, SlotProportion}; use sc_network::{ @@ -514,17 +513,7 @@ pub fn new_full_base::Hash>>( Vec::default(), )); - let syncing_strategy = build_polkadot_syncing_strategy( - config.protocol_id(), - config.chain_spec.fork_id(), - &mut net_config, - Some(WarpSyncConfig::WithProvider(warp_sync)), - client.clone(), - &task_manager.spawn_handle(), - config.prometheus_config.as_ref().map(|config| &config.registry), - )?; - - let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, net_config, @@ -533,7 +522,7 @@ pub fn new_full_base::Hash>>( spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - syncing_strategy, + warp_sync_config: Some(WarpSyncConfig::WithProvider(warp_sync)), block_relay: None, metrics, })?; @@ -812,7 +801,6 @@ pub fn new_full_base::Hash>>( ); } - network_starter.start_network(); Ok(NewFullBase { task_manager, client, @@ -883,7 +871,7 @@ mod tests { use sp_consensus::{BlockOrigin, Environment, Proposer}; use sp_core::crypto::Pair; use sp_inherents::InherentDataProvider; - use sp_keyring::AccountKeyring; + use sp_keyring::Sr25519Keyring; use sp_keystore::KeystorePtr; use sp_runtime::{ generic::{self, Digest, Era, SignedPayload}, @@ -918,8 +906,8 @@ mod tests { let mut slot = 1u64; // For the extrinsics factory - let bob = Arc::new(AccountKeyring::Bob.pair()); - let charlie = Arc::new(AccountKeyring::Charlie.pair()); + let bob = Arc::new(Sr25519Keyring::Bob.pair()); + let charlie = Arc::new(Sr25519Keyring::Charlie.pair()); let mut index = 0; sc_service_test::sync( diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 6c8a4e59f68d..0cf13bef71f1 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -17,7 +17,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { features = ["derive"], workspace = true } codec = { workspace = true, default-features = true } -thiserror = { workspace = true } sc-cli = { workspace = true } sc-client-api = { workspace = true, default-features = true } sc-service = { workspace = true } @@ -26,6 +25,7 @@ sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-statement-store = { workspace = true, default-features = true } +thiserror = { workspace = true } [features] runtime-benchmarks = [ diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index 02f5d9a4a702..c8b20287650b 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -17,16 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { features = ["server"], workspace = true } +mmr-rpc = { workspace = true, default-features = true } node-primitives = { workspace = true, default-features = true } pallet-transaction-payment-rpc = { workspace = true, default-features = true } -mmr-rpc = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } sc-consensus-babe-rpc = { workspace = true, default-features = true } sc-consensus-beefy = { workspace = true, default-features = true } sc-consensus-beefy-rpc = { workspace = true, default-features = true } -sp-consensus-beefy = { workspace = true, default-features = true } sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-grandpa-rpc = { workspace = true, default-features = true } sc-mixnet = { workspace = true, default-features = true } @@ -34,13 +33,14 @@ sc-rpc = { workspace = true, default-features = true } sc-sync-state-rpc = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } sp-statement-store = { workspace = true, default-features = true } substrate-frame-rpc-system = { workspace = true, default-features = true } substrate-state-trie-migration-rpc = { workspace = true, default-features = true } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 3ad6315561d0..6d377cc92cce 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -23,11 +23,11 @@ codec = { features = [ "derive", "max-encoded-len", ], workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } -static_assertions = { workspace = true, default-features = true } log = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } sp-debug-derive = { workspace = true, features = ["force-debug"] } +static_assertions = { workspace = true, default-features = true } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d407aafb452b..45ae378cc00e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -24,6 +24,13 @@ extern crate alloc; +#[cfg(feature = "runtime-benchmarks")] +use pallet_asset_rate::AssetKindFactory; +#[cfg(feature = "runtime-benchmarks")] +use pallet_treasury::ArgumentsFactory; +#[cfg(feature = "runtime-benchmarks")] +use polkadot_sdk::sp_core::crypto::FromEntropy; + use polkadot_sdk::*; use alloc::{vec, vec::Vec}; @@ -76,8 +83,10 @@ use pallet_identity::legacy::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; +use pallet_nomination_pools::PoolId; use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; use pallet_session::historical as pallet_session_historical; +use sp_core::U256; // Can't use `FungibleAdapter` here until Treasury pallet migrates to fungibles // use pallet_broker::TaskId; @@ -95,7 +104,6 @@ use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ - create_runtime_str, curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ @@ -161,8 +169,8 @@ pub fn wasm_binary_unwrap() -> &'static [u8] { /// Runtime version. #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("node"), - impl_name: create_runtime_str!("substrate-node"), + spec_name: alloc::borrow::Cow::Borrowed("node"), + impl_name: alloc::borrow::Cow::Borrowed("substrate-node"), authoring_version: 10, // Per convention: if the runtime behavior changes, increment spec_version // and set impl_version to 0. If only runtime @@ -267,6 +275,36 @@ impl Contains> for TxPauseWhitelistedCalls { } } +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetRateArguments; +#[cfg(feature = "runtime-benchmarks")] +impl AssetKindFactory> for AssetRateArguments { + fn create_asset_kind(seed: u32) -> NativeOrWithId { + if seed % 2 > 0 { + NativeOrWithId::Native + } else { + NativeOrWithId::WithId(seed / 2) + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct PalletTreasuryArguments; +#[cfg(feature = "runtime-benchmarks")] +impl ArgumentsFactory, AccountId> for PalletTreasuryArguments { + fn create_asset_kind(seed: u32) -> NativeOrWithId { + if seed % 2 > 0 { + NativeOrWithId::Native + } else { + NativeOrWithId::WithId(seed / 2) + } + } + + fn create_beneficiary(seed: [u8; 32]) -> AccountId { + AccountId::from_entropy(&mut seed.as_slice()).unwrap() + } +} + impl pallet_tx_pause::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -354,6 +392,7 @@ impl pallet_multisig::Config for Runtime { type DepositFactor = DepositFactor; type MaxSignatories = ConstU32<100>; type WeightInfo = pallet_multisig::weights::SubstrateWeight; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -441,6 +480,7 @@ impl pallet_proxy::Config for Runtime { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -704,7 +744,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; - type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; } impl pallet_fast_unstake::Config for Runtime { @@ -1260,15 +1300,15 @@ impl pallet_treasury::Config for Runtime { type WeightInfo = pallet_treasury::weights::SubstrateWeight; type MaxApprovals = MaxApprovals; type SpendOrigin = EnsureWithSuccess, AccountId, MaxBalance>; - type AssetKind = u32; + type AssetKind = NativeOrWithId; type Beneficiary = AccountId; type BeneficiaryLookup = Indices; - type Paymaster = PayAssetFromAccount; + type Paymaster = PayAssetFromAccount; type BalanceConverter = AssetRate; type PayoutPeriod = SpendPayoutPeriod; type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type BenchmarkHelper = PalletTreasuryArguments; } impl pallet_asset_rate::Config for Runtime { @@ -1276,11 +1316,11 @@ impl pallet_asset_rate::Config for Runtime { type RemoveOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; type Currency = Balances; - type AssetKind = u32; + type AssetKind = NativeOrWithId; type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_asset_rate::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type BenchmarkHelper = AssetRateArguments; } parameter_types! { @@ -1613,6 +1653,7 @@ impl pallet_recovery::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_recovery::weights::SubstrateWeight; type RuntimeCall = RuntimeCall; + type BlockNumberProvider = System; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; @@ -2010,6 +2051,7 @@ impl pallet_nfts::Config for Runtime { type Helper = (); type CreateOrigin = AsEnsureOriginWithArg>; type Locker = (); + type BlockNumberProvider = frame_system::Pallet; } impl pallet_transaction_storage::Config for Runtime { @@ -2968,15 +3010,15 @@ impl_runtime_apis! { NominationPools::api_pending_rewards(who).unwrap_or_default() } - fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { + fn points_to_balance(pool_id: PoolId, points: Balance) -> Balance { NominationPools::api_points_to_balance(pool_id, points) } - fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { + fn balance_to_points(pool_id: PoolId, new_funds: Balance) -> Balance { NominationPools::api_balance_to_points(pool_id, new_funds) } - fn pool_pending_slash(pool_id: pallet_nomination_pools::PoolId) -> Balance { + fn pool_pending_slash(pool_id: PoolId) -> Balance { NominationPools::api_pool_pending_slash(pool_id) } @@ -2984,7 +3026,7 @@ impl_runtime_apis! { NominationPools::api_member_pending_slash(member) } - fn pool_needs_delegate_migration(pool_id: pallet_nomination_pools::PoolId) -> bool { + fn pool_needs_delegate_migration(pool_id: PoolId) -> bool { NominationPools::api_pool_needs_delegate_migration(pool_id) } @@ -2996,9 +3038,13 @@ impl_runtime_apis! { NominationPools::api_member_total_balance(member) } - fn pool_balance(pool_id: pallet_nomination_pools::PoolId) -> Balance { + fn pool_balance(pool_id: PoolId) -> Balance { NominationPools::api_pool_balance(pool_id) } + + fn pool_accounts(pool_id: PoolId) -> (AccountId, AccountId) { + NominationPools::api_pool_accounts(pool_id) + } } impl pallet_staking_runtime_api::StakingApi for Runtime { @@ -3164,9 +3210,8 @@ impl_runtime_apis! { impl pallet_revive::ReviveApi for Runtime { - fn balance(address: H160) -> Balance { - let account = ::AddressMapper::to_account_id(&address); - Balances::usable_balance(account) + fn balance(address: H160) -> U256 { + Revive::evm_balance(&address) } fn nonce(address: H160) -> Nonce { @@ -3174,18 +3219,9 @@ impl_runtime_apis! { System::account_nonce(account) } - fn eth_transact( - from: H160, - dest: Option, - value: Balance, - input: Vec, - gas_limit: Option, - storage_deposit_limit: Option, - ) -> pallet_revive::EthContractResult + fn eth_transact(tx: pallet_revive::evm::GenericTransaction) -> Result, pallet_revive::EthTransactError> { - use pallet_revive::AddressMapper; let blockweights: BlockWeights = ::BlockWeights::get(); - let origin = ::AddressMapper::to_account_id(&from); let encoded_size = |pallet_call| { let call = RuntimeCall::Revive(pallet_call); @@ -3194,15 +3230,9 @@ impl_runtime_apis! { }; Revive::bare_eth_transact( - origin, - dest, - value, - input, - gas_limit.unwrap_or(blockweights.max_block), - storage_deposit_limit.unwrap_or(u128::MAX), + tx, + blockweights.max_block, encoded_size, - pallet_revive::DebugInfo::UnsafeDebug, - pallet_revive::CollectEvents::UnsafeCollect, ) } @@ -3219,7 +3249,7 @@ impl_runtime_apis! { dest, value, gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block), - storage_deposit_limit.unwrap_or(u128::MAX), + pallet_revive::DepositLimit::Balance(storage_deposit_limit.unwrap_or(u128::MAX)), input_data, pallet_revive::DebugInfo::UnsafeDebug, pallet_revive::CollectEvents::UnsafeCollect, @@ -3240,7 +3270,7 @@ impl_runtime_apis! { RuntimeOrigin::signed(origin), value, gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block), - storage_deposit_limit.unwrap_or(u128::MAX), + pallet_revive::DepositLimit::Balance(storage_deposit_limit.unwrap_or(u128::MAX)), code, data, salt, @@ -3575,7 +3605,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch}; use sp_storage::TrackedStorageKey; diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 16112386ad7c..13477a172fb8 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -17,27 +17,26 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true, default-features = true } +frame-metadata-hash-extension = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } fs_extra = { workspace = true } futures = { workspace = true } +kitchensink-runtime = { workspace = true } log = { workspace = true, default-features = true } -tempfile = { workspace = true } -frame-metadata-hash-extension = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } node-cli = { workspace = true } node-primitives = { workspace = true, default-features = true } -kitchensink-runtime = { workspace = true } pallet-asset-conversion = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-revive = { workspace = true, default-features = true } pallet-asset-conversion-tx-payment = { workspace = true, default-features = true } pallet-asset-tx-payment = { workspace = true, default-features = true } +pallet-assets = { workspace = true, default-features = true } +pallet-revive = { workspace = true, default-features = true } pallet-skip-feeless-payment = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-client-db = { features = ["rocksdb"], workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } -sc-service = { features = ["rocksdb", "test-helpers"], workspace = true, default-features = true } +sc-service = { features = ["rocksdb"], workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } @@ -50,3 +49,4 @@ sp-keyring = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-timestamp = { workspace = true } substrate-test-client = { workspace = true } +tempfile = { workspace = true } diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 3812524f0b1f..35f041ef0445 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -590,7 +590,6 @@ impl BenchKeyring { preamble: Preamble::Signed( sp_runtime::MultiAddress::Id(signed), signature, - 0, tx_ext, ), function: payload.0, @@ -602,8 +601,8 @@ impl BenchKeyring { function: xt.function, } .into(), - ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(0, tx_ext), + ExtrinsicFormat::General(ext_version, tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(ext_version, tx_ext), function: xt.function, } .into(), diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index 20497e85eab9..e5b0299f01a8 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -123,7 +123,6 @@ pub fn sign( preamble: sp_runtime::generic::Preamble::Signed( sp_runtime::MultiAddress::Id(signed), signature, - 0, tx_ext, ), function: payload.0, @@ -135,8 +134,8 @@ pub fn sign( function: xt.function, } .into(), - ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(0, tx_ext), + ExtrinsicFormat::General(ext_version, tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(ext_version, tx_ext), function: xt.function, } .into(), diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index b71e935a918f..f3adc5682969 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -34,14 +34,14 @@ log = { workspace = true, default-features = true } sc-chain-spec = { features = [ "clap", ], workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } [dev-dependencies] -substrate-test-runtime = { workspace = true } cmd_lib = { workspace = true } docify = { workspace = true } +substrate-test-runtime = { workspace = true } [features] # `cargo build --feature=generate-readme` updates the `README.md` file. diff --git a/substrate/bin/utils/chain-spec-builder/README.docify.md b/substrate/bin/utils/chain-spec-builder/README.docify.md index bb4db4c666e0..75d05bccfe0d 100644 --- a/substrate/bin/utils/chain-spec-builder/README.docify.md +++ b/substrate/bin/utils/chain-spec-builder/README.docify.md @@ -73,6 +73,8 @@ storage (`-s`) version of chain spec: +Refer to [*patch file*](#patch-file) for some details on the patch file format. + _Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) and [`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state) @@ -84,6 +86,8 @@ Build the chain spec using provided full genesis config json file. No defaults w +Refer to [*full config file*](#full-genesis-config-file) for some details on the full file format. + _Note_: [`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state) runtime function is called. @@ -91,10 +95,50 @@ runtime function is called. +Refer to [*patch file*](#patch-file) for some details on the patch file format. + ### Generate human readable chain spec using provided full genesis config +Refer to [*full config file*](#full-genesis-config-file) for some details on the full file format. + + +## Patch and full genesis config files +This section provides details on the files that can be used with `create patch` or `create full` subcommands. + +### Patch file +The patch file for genesis config contains the key-value pairs valid for given runtime, that needs to be customized, + e.g: +```ignore +{ + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "sudo": { + "key": "5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo" + } +} +``` +The rest of genesis config keys will be initialized with default values. + +### Full genesis config file +The full genesis config file must contain values for *all* the keys present in the genesis config for given runtime. The +format of the file is similar to patch format. Example is not provided here as it heavily depends on the runtime. + ### Extra tools The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.VerifyCmd.html), diff --git a/substrate/bin/utils/chain-spec-builder/README.md b/substrate/bin/utils/chain-spec-builder/README.md index e03c710ce1b3..a85b37826139 100644 --- a/substrate/bin/utils/chain-spec-builder/README.md +++ b/substrate/bin/utils/chain-spec-builder/README.md @@ -99,6 +99,8 @@ bash!( ) ``` +Refer to [*patch file*](#patch-file) for some details on the patch file format. + _Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) and [`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state) @@ -114,6 +116,8 @@ bash!( ) ``` +Refer to [*full config file*](#full-genesis-config-file) for some details on the full file format. + _Note_: [`GenesisBuilder::build_state`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.build_state) runtime function is called. @@ -125,6 +129,8 @@ bash!( ) ``` +Refer to [*patch file*](#patch-file) for some details on the patch file format. + ### Generate human readable chain spec using provided full genesis config ```rust,ignore @@ -133,6 +139,44 @@ bash!( ) ``` +Refer to [*full config file*](#full-genesis-config-file) for some details on the full file format. + + +## Patch and full genesis config files +This section provides details on the files that can be used with `create patch` or `create full` subcommands. + +### Patch file +The patch file for genesis config contains the key-value pairs valid for given runtime, that needs to be customized, + e.g: +```ignore +{ + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "sudo": { + "key": "5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo" + } +} +``` +The rest of genesis config keys will be initialized with default values. + +### Full genesis config file +The full genesis config file must contain values for *all* the keys present in the genesis config for given runtime. The +format of the file is similar to patch format. Example is not provided here as it heavily depends on the runtime. + ### Extra tools The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.VerifyCmd.html), diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 98ff480b8ceb..73c2868b3312 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -261,19 +261,19 @@ impl ChainSpecBuilder { .map_err(|e| format!("Conversion to json failed: {e}"))?; // We want to extract only raw genesis ("genesis::raw" key), and apply it as a patch - // for the original json file. However, the file also contains original plain - // genesis ("genesis::runtimeGenesis") so set it to null so the patch will erase it. + // for the original json file. genesis_json.as_object_mut().map(|map| { map.retain(|key, _| key == "genesis"); - map.get_mut("genesis").map(|genesis| { - genesis.as_object_mut().map(|genesis_map| { - genesis_map - .insert("runtimeGenesis".to_string(), serde_json::Value::Null); - }); - }); }); let mut org_chain_spec_json = extract_chain_spec_json(input_chain_spec.as_path())?; + + // The original plain genesis ("genesis::runtimeGenesis") is no longer needed, so + // just remove it: + org_chain_spec_json + .get_mut("genesis") + .and_then(|genesis| genesis.as_object_mut()) + .and_then(|genesis| genesis.remove("runtimeGenesis")); json_patch::merge(&mut org_chain_spec_json, genesis_json); let chain_spec_json = serde_json::to_string_pretty(&org_chain_spec_json) @@ -293,16 +293,6 @@ impl ChainSpecBuilder { let presets = caller .preset_names() .map_err(|e| format!("getting default config from runtime should work: {e}"))?; - let presets: Vec = presets - .into_iter() - .map(|preset| { - String::from( - TryInto::<&str>::try_into(&preset) - .unwrap_or_else(|_| "cannot display preset id") - .to_string(), - ) - }) - .collect(); println!("{}", serde_json::json!({"presets":presets}).to_string()); }, ChainSpecBuilderCmd::DisplayPreset(DisplayPresetCmd { runtime, preset_name }) => { diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index a8b3bdc864c9..c0ce640566b0 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -18,6 +18,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true, default-features = true } -thiserror = { workspace = true } sp-core = { workspace = true, default-features = true } sp-wasm-interface = { workspace = true, default-features = true } +thiserror = { workspace = true } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index 670c74684467..fe961b4690fc 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -41,6 +41,6 @@ sp-storage = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } [dev-dependencies] -thiserror = { workspace = true } sp-test-primitives = { workspace = true } substrate-test-runtime = { workspace = true } +thiserror = { workspace = true } diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 09381ec6b553..ac1891451ec0 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -20,18 +20,17 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = { workspace = true } [dependencies] +async-trait = { workspace = true } codec = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } ip_network = { workspace = true } -libp2p = { features = ["ed25519", "kad"], workspace = true } -multihash = { workspace = true } linked_hash_set = { workspace = true } log = { workspace = true, default-features = true } +multihash = { workspace = true } +prometheus-endpoint = { workspace = true, default-features = true } prost = { workspace = true } rand = { workspace = true, default-features = true } -thiserror = { workspace = true } -prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } @@ -41,7 +40,7 @@ sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -async-trait = { workspace = true } +thiserror = { workspace = true } [dev-dependencies] quickcheck = { workspace = true } diff --git a/substrate/client/authority-discovery/src/tests.rs b/substrate/client/authority-discovery/src/tests.rs index acfd0e61de01..a73515ee00d2 100644 --- a/substrate/client/authority-discovery/src/tests.rs +++ b/substrate/client/authority-discovery/src/tests.rs @@ -25,7 +25,7 @@ use crate::{ }; use futures::{channel::mpsc::channel, executor::LocalPool, task::LocalSpawn}; -use libp2p::identity::ed25519; +use sc_network_types::ed25519; use std::{collections::HashSet, sync::Arc}; use sc_network::{multiaddr::Protocol, Multiaddr, PeerId}; diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 6f4fbac77e05..6630b7157d96 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -34,8 +34,8 @@ use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt} use addr_cache::AddrCache; use codec::{Decode, Encode}; use ip_network::IpNetwork; -use libp2p::kad::{PeerRecord, Record}; use linked_hash_set::LinkedHashSet; +use sc_network_types::kad::{Key, PeerRecord, Record}; use log::{debug, error, trace}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64}; @@ -71,7 +71,13 @@ pub mod tests; const LOG_TARGET: &str = "sub-authority-discovery"; /// Maximum number of addresses cached per authority. Additional addresses are discarded. -const MAX_ADDRESSES_PER_AUTHORITY: usize = 10; +const MAX_ADDRESSES_PER_AUTHORITY: usize = 16; + +/// Maximum number of global listen addresses published by the node. +const MAX_GLOBAL_LISTEN_ADDRESSES: usize = 4; + +/// Maximum number of addresses to publish in a single record. +const MAX_ADDRESSES_TO_PUBLISH: usize = 32; /// Maximum number of in-flight DHT lookups at any given point in time. const MAX_IN_FLIGHT_LOOKUPS: usize = 8; @@ -174,6 +180,9 @@ pub struct Worker { metrics: Option, + /// Flag to ensure the warning about missing public addresses is only printed once. + warn_public_addresses: bool, + role: Role, phantom: PhantomData, @@ -271,20 +280,7 @@ where config .public_addresses .into_iter() - .map(|mut address| { - if let Some(multiaddr::Protocol::P2p(peer_id)) = address.iter().last() { - if peer_id != *local_peer_id.as_ref() { - error!( - target: LOG_TARGET, - "Discarding invalid local peer ID in public address {address}.", - ); - } - // Always discard `/p2p/...` protocol for proper address comparison (local - // peer id will be added before publishing). - address.pop(); - } - address - }) + .map(|address| AddressType::PublicAddress(address).without_p2p(local_peer_id)) .collect() }; @@ -309,6 +305,7 @@ where addr_cache, role, metrics, + warn_public_addresses: false, phantom: PhantomData, last_known_records: HashMap::new(), } @@ -373,47 +370,70 @@ where } } - fn addresses_to_publish(&self) -> impl Iterator { + fn addresses_to_publish(&mut self) -> impl Iterator { let local_peer_id = self.network.local_peer_id(); let publish_non_global_ips = self.publish_non_global_ips; + + // Checks that the address is global. + let address_is_global = |address: &Multiaddr| { + address.iter().all(|protocol| match protocol { + // The `ip_network` library is used because its `is_global()` method is stable, + // while `is_global()` in the standard library currently isn't. + multiaddr::Protocol::Ip4(ip) => IpNetwork::from(ip).is_global(), + multiaddr::Protocol::Ip6(ip) => IpNetwork::from(ip).is_global(), + _ => true, + }) + }; + + // These are the addresses the node is listening for incoming connections, + // as reported by installed protocols (tcp / websocket etc). + // + // We double check the address is global. In other words, we double check the node + // is not running behind a NAT. + // Note: we do this regardless of the `publish_non_global_ips` setting, since the + // node discovers many external addresses via the identify protocol. + let mut global_listen_addresses = self + .network + .listen_addresses() + .into_iter() + .filter_map(|address| { + address_is_global(&address) + .then(|| AddressType::GlobalListenAddress(address).without_p2p(local_peer_id)) + }) + .take(MAX_GLOBAL_LISTEN_ADDRESSES) + .peekable(); + + // Similar to listen addresses that takes into consideration `publish_non_global_ips`. + let mut external_addresses = self + .network + .external_addresses() + .into_iter() + .filter_map(|address| { + (publish_non_global_ips || address_is_global(&address)) + .then(|| AddressType::ExternalAddress(address).without_p2p(local_peer_id)) + }) + .peekable(); + + let has_global_listen_addresses = global_listen_addresses.peek().is_some(); + trace!( + target: LOG_TARGET, + "Node has public addresses: {}, global listen addresses: {}, external addresses: {}", + !self.public_addresses.is_empty(), + has_global_listen_addresses, + external_addresses.peek().is_some(), + ); + + let mut seen_addresses = HashSet::new(); + let addresses = self .public_addresses .clone() .into_iter() - .chain(self.network.external_addresses().into_iter().filter_map(|mut address| { - // Make sure the reported external address does not contain `/p2p/...` protocol. - if let Some(multiaddr::Protocol::P2p(peer_id)) = address.iter().last() { - if peer_id != *local_peer_id.as_ref() { - error!( - target: LOG_TARGET, - "Network returned external address '{address}' with peer id \ - not matching the local peer id '{local_peer_id}'.", - ); - debug_assert!(false); - } - address.pop(); - } - - if self.public_addresses.contains(&address) { - // Already added above. - None - } else { - Some(address) - } - })) - .filter(move |address| { - if publish_non_global_ips { - return true - } - - address.iter().all(|protocol| match protocol { - // The `ip_network` library is used because its `is_global()` method is stable, - // while `is_global()` in the standard library currently isn't. - multiaddr::Protocol::Ip4(ip) if !IpNetwork::from(ip).is_global() => false, - multiaddr::Protocol::Ip6(ip) if !IpNetwork::from(ip).is_global() => false, - _ => true, - }) - }) + .chain(global_listen_addresses) + .chain(external_addresses) + // Deduplicate addresses. + .filter(|address| seen_addresses.insert(address.clone())) + .take(MAX_ADDRESSES_TO_PUBLISH) .collect::>(); if !addresses.is_empty() { @@ -421,6 +441,21 @@ where target: LOG_TARGET, "Publishing authority DHT record peer_id='{local_peer_id}' with addresses='{addresses:?}'", ); + + if !self.warn_public_addresses && + self.public_addresses.is_empty() && + !has_global_listen_addresses + { + self.warn_public_addresses = true; + + error!( + target: LOG_TARGET, + "No public addresses configured and no global listen addresses found. \ + Authority DHT record may contain unreachable addresses. \ + Consider setting `--public-addr` to the public IP address of this node. \ + This will become a hard requirement in future versions for authorities." + ); + } } // The address must include the local peer id. @@ -437,7 +472,8 @@ where let key_store = match &self.role { Role::PublishAndDiscover(key_store) => key_store, Role::Discover => return Ok(()), - }; + } + .clone(); let addresses = serialize_addresses(self.addresses_to_publish()); if addresses.is_empty() { @@ -641,12 +677,15 @@ where metrics.dht_event_received.with_label_values(&["put_record_req"]).inc(); } }, + DhtEvent::StartProvidingFailed(..) => {}, + DhtEvent::ProvidersFound(..) => {}, + DhtEvent::ProvidersNotFound(..) => {}, } } async fn handle_put_record_requested( &mut self, - record_key: KademliaKey, + record_key: Key, record_value: Vec, publisher: Option, expires: Option, @@ -907,7 +946,7 @@ where authority_id, new_record.creation_time, current_record_info.creation_time, ); self.network.put_record_to( - current_record_info.record.clone(), + current_record_info.record.clone().into(), new_record.peers_with_record.clone(), // If this is empty it means we received the answer from our node local // storage, so we need to update that as well. @@ -946,6 +985,44 @@ where } } +/// Removes the `/p2p/..` from the address if it is present. +#[derive(Debug, Clone, PartialEq, Eq)] +enum AddressType { + /// The address is specified as a public address via the CLI. + PublicAddress(Multiaddr), + /// The address is a global listen address. + GlobalListenAddress(Multiaddr), + /// The address is discovered via the network (ie /identify protocol). + ExternalAddress(Multiaddr), +} + +impl AddressType { + /// Removes the `/p2p/..` from the address if it is present. + /// + /// In case the peer id in the address does not match the local peer id, an error is logged for + /// `ExternalAddress` and `GlobalListenAddress`. + fn without_p2p(self, local_peer_id: PeerId) -> Multiaddr { + // Get the address and the source str for logging. + let (mut address, source) = match self { + AddressType::PublicAddress(address) => (address, "public address"), + AddressType::GlobalListenAddress(address) => (address, "global listen address"), + AddressType::ExternalAddress(address) => (address, "external address"), + }; + + if let Some(multiaddr::Protocol::P2p(peer_id)) = address.iter().last() { + if peer_id != *local_peer_id.as_ref() { + error!( + target: LOG_TARGET, + "Network returned '{source}' '{address}' with peer id \ + not matching the local peer id '{local_peer_id}'.", + ); + } + address.pop(); + } + address + } +} + /// NetworkProvider provides [`Worker`] with all necessary hooks into the /// underlying Substrate networking. Using this trait abstraction instead of /// `sc_network::NetworkService` directly is necessary to unit test [`Worker`]. diff --git a/substrate/client/authority-discovery/src/worker/schema/tests.rs b/substrate/client/authority-discovery/src/worker/schema/tests.rs index 557fa9641f97..1dff1b93e06d 100644 --- a/substrate/client/authority-discovery/src/worker/schema/tests.rs +++ b/substrate/client/authority-discovery/src/worker/schema/tests.rs @@ -26,9 +26,9 @@ mod schema_v2 { use super::*; use codec::Encode; -use libp2p::identity::Keypair; use prost::Message; use sc_network::{Multiaddr, PeerId}; +use sc_network_types::ed25519::Keypair; #[test] fn v2_decodes_v1() { @@ -61,7 +61,7 @@ fn v2_decodes_v1() { #[test] fn v1_decodes_v2() { - let peer_secret = Keypair::generate_ed25519(); + let peer_secret = Keypair::generate(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = @@ -73,7 +73,7 @@ fn v1_decodes_v2() { let record_v2 = schema_v2::AuthorityRecord { addresses: vec_addresses.clone() }; let mut vec_record_v2 = vec![]; record_v2.encode(&mut vec_record_v2).unwrap(); - let vec_peer_public = peer_public.encode_protobuf(); + let vec_peer_public = peer_public.to_bytes().to_vec(); let peer_signature_v2 = PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; let signed_record_v2 = SignedAuthorityRecord { @@ -97,7 +97,7 @@ fn v1_decodes_v2() { #[test] fn v1_decodes_v3() { - let peer_secret = Keypair::generate_ed25519(); + let peer_secret = Keypair::generate(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = @@ -112,7 +112,7 @@ fn v1_decodes_v3() { }; let mut vec_record_v3 = vec![]; record_v3.encode(&mut vec_record_v3).unwrap(); - let vec_peer_public = peer_public.encode_protobuf(); + let vec_peer_public = peer_public.to_bytes().to_vec(); let peer_signature_v3 = PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; let signed_record_v3 = SignedAuthorityRecord { @@ -136,7 +136,7 @@ fn v1_decodes_v3() { #[test] fn v3_decodes_v2() { - let peer_secret = Keypair::generate_ed25519(); + let peer_secret = Keypair::generate(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = @@ -148,7 +148,7 @@ fn v3_decodes_v2() { let record_v2 = schema_v2::AuthorityRecord { addresses: vec_addresses.clone() }; let mut vec_record_v2 = vec![]; record_v2.encode(&mut vec_record_v2).unwrap(); - let vec_peer_public = peer_public.encode_protobuf(); + let vec_peer_public = peer_public.to_bytes().to_vec(); let peer_signature_v2 = schema_v2::PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; let signed_record_v2 = schema_v2::SignedAuthorityRecord { diff --git a/substrate/client/authority-discovery/src/worker/tests.rs b/substrate/client/authority-discovery/src/worker/tests.rs index d71a85db8b81..c14771585655 100644 --- a/substrate/client/authority-discovery/src/worker/tests.rs +++ b/substrate/client/authority-discovery/src/worker/tests.rs @@ -30,12 +30,14 @@ use futures::{ sink::SinkExt, task::LocalSpawn, }; -use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; use prometheus_endpoint::prometheus::default_registry; - use sc_client_api::HeaderBackend; -use sc_network::{service::signature::Keypair, Signature}; +use sc_network::{ + service::signature::{Keypair, SigningError}, + PublicKey, Signature, +}; use sc_network_types::{ + kad::Key as KademliaKey, multiaddr::{Multiaddr, Protocol}, PeerId, }; @@ -178,8 +180,8 @@ impl NetworkSigner for TestNetwork { signature: &Vec, message: &Vec, ) -> std::result::Result { - let public_key = libp2p::identity::PublicKey::try_decode_protobuf(&public_key) - .map_err(|error| error.to_string())?; + let public_key = + PublicKey::try_decode_protobuf(&public_key).map_err(|error| error.to_string())?; let peer_id: PeerId = peer_id.into(); let remote: PeerId = public_key.to_peer_id().into(); @@ -229,6 +231,18 @@ impl NetworkDHTProvider for TestNetwork { .unbounded_send(TestNetworkEvent::StoreRecordCalled) .unwrap(); } + + fn start_providing(&self, _: KademliaKey) { + unimplemented!() + } + + fn stop_providing(&self, _: KademliaKey) { + unimplemented!() + } + + fn get_providers(&self, _: KademliaKey) { + unimplemented!() + } } impl NetworkStateInfo for TestNetwork { @@ -1018,7 +1032,7 @@ fn addresses_to_publish_adds_p2p() { )); let (_to_worker, from_service) = mpsc::channel(0); - let worker = Worker::new( + let mut worker = Worker::new( from_service, Arc::new(TestApi { authorities: vec![] }), network.clone(), @@ -1056,7 +1070,7 @@ fn addresses_to_publish_respects_existing_p2p_protocol() { }); let (_to_worker, from_service) = mpsc::channel(0); - let worker = Worker::new( + let mut worker = Worker::new( from_service, Arc::new(TestApi { authorities: vec![] }), network.clone(), diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 79e6fddae99f..2096af1c25bb 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -483,7 +483,7 @@ where match sc_block_builder::BlockBuilder::push(block_builder, pending_tx_data) { Ok(()) => { transaction_pushed = true; - debug!(target: LOG_TARGET, "[{:?}] Pushed to the block.", pending_tx_hash); + trace!(target: LOG_TARGET, "[{:?}] Pushed to the block.", pending_tx_hash); }, Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() => { pending_iterator.report_invalid(&pending_tx); @@ -565,20 +565,22 @@ where if log::log_enabled!(log::Level::Info) { info!( - "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; extrinsics_count: {}", + "🎁 Prepared block for proposing at {} ({} ms) hash: {:?}; parent_hash: {}; end: {:?}; extrinsics_count: {}", block.header().number(), block_took.as_millis(), ::Hash::from(block.header().hash()), block.header().parent_hash(), + end_reason, extrinsics.len() ) - } else if log::log_enabled!(log::Level::Debug) { - debug!( - "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; {extrinsics_summary}", + } else if log::log_enabled!(log::Level::Trace) { + trace!( + "🎁 Prepared block for proposing at {} ({} ms) hash: {:?}; parent_hash: {}; end: {:?}; {extrinsics_summary}", block.header().number(), block_took.as_millis(), ::Hash::from(block.header().hash()), block.header().parent_hash(), + end_reason ); } @@ -908,8 +910,8 @@ mod tests { let extrinsics_num = 5; let extrinsics = std::iter::once( Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), amount: 100, nonce: 0, } @@ -1014,7 +1016,7 @@ mod tests { }; let huge = |who| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(HUGE)) - .signer(AccountKeyring::numeric(who)) + .signer(Sr25519Keyring::numeric(who)) .build() }; @@ -1080,13 +1082,13 @@ mod tests { let tiny = |who| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY)) - .signer(AccountKeyring::numeric(who)) + .signer(Sr25519Keyring::numeric(who)) .nonce(1) .build() }; let huge = |who| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(HUGE)) - .signer(AccountKeyring::numeric(who)) + .signer(Sr25519Keyring::numeric(who)) .build() }; diff --git a/substrate/client/basic-authorship/src/lib.rs b/substrate/client/basic-authorship/src/lib.rs index adea7a3571dd..13c75fd08c3c 100644 --- a/substrate/client/basic-authorship/src/lib.rs +++ b/substrate/client/basic-authorship/src/lib.rs @@ -26,7 +26,7 @@ //! # use sp_runtime::generic::BlockId; //! # use std::{sync::Arc, time::Duration}; //! # use substrate_test_runtime_client::{ -//! # runtime::Transfer, AccountKeyring, +//! # runtime::Transfer, Sr25519Keyring, //! # DefaultTestClientBuilderExt, TestClientBuilderExt, //! # }; //! # use sc_transaction_pool::{BasicPool, FullChainApi}; diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 08392e18227f..c61a5a7ad3c1 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -23,9 +23,9 @@ sp-api = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-trie = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } [dev-dependencies] sp-state-machine = { workspace = true, default-features = true } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 2e885240936f..f63ff6c64447 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -16,31 +16,31 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = { workspace = true, default-features = true } clap = { features = ["derive"], optional = true, workspace = true } codec = { features = ["derive"], workspace = true } +docify = { workspace = true } +log = { workspace = true } memmap2 = { workspace = true } -serde = { features = ["derive"], workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } sc-chain-spec-derive = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } -sp-io = { workspace = true } sc-network = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } +sp-io = { workspace = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } -log = { workspace = true } sp-tracing = { workspace = true, default-features = true } -array-bytes = { workspace = true, default-features = true } -docify = { workspace = true } [dev-dependencies] -substrate-test-runtime = { workspace = true } -sp-keyring = { workspace = true, default-features = true } +regex = { workspace = true } sp-application-crypto = { features = ["serde"], workspace = true } sp-consensus-babe = { features = ["serde"], workspace = true } -regex = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +substrate-test-runtime = { workspace = true } diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index aa3c1ba3e6f1..fa161f1202ab 100644 --- a/substrate/client/chain-spec/src/chain_spec.rs +++ b/substrate/client/chain-spec/src/chain_spec.rs @@ -782,7 +782,7 @@ mod tests { use serde_json::{from_str, json, Value}; use sp_application_crypto::Ss58Codec; use sp_core::storage::well_known_keys; - use sp_keyring::AccountKeyring; + use sp_keyring::Sr25519Keyring; type TestSpec = ChainSpec; @@ -924,8 +924,8 @@ mod tests { }, "substrateTest": { "authorities": [ - AccountKeyring::Ferdie.public().to_ss58check(), - AccountKeyring::Alice.public().to_ss58check() + Sr25519Keyring::Ferdie.public().to_ss58check(), + Sr25519Keyring::Alice.public().to_ss58check() ], } })) @@ -980,8 +980,8 @@ mod tests { }, "substrateTest": { "authorities": [ - AccountKeyring::Ferdie.public().to_ss58check(), - AccountKeyring::Alice.public().to_ss58check() + Sr25519Keyring::Ferdie.public().to_ss58check(), + Sr25519Keyring::Alice.public().to_ss58check() ], } })) @@ -1083,8 +1083,8 @@ mod tests { "invalid_pallet": {}, "substrateTest": { "authorities": [ - AccountKeyring::Ferdie.public().to_ss58check(), - AccountKeyring::Alice.public().to_ss58check() + Sr25519Keyring::Ferdie.public().to_ss58check(), + Sr25519Keyring::Alice.public().to_ss58check() ], } })) diff --git a/substrate/client/chain-spec/src/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs index 66989495d423..5fe8f9dc053c 100644 --- a/substrate/client/chain-spec/src/genesis_config_builder.rs +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -142,11 +142,9 @@ where /// The patching process modifies the default `RuntimeGenesisConfig` according to the following /// rules: /// 1. Existing keys in the default configuration will be overridden by the corresponding values - /// in the patch. + /// in the patch (also applies to `null` values). /// 2. If a key exists in the patch but not in the default configuration, it will be added to /// the resulting `RuntimeGenesisConfig`. - /// 3. Keys in the default configuration that have null values in the patch will be removed from - /// the resulting `RuntimeGenesisConfig`. This is helpful for changing enum variant value. /// /// Please note that the patch may contain full `RuntimeGenesisConfig`. pub fn get_storage_for_patch(&self, patch: Value) -> core::result::Result { diff --git a/substrate/client/chain-spec/src/json_patch.rs b/substrate/client/chain-spec/src/json_patch.rs index c3930069a60d..a223792374e0 100644 --- a/substrate/client/chain-spec/src/json_patch.rs +++ b/substrate/client/chain-spec/src/json_patch.rs @@ -22,9 +22,10 @@ use serde_json::Value; /// Recursively merges two JSON objects, `a` and `b`, into a single object. /// -/// If a key exists in both objects, the value from `b` will override the value from `a`. -/// If a key exists in `b` with a `null` value, it will be removed from `a`. +/// If a key exists in both objects, the value from `b` will override the value from `a` (also if +/// value in `b` is `null`). /// If a key exists only in `b` and not in `a`, it will be added to `a`. +/// No keys will be removed from `a`. /// /// # Arguments /// @@ -34,11 +35,7 @@ pub fn merge(a: &mut Value, b: Value) { match (a, b) { (Value::Object(a), Value::Object(b)) => for (k, v) in b { - if v.is_null() { - a.remove(&k); - } else { - merge(a.entry(k).or_insert(Value::Null), v); - } + merge(a.entry(k).or_insert(Value::Null), v); }, (a, b) => *a = b, }; @@ -166,7 +163,7 @@ mod tests { } #[test] - fn test6_patch_removes_keys_if_null() { + fn test6_patch_does_not_remove_keys_if_null() { let mut j1 = json!({ "a": { "name": "xxx", @@ -186,6 +183,16 @@ mod tests { }); merge(&mut j1, j2); - assert_eq!(j1, json!({ "a": {"name":"xxx", "value":456, "enum_variant_2": 32 }})); + assert_eq!( + j1, + json!({ + "a": { + "name":"xxx", + "value":456, + "enum_variant_1": null, + "enum_variant_2": 32 + } + }) + ); } } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index f0b9f8f9b905..d7b4489b6cc5 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = { workspace = true, default-features = true } chrono = { workspace = true } clap = { features = ["derive", "string", "wrap_help"], workspace = true } +codec = { workspace = true, default-features = true } fdlimit = { workspace = true } futures = { workspace = true } itertools = { workspace = true } libp2p-identity = { features = ["ed25519", "peerid"], workspace = true } log = { workspace = true, default-features = true } names = { workspace = true } -codec = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } regex = { workspace = true } rpassword = { workspace = true } @@ -34,7 +34,6 @@ serde_json = { workspace = true, default-features = true } thiserror = { 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", features = ["rand"] } -tokio = { features = ["parking_lot", "rt-multi-thread", "signal"], workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-client-db = { workspace = true } sc-keystore = { workspace = true, default-features = true } @@ -52,11 +51,12 @@ sp-keystore = { workspace = true, default-features = true } sp-panic-handler = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } +tokio = { features = ["parking_lot", "rt-multi-thread", "signal"], workspace = true, default-features = true } [dev-dependencies] -tempfile = { workspace = true } futures-timer = { workspace = true } sp-tracing = { workspace = true, default-features = true } +tempfile = { workspace = true } [features] default = ["rocksdb"] diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index f91d18aca749..f79e5b558e37 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -201,17 +201,7 @@ impl CliConfiguration for RunCmd { } fn network_params(&self) -> Option<&NetworkParams> { - let network_params = &self.network_params; - let is_authority = self.role(self.is_dev().ok()?).ok()?.is_authority(); - if is_authority && network_params.public_addr.is_empty() { - eprintln!( - "WARNING: No public address specified, validator node may not be reachable. - Consider setting `--public-addr` to the public IP address of this node. - This will become a hard requirement in future versions." - ); - } - - Some(network_params) + Some(&self.network_params) } fn keystore_params(&self) -> Option<&KeystoreParams> { diff --git a/substrate/client/cli/src/params/import_params.rs b/substrate/client/cli/src/params/import_params.rs index add7cb4f8505..e4b8b9644feb 100644 --- a/substrate/client/cli/src/params/import_params.rs +++ b/substrate/client/cli/src/params/import_params.rs @@ -78,21 +78,13 @@ pub struct ImportParams { /// Specify the state cache size. /// /// Providing `0` will disable the cache. - #[arg(long, value_name = "Bytes", default_value_t = 67108864)] + #[arg(long, value_name = "Bytes", default_value_t = 1024 * 1024 * 1024)] pub trie_cache_size: usize, - - /// DEPRECATED: switch to `--trie-cache-size`. - #[arg(long)] - state_cache_size: Option, } impl ImportParams { /// Specify the trie cache maximum size. pub fn trie_cache_maximum_size(&self) -> Option { - if self.state_cache_size.is_some() { - eprintln!("`--state-cache-size` was deprecated. Please switch to `--trie-cache-size`."); - } - if self.trie_cache_size == 0 { None } else { diff --git a/substrate/client/cli/src/params/shared_params.rs b/substrate/client/cli/src/params/shared_params.rs index 465372fba17d..e0c52deb44ca 100644 --- a/substrate/client/cli/src/params/shared_params.rs +++ b/substrate/client/cli/src/params/shared_params.rs @@ -33,10 +33,12 @@ pub struct SharedParams { /// Specify the development chain. /// - /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, - /// `--alice`, and `--tmp` flags, unless explicitly overridden. - /// It also disables local peer discovery (see --no-mdns and --discover-local) - #[arg(long, conflicts_with_all = &["chain"])] + /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, `--alice`, and `--tmp` + /// flags, unless explicitly overridden. It also disables local peer discovery (see `--no-mdns` + /// and `--discover-local`). With this flag some nodes might start with manual seal, producing + /// blocks at certain events (e.g. `polkadot-omni-node`, which produces blocks at certain + /// intervals dictated by `--dev-block-time`). + #[arg(long)] pub dev: bool, /// Specify custom base path. @@ -109,12 +111,8 @@ impl SharedParams { pub fn chain_id(&self, is_dev: bool) -> String { match self.chain { Some(ref chain) => chain.clone(), - None => - if is_dev { - "dev".into() - } else { - "".into() - }, + None if is_dev => "dev".into(), + _ => "".into(), } } diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index 98e8ad676be3..6af673617118 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -20,7 +20,6 @@ async-trait = { workspace = true } codec = { workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true, default-features = true } -thiserror = { workspace = true } prometheus-endpoint = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } @@ -38,10 +37,10 @@ sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] parking_lot = { workspace = true, default-features = true } -tempfile = { workspace = true } sc-keystore = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-test = { workspace = true } @@ -49,4 +48,5 @@ sp-keyring = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +tempfile = { workspace = true } tokio = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index af55e72a9b7e..305409b80c78 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -19,14 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { workspace = true } codec = { features = ["derive"], workspace = true, default-features = true } +fork-tree = { workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true, default-features = true } num-bigint = { workspace = true } num-rational = { workspace = true } num-traits = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -thiserror = { workspace = true } -fork-tree = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } @@ -46,11 +45,12 @@ sp-crypto-hashing = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] sc-block-builder = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } sc-network-test = { workspace = true } +sp-keyring = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index ce5b1baec0b5..3e3834189938 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -16,13 +16,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } futures = { workspace = true } -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } sc-consensus-babe = { workspace = true, default-features = true } sc-consensus-epochs = { workspace = true, default-features = true } sc-rpc-api = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } @@ -31,12 +30,13 @@ sp-consensus-babe = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] -serde_json = { workspace = true, default-features = true } -tokio = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-keystore = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 900a44b95e04..bfe7e2c3d5dc 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -20,8 +20,6 @@ fnv = { workspace = true } futures = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -thiserror = { workspace = true } -wasm-timer = { workspace = true } prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } @@ -40,18 +38,20 @@ sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } tokio = { workspace = true, default-features = true } +wasm-timer = { workspace = true } [dev-dependencies] -serde = { workspace = true, default-features = true } -tempfile = { workspace = true } sc-block-builder = { workspace = true, default-features = true } sc-network-test = { workspace = true } +serde = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-mmr-primitives = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +tempfile = { workspace = true } [features] # This feature adds BLS crypto primitives. It should not be used in production since diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index e1956dacf396..f8f24250ad93 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -17,17 +17,17 @@ futures = { workspace = true } jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } sc-consensus-beefy = { workspace = true, default-features = true } -sp-consensus-beefy = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +sp-application-crypto = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-application-crypto = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] -serde_json = { workspace = true, default-features = true } sc-rpc = { features = ["test-helpers"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index 77cd50ad784b..1b0f799f81bc 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -21,18 +21,18 @@ futures = { features = ["thread-pool"], workspace = true } log = { workspace = true, default-features = true } mockall = { workspace = true } parking_lot = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] sp-test-primitives = { workspace = true } diff --git a/substrate/client/consensus/common/src/import_queue.rs b/substrate/client/consensus/common/src/import_queue.rs index 1baa67398a49..602683907d48 100644 --- a/substrate/client/consensus/common/src/import_queue.rs +++ b/substrate/client/consensus/common/src/import_queue.rs @@ -107,7 +107,7 @@ pub trait Verifier: Send + Sync { /// /// The `import_*` methods can be called in order to send elements for the import queue to verify. pub trait ImportQueueService: Send { - /// Import bunch of blocks, every next block must be an ancestor of the previous block in the + /// Import a bunch of blocks, every next block must be an ancestor of the previous block in the /// list. fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec>); @@ -132,21 +132,21 @@ pub trait ImportQueue: Send { /// This method should behave in a way similar to `Future::poll`. It can register the current /// task and notify later when more actions are ready to be polled. To continue the comparison, /// it is as if this method always returned `Poll::Pending`. - fn poll_actions(&mut self, cx: &mut futures::task::Context, link: &mut dyn Link); + fn poll_actions(&mut self, cx: &mut futures::task::Context, link: &dyn Link); /// Start asynchronous runner for import queue. /// /// Takes an object implementing [`Link`] which allows the import queue to /// influence the synchronization process. - async fn run(self, link: Box>); + async fn run(self, link: &dyn Link); } /// Hooks that the verification queue can use to influence the synchronization /// algorithm. -pub trait Link: Send { +pub trait Link: Send + Sync { /// Batch of blocks imported, with or without error. fn blocks_processed( - &mut self, + &self, _imported: usize, _count: usize, _results: Vec<(BlockImportResult, B::Hash)>, @@ -155,7 +155,7 @@ pub trait Link: Send { /// Justification import result. fn justification_imported( - &mut self, + &self, _who: RuntimeOrigin, _hash: &B::Hash, _number: NumberFor, @@ -164,7 +164,7 @@ pub trait Link: Send { } /// Request a justification for the given block. - fn request_justification(&mut self, _hash: &B::Hash, _number: NumberFor) {} + fn request_justification(&self, _hash: &B::Hash, _number: NumberFor) {} } /// Block import successful result. diff --git a/substrate/client/consensus/common/src/import_queue/basic_queue.rs b/substrate/client/consensus/common/src/import_queue/basic_queue.rs index 7b371145e2e7..21270859dd75 100644 --- a/substrate/client/consensus/common/src/import_queue/basic_queue.rs +++ b/substrate/client/consensus/common/src/import_queue/basic_queue.rs @@ -177,7 +177,7 @@ impl ImportQueue for BasicQueue { } /// Poll actions from network. - fn poll_actions(&mut self, cx: &mut Context, link: &mut dyn Link) { + fn poll_actions(&mut self, cx: &mut Context, link: &dyn Link) { if self.result_port.poll_actions(cx, link).is_err() { log::error!( target: LOG_TARGET, @@ -190,9 +190,9 @@ impl ImportQueue for BasicQueue { /// /// Takes an object implementing [`Link`] which allows the import queue to /// influence the synchronization process. - async fn run(mut self, mut link: Box>) { + async fn run(mut self, link: &dyn Link) { loop { - if let Err(_) = self.result_port.next_action(&mut *link).await { + if let Err(_) = self.result_port.next_action(link).await { log::error!(target: "sync", "poll_actions: Background import task is no longer alive"); return } @@ -223,7 +223,7 @@ mod worker_messages { async fn block_import_process( mut block_import: BoxBlockImport, verifier: impl Verifier, - mut result_sender: BufferedLinkSender, + result_sender: BufferedLinkSender, mut block_import_receiver: TracingUnboundedReceiver>, metrics: Option, ) { @@ -501,6 +501,7 @@ mod tests { import_queue::Verifier, }; use futures::{executor::block_on, Future}; + use parking_lot::Mutex; use sp_test_primitives::{Block, BlockNumber, Hash, Header}; #[async_trait::async_trait] @@ -558,29 +559,29 @@ mod tests { #[derive(Default)] struct TestLink { - events: Vec, + events: Mutex>, } impl Link for TestLink { fn blocks_processed( - &mut self, + &self, _imported: usize, _count: usize, results: Vec<(Result, BlockImportError>, Hash)>, ) { if let Some(hash) = results.into_iter().find_map(|(r, h)| r.ok().map(|_| h)) { - self.events.push(Event::BlockImported(hash)); + self.events.lock().push(Event::BlockImported(hash)); } } fn justification_imported( - &mut self, + &self, _who: RuntimeOrigin, hash: &Hash, _number: BlockNumber, _success: bool, ) { - self.events.push(Event::JustificationImported(*hash)) + self.events.lock().push(Event::JustificationImported(*hash)) } } @@ -638,7 +639,7 @@ mod tests { hash }; - let mut link = TestLink::default(); + let link = TestLink::default(); // we send a bunch of tasks to the worker let block1 = import_block(1); @@ -653,13 +654,13 @@ mod tests { // we poll the worker until we have processed 9 events block_on(futures::future::poll_fn(|cx| { - while link.events.len() < 9 { + while link.events.lock().len() < 9 { match Future::poll(Pin::new(&mut worker), cx) { Poll::Pending => {}, Poll::Ready(()) => panic!("import queue worker should not conclude."), } - result_port.poll_actions(cx, &mut link).unwrap(); + result_port.poll_actions(cx, &link).unwrap(); } Poll::Ready(()) @@ -667,8 +668,8 @@ mod tests { // all justification tasks must be done before any block import work assert_eq!( - link.events, - vec![ + &*link.events.lock(), + &[ Event::JustificationImported(justification1), Event::JustificationImported(justification2), Event::JustificationImported(justification3), diff --git a/substrate/client/consensus/common/src/import_queue/buffered_link.rs b/substrate/client/consensus/common/src/import_queue/buffered_link.rs index c23a4b0d5d0a..67131b06a32e 100644 --- a/substrate/client/consensus/common/src/import_queue/buffered_link.rs +++ b/substrate/client/consensus/common/src/import_queue/buffered_link.rs @@ -27,13 +27,13 @@ //! # use sc_consensus::import_queue::buffered_link::buffered_link; //! # use sp_test_primitives::Block; //! # struct DummyLink; impl Link for DummyLink {} -//! # let mut my_link = DummyLink; +//! # let my_link = DummyLink; //! let (mut tx, mut rx) = buffered_link::(100_000); //! tx.blocks_processed(0, 0, vec![]); //! //! // Calls `my_link.blocks_processed(0, 0, vec![])` when polled. //! let _fut = futures::future::poll_fn(move |cx| { -//! rx.poll_actions(cx, &mut my_link); +//! rx.poll_actions(cx, &my_link).unwrap(); //! std::task::Poll::Pending::<()> //! }); //! ``` @@ -90,7 +90,7 @@ pub enum BlockImportWorkerMsg { impl Link for BufferedLinkSender { fn blocks_processed( - &mut self, + &self, imported: usize, count: usize, results: Vec<(BlockImportResult, B::Hash)>, @@ -101,7 +101,7 @@ impl Link for BufferedLinkSender { } fn justification_imported( - &mut self, + &self, who: RuntimeOrigin, hash: &B::Hash, number: NumberFor, @@ -111,7 +111,7 @@ impl Link for BufferedLinkSender { let _ = self.tx.unbounded_send(msg); } - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + fn request_justification(&self, hash: &B::Hash, number: NumberFor) { let _ = self .tx .unbounded_send(BlockImportWorkerMsg::RequestJustification(*hash, number)); @@ -125,7 +125,7 @@ pub struct BufferedLinkReceiver { impl BufferedLinkReceiver { /// Send action for the synchronization to perform. - pub fn send_actions(&mut self, msg: BlockImportWorkerMsg, link: &mut dyn Link) { + pub fn send_actions(&mut self, msg: BlockImportWorkerMsg, link: &dyn Link) { match msg { BlockImportWorkerMsg::BlocksProcessed(imported, count, results) => link.blocks_processed(imported, count, results), @@ -144,7 +144,7 @@ impl BufferedLinkReceiver { /// it is as if this method always returned `Poll::Pending`. /// /// Returns an error if the corresponding [`BufferedLinkSender`] has been closed. - pub fn poll_actions(&mut self, cx: &mut Context, link: &mut dyn Link) -> Result<(), ()> { + pub fn poll_actions(&mut self, cx: &mut Context, link: &dyn Link) -> Result<(), ()> { loop { let msg = match Stream::poll_next(Pin::new(&mut self.rx), cx) { Poll::Ready(Some(msg)) => msg, @@ -152,12 +152,12 @@ impl BufferedLinkReceiver { Poll::Pending => break Ok(()), }; - self.send_actions(msg, &mut *link); + self.send_actions(msg, link); } } /// Poll next element from import queue and send the corresponding action command over the link. - pub async fn next_action(&mut self, link: &mut dyn Link) -> Result<(), ()> { + pub async fn next_action(&mut self, link: &dyn Link) -> Result<(), ()> { if let Some(msg) = self.rx.next().await { self.send_actions(msg, link); return Ok(()) diff --git a/substrate/client/consensus/common/src/import_queue/mock.rs b/substrate/client/consensus/common/src/import_queue/mock.rs index 64ac532ded85..a238f72568ca 100644 --- a/substrate/client/consensus/common/src/import_queue/mock.rs +++ b/substrate/client/consensus/common/src/import_queue/mock.rs @@ -40,7 +40,7 @@ mockall::mock! { impl ImportQueue for ImportQueue { fn service(&self) -> Box>; fn service_ref(&mut self) -> &mut dyn ImportQueueService; - fn poll_actions<'a>(&mut self, cx: &mut futures::task::Context<'a>, link: &mut dyn Link); - async fn run(self, link: Box>); + fn poll_actions<'a>(&mut self, cx: &mut futures::task::Context<'a>, link: &dyn Link); + async fn run(self, link: &'__mockall_link dyn Link); } } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 65ba39d34c21..f361fac54af7 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -20,48 +20,48 @@ targets = ["x86_64-unknown-linux-gnu"] ahash = { workspace = true } array-bytes = { workspace = true, default-features = true } async-trait = { workspace = true } +codec = { features = ["derive"], workspace = true, default-features = true } dyn-clone = { workspace = true } finality-grandpa = { features = ["derive-codec"], workspace = true, default-features = true } +fork-tree = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -rand = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -thiserror = { workspace = true } -fork-tree = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } -sc-network-gossip = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } +sc-network-gossip = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } sp-arithmetic = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-consensus-grandpa = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } -sp-consensus-grandpa = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } finality-grandpa = { features = ["derive-codec", "test-helpers"], workspace = true, default-features = true } -serde = { workspace = true, default-features = true } -tokio = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-test = { workspace = true } +serde = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index 86513ac5df15..1fb8bd9367c4 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -13,25 +13,25 @@ homepage.workspace = true workspace = true [dependencies] +codec = { features = ["derive"], workspace = true, default-features = true } finality-grandpa = { features = ["derive-codec"], workspace = true, default-features = true } futures = { workspace = true } jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } log = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } sc-client-api = { workspace = true, default-features = true } sc-consensus-grandpa = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] sc-block-builder = { workspace = true, default-features = true } sc-rpc = { features = ["test-helpers"], workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index a79581b1e9f1..ada3a45e186e 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -174,10 +174,20 @@ impl WarpSyncProof { let header = blockchain.header(latest_justification.target().1)? .expect("header hash corresponds to a justification in db; must exist in db as well; qed."); - proofs.push(WarpSyncFragment { header, justification: latest_justification }) + let proof = WarpSyncFragment { header, justification: latest_justification }; + + // Check for the limit. We remove some bytes from the maximum size, because we're + // only counting the size of the `WarpSyncFragment`s. The extra margin is here + // to leave room for rest of the data (the size of the `Vec` and the boolean). + if proofs_encoded_len + proof.encoded_size() >= MAX_WARP_SYNC_PROOF_SIZE - 50 { + false + } else { + proofs.push(proof); + true + } + } else { + true } - - true }; let final_outcome = WarpSyncProof { proofs, is_finished }; diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index 49111434015a..4d232f7256cb 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -16,15 +16,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } assert_matches = { workspace = true } async-trait = { workspace = true } codec = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } log = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } @@ -33,6 +31,7 @@ sc-consensus-babe = { workspace = true, default-features = true } sc-consensus-epochs = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } @@ -44,9 +43,10 @@ sp-inherents = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] -tokio = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } sc-basic-authorship = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } substrate-test-runtime-transaction-pool = { workspace = true } +tokio = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index 39f8f8609d8d..af9bcc8d56d6 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -353,7 +353,7 @@ mod tests { use sp_inherents::InherentData; use sp_runtime::generic::{Digest, DigestItem}; use substrate_test_runtime_client::{ - AccountKeyring::*, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, + DefaultTestClientBuilderExt, Sr25519Keyring::*, TestClientBuilder, TestClientBuilderExt, }; use substrate_test_runtime_transaction_pool::{uxt, TestApi}; diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index bc89deb0b50d..a051bf3f4779 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -22,7 +22,6 @@ futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -thiserror = { workspace = true } prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } @@ -34,3 +33,4 @@ sp-consensus-pow = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } diff --git a/substrate/client/consensus/pow/src/lib.rs b/substrate/client/consensus/pow/src/lib.rs index cd7da128549f..882f3440e164 100644 --- a/substrate/client/consensus/pow/src/lib.rs +++ b/substrate/client/consensus/pow/src/lib.rs @@ -62,7 +62,6 @@ use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::{ generic::{BlockId, Digest, DigestItem}, traits::{Block as BlockT, Header as HeaderT}, - RuntimeString, }; use std::{cmp::Ordering, marker::PhantomData, sync::Arc, time::Duration}; @@ -110,7 +109,7 @@ pub enum Error { #[error("{0}")] Environment(String), #[error("{0}")] - Runtime(RuntimeString), + Runtime(String), #[error("{0}")] Other(String), } diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index 5725155579fc..7e02558e007c 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -39,15 +39,15 @@ sp-state-machine = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } [dev-dependencies] +array-bytes = { workspace = true, default-features = true } criterion = { workspace = true, default-features = true } +kitchensink-runtime = { workspace = true } kvdb-rocksdb = { workspace = true } -rand = { workspace = true, default-features = true } -tempfile = { workspace = true } quickcheck = { workspace = true } -kitchensink-runtime = { workspace = true } +rand = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } -array-bytes = { workspace = true, default-features = true } +tempfile = { workspace = true } [features] default = [] diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index aaa1398a13bc..092101945107 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -1180,7 +1180,7 @@ impl Backend { /// The second argument is the Column that stores the State. /// /// Should only be needed for benchmarking. - #[cfg(any(feature = "runtime-benchmarks"))] + #[cfg(feature = "runtime-benchmarks")] pub fn expose_db(&self) -> (Arc>, sp_database::ColumnId) { (self.storage.db.clone(), columns::STATE) } @@ -1188,7 +1188,7 @@ impl Backend { /// Expose the Storage that is used by this backend. /// /// Should only be needed for benchmarking. - #[cfg(any(feature = "runtime-benchmarks"))] + #[cfg(feature = "runtime-benchmarks")] pub fn expose_storage(&self) -> Arc>> { self.storage.clone() } @@ -1486,6 +1486,7 @@ impl Backend { .map(|(n, _)| n) .unwrap_or(Zero::zero()); let existing_header = number <= highest_leaf && self.blockchain.header(hash)?.is_some(); + let existing_body = pending_block.body.is_some(); // blocks are keyed by number + hash. let lookup_key = utils::number_and_hash_to_lookup_key(number, hash)?; @@ -1677,6 +1678,23 @@ impl Backend { children, ); } + } + + let should_check_block_gap = !existing_header || !existing_body; + + if should_check_block_gap { + let insert_new_gap = + |transaction: &mut Transaction, + new_gap: BlockGap>, + block_gap: &mut Option>>| { + transaction.set(columns::META, meta_keys::BLOCK_GAP, &new_gap.encode()); + transaction.set( + columns::META, + meta_keys::BLOCK_GAP_VERSION, + &BLOCK_GAP_CURRENT_VERSION.encode(), + ); + block_gap.replace(new_gap); + }; if let Some(mut gap) = block_gap { match gap.gap_type { @@ -1695,43 +1713,65 @@ impl Backend { block_gap = None; debug!(target: "db", "Removed block gap."); } else { - block_gap = Some(gap); + insert_new_gap(&mut transaction, gap, &mut block_gap); debug!(target: "db", "Update block gap. {block_gap:?}"); - transaction.set( - columns::META, - meta_keys::BLOCK_GAP, - &gap.encode(), - ); - transaction.set( - columns::META, - meta_keys::BLOCK_GAP_VERSION, - &BLOCK_GAP_CURRENT_VERSION.encode(), - ); } block_gap_updated = true; }, BlockGapType::MissingBody => { - unreachable!("Unsupported block gap. TODO: https://github.com/paritytech/polkadot-sdk/issues/5406") + // Gap increased when syncing the header chain during fast sync. + if number == gap.end + One::one() && !existing_body { + gap.end += One::one(); + utils::insert_number_to_key_mapping( + &mut transaction, + columns::KEY_LOOKUP, + number, + hash, + )?; + insert_new_gap(&mut transaction, gap, &mut block_gap); + debug!(target: "db", "Update block gap. {block_gap:?}"); + block_gap_updated = true; + // Gap decreased when downloading the full blocks. + } else if number == gap.start && existing_body { + gap.start += One::one(); + if gap.start > gap.end { + transaction.remove(columns::META, meta_keys::BLOCK_GAP); + transaction.remove(columns::META, meta_keys::BLOCK_GAP_VERSION); + block_gap = None; + debug!(target: "db", "Removed block gap."); + } else { + insert_new_gap(&mut transaction, gap, &mut block_gap); + debug!(target: "db", "Update block gap. {block_gap:?}"); + } + block_gap_updated = true; + } }, } - } else if operation.create_gap && - number > best_num + One::one() && - self.blockchain.header(parent_hash)?.is_none() - { - let gap = BlockGap { - start: best_num + One::one(), - end: number - One::one(), - gap_type: BlockGapType::MissingHeaderAndBody, - }; - transaction.set(columns::META, meta_keys::BLOCK_GAP, &gap.encode()); - transaction.set( - columns::META, - meta_keys::BLOCK_GAP_VERSION, - &BLOCK_GAP_CURRENT_VERSION.encode(), - ); - block_gap = Some(gap); - block_gap_updated = true; - debug!(target: "db", "Detected block gap {block_gap:?}"); + } else if operation.create_gap { + if number > best_num + One::one() && + self.blockchain.header(parent_hash)?.is_none() + { + let gap = BlockGap { + start: best_num + One::one(), + end: number - One::one(), + gap_type: BlockGapType::MissingHeaderAndBody, + }; + insert_new_gap(&mut transaction, gap, &mut block_gap); + block_gap_updated = true; + debug!(target: "db", "Detected block gap (warp sync) {block_gap:?}"); + } else if number == best_num + One::one() && + self.blockchain.header(parent_hash)?.is_some() && + !existing_body + { + let gap = BlockGap { + start: number, + end: number, + gap_type: BlockGapType::MissingBody, + }; + insert_new_gap(&mut transaction, gap, &mut block_gap); + block_gap_updated = true; + debug!(target: "db", "Detected block gap (fast sync) {block_gap:?}"); + } } } diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index ca78afd47068..5cb4936e7534 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -38,21 +38,21 @@ sp-wasm-interface = { workspace = true, default-features = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } assert_matches = { workspace = true } -wat = { workspace = true } +criterion = { workspace = true, default-features = true } +num_cpus = { workspace = true } +paste = { workspace = true, default-features = true } +regex = { workspace = true } sc-runtime-test = { workspace = true } -substrate-test-runtime = { workspace = true } +sc-tracing = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } -sp-state-machine = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-maybe-compressed-blob = { workspace = true, default-features = true } -sc-tracing = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -tracing-subscriber = { workspace = true } -paste = { workspace = true, default-features = true } -regex = { workspace = true } -criterion = { workspace = true, default-features = true } -num_cpus = { workspace = true } +substrate-test-runtime = { workspace = true } tempfile = { workspace = true } +tracing-subscriber = { workspace = true } +wat = { workspace = true } [[bench]] name = "bench" diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index 58fb0b423f24..aaf13a8ae768 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -17,12 +17,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -thiserror = { workspace = true } -wasm-instrument = { workspace = true, default-features = true } +polkavm = { workspace = true } sc-allocator = { workspace = true, default-features = true } sp-maybe-compressed-blob = { workspace = true, default-features = true } sp-wasm-interface = { workspace = true, default-features = true } -polkavm = { workspace = true } +thiserror = { workspace = true } +wasm-instrument = { workspace = true, default-features = true } [features] default = [] diff --git a/substrate/client/executor/common/src/error.rs b/substrate/client/executor/common/src/error.rs index 9d489eaae420..a94c1d493134 100644 --- a/substrate/client/executor/common/src/error.rs +++ b/substrate/client/executor/common/src/error.rs @@ -150,8 +150,8 @@ pub enum WasmError { Other(String), } -impl From for WasmError { - fn from(error: polkavm::ProgramParseError) -> Self { +impl From for WasmError { + fn from(error: polkavm::program::ProgramParseError) -> Self { WasmError::Other(error.to_string()) } } diff --git a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs index d689083b2f85..e3f4b4ad9774 100644 --- a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use crate::{error::WasmError, wasm_runtime::HeapAllocStrategy}; +use polkavm::ArcBytes; use wasm_instrument::parity_wasm::elements::{ deserialize_buffer, serialize, ExportEntry, External, Internal, MemorySection, MemoryType, Module, Section, @@ -29,7 +30,7 @@ pub struct RuntimeBlob(BlobKind); #[derive(Clone)] enum BlobKind { WebAssembly(Module), - PolkaVM(polkavm::ProgramBlob<'static>), + PolkaVM((polkavm::ProgramBlob, ArcBytes)), } impl RuntimeBlob { @@ -52,9 +53,9 @@ impl RuntimeBlob { pub fn new(raw_blob: &[u8]) -> Result { if raw_blob.starts_with(b"PVM\0") { if crate::is_polkavm_enabled() { - return Ok(Self(BlobKind::PolkaVM( - polkavm::ProgramBlob::parse(raw_blob)?.into_owned(), - ))); + let raw = ArcBytes::from(raw_blob); + let blob = polkavm::ProgramBlob::parse(raw.clone())?; + return Ok(Self(BlobKind::PolkaVM((blob, raw)))); } else { return Err(WasmError::Other("expected a WASM runtime blob, found a PolkaVM runtime blob; set the 'SUBSTRATE_ENABLE_POLKAVM' environment variable to enable the experimental PolkaVM-based executor".to_string())); } @@ -192,7 +193,7 @@ impl RuntimeBlob { match self.0 { BlobKind::WebAssembly(raw_module) => serialize(raw_module).expect("serializing into a vec should succeed; qed"), - BlobKind::PolkaVM(ref blob) => blob.as_bytes().to_vec(), + BlobKind::PolkaVM(ref blob) => blob.1.to_vec(), } } @@ -227,7 +228,7 @@ impl RuntimeBlob { pub fn as_polkavm_blob(&self) -> Option<&polkavm::ProgramBlob> { match self.0 { BlobKind::WebAssembly(..) => None, - BlobKind::PolkaVM(ref blob) => Some(blob), + BlobKind::PolkaVM((ref blob, _)) => Some(blob), } } } diff --git a/substrate/client/executor/polkavm/src/lib.rs b/substrate/client/executor/polkavm/src/lib.rs index 1bd72eb33d30..134f9ea3d8c4 100644 --- a/substrate/client/executor/polkavm/src/lib.rs +++ b/substrate/client/executor/polkavm/src/lib.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use polkavm::{Caller, Reg}; +use polkavm::{CallError, Caller, Reg}; use sc_executor_common::{ error::{Error, WasmError}, wasm_runtime::{AllocationStats, WasmInstance, WasmModule}, @@ -26,10 +26,10 @@ use sp_wasm_interface::{ }; #[repr(transparent)] -pub struct InstancePre(polkavm::InstancePre<()>); +pub struct InstancePre(polkavm::InstancePre<(), String>); #[repr(transparent)] -pub struct Instance(polkavm::Instance<()>); +pub struct Instance(polkavm::Instance<(), String>); impl WasmModule for InstancePre { fn new_instance(&self) -> Result, Error> { @@ -43,11 +43,13 @@ impl WasmInstance for Instance { name: &str, raw_data: &[u8], ) -> (Result, Error>, Option) { - let Some(method_index) = self.0.module().lookup_export(name) else { - return ( - Err(format!("cannot call into the runtime: export not found: '{name}'").into()), - None, - ); + let pc = match self.0.module().exports().find(|e| e.symbol() == name) { + Some(export) => export.program_counter(), + None => + return ( + Err(format!("cannot call into the runtime: export not found: '{name}'").into()), + None, + ), }; let Ok(raw_data_length) = u32::try_from(raw_data.len()) else { @@ -58,56 +60,60 @@ impl WasmInstance for Instance { }; // TODO: This will leak guest memory; find a better solution. - let mut state_args = polkavm::StateArgs::new(); - // Make sure the memory is cleared... - state_args.reset_memory(true); - // ...and allocate space for the input payload. - state_args.sbrk(raw_data_length); + // Make sure that the memory is cleared... + if let Err(err) = self.0.reset_memory() { + return ( + Err(format!( + "call into the runtime method '{name}' failed: reset memory failed: {err}" + ) + .into()), + None, + ); + } - match self.0.update_state(state_args) { - Ok(()) => {}, - Err(polkavm::ExecutionError::Trap(trap)) => { - return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {trap}").into()), None); - }, - Err(polkavm::ExecutionError::Error(error)) => { - return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {error}").into()), None); - }, - Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + // ... and allocate space for the input payload. + if let Err(err) = self.0.sbrk(raw_data_length) { + return ( + Err(format!( + "call into the runtime method '{name}' failed: reset memory failed: {err}" + ) + .into()), + None, + ); } // Grab the address of where the guest's heap starts; that's where we've just allocated // the memory for the input payload. let data_pointer = self.0.module().memory_map().heap_base(); - if let Err(error) = self.0.write_memory(data_pointer, raw_data) { - return (Err(format!("call into the runtime method '{name}': failed to write the input payload into guest memory: {error}").into()), None); + if let Err(err) = self.0.write_memory(data_pointer, raw_data) { + return (Err(format!("call into the runtime method '{name}': failed to write the input payload into guest memory: {err}").into()), None); } - let mut state = (); - let mut call_args = polkavm::CallArgs::new(&mut state, method_index); - call_args.args_untyped(&[data_pointer, raw_data_length]); - - match self.0.call(Default::default(), call_args) { + match self.0.call_typed(&mut (), pc, (data_pointer, raw_data_length)) { Ok(()) => {}, - Err(polkavm::ExecutionError::Trap(trap)) => { + Err(CallError::Trap) => return ( - Err(format!("call into the runtime method '{name}' failed: {trap}").into()), + Err(format!("call into the runtime method '{name}' failed: trap").into()), None, - ); - }, - Err(polkavm::ExecutionError::Error(error)) => { + ), + Err(CallError::Error(err)) => return ( - Err(format!("call into the runtime method '{name}' failed: {error}").into()), + Err(format!("call into the runtime method '{name}' failed: {err}").into()), None, - ); - }, - Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), - } + ), + Err(CallError::User(err)) => + return ( + Err(format!("call into the runtime method '{name}' failed: {err}").into()), + None, + ), + Err(CallError::NotEnoughGas) => unreachable!("gas metering is never enabled"), + }; - let result_pointer = self.0.get_reg(Reg::A0); - let result_length = self.0.get_reg(Reg::A1); - let output = match self.0.read_memory_into_vec(result_pointer, result_length) { + let result_pointer = self.0.reg(Reg::A0); + let result_length = self.0.reg(Reg::A1); + let output = match self.0.read_memory(result_pointer as u32, result_length as u32) { Ok(output) => output, Err(error) => { return (Err(format!("call into the runtime method '{name}' failed: failed to read the return payload: {error}").into()), None) @@ -127,20 +133,31 @@ impl<'r, 'a> FunctionContext for Context<'r, 'a> { dest: &mut [u8], ) -> sp_wasm_interface::Result<()> { self.0 - .read_memory_into_slice(u32::from(address), dest) + .instance + .read_memory_into(u32::from(address), dest) .map_err(|error| error.to_string()) .map(|_| ()) } fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { - self.0.write_memory(u32::from(address), data).map_err(|error| error.to_string()) + self.0 + .instance + .write_memory(u32::from(address), data) + .map_err(|error| error.to_string()) } fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { - let pointer = self.0.sbrk(0).expect("fetching the current heap pointer never fails"); + let pointer = match self.0.instance.sbrk(0) { + Ok(pointer) => pointer.expect("fetching the current heap pointer never fails"), + Err(err) => return Err(format!("sbrk failed: {err}")), + }; // TODO: This will leak guest memory; find a better solution. - self.0.sbrk(size).ok_or_else(|| String::from("allocation failed"))?; + match self.0.instance.sbrk(size) { + Ok(Some(_)) => (), + Ok(None) => return Err(String::from("allocation error")), + Err(err) => return Err(format!("sbrk failed: {err}")), + } Ok(Pointer::new(pointer)) } @@ -155,41 +172,46 @@ impl<'r, 'a> FunctionContext for Context<'r, 'a> { } } -fn call_host_function( - caller: &mut Caller<()>, - function: &dyn Function, -) -> Result<(), polkavm::Trap> { +fn call_host_function(caller: &mut Caller<()>, function: &dyn Function) -> Result<(), String> { let mut args = [Value::I64(0); Reg::ARG_REGS.len()]; let mut nth_reg = 0; for (nth_arg, kind) in function.signature().args.iter().enumerate() { match kind { ValueType::I32 => { - args[nth_arg] = Value::I32(caller.get_reg(Reg::ARG_REGS[nth_reg]) as i32); + args[nth_arg] = Value::I32(caller.instance.reg(Reg::ARG_REGS[nth_reg]) as i32); nth_reg += 1; }, ValueType::F32 => { - args[nth_arg] = Value::F32(caller.get_reg(Reg::ARG_REGS[nth_reg])); - nth_reg += 1; - }, - ValueType::I64 => { - let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); - nth_reg += 1; - - let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); - nth_reg += 1; - - args[nth_arg] = - Value::I64((u64::from(value_lo) | (u64::from(value_hi) << 32)) as i64); - }, - ValueType::F64 => { - let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + args[nth_arg] = Value::F32(caller.instance.reg(Reg::ARG_REGS[nth_reg]) as u32); nth_reg += 1; - - let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); - nth_reg += 1; - - args[nth_arg] = Value::F64(u64::from(value_lo) | (u64::from(value_hi) << 32)); }, + ValueType::I64 => + if caller.instance.is_64_bit() { + args[nth_arg] = Value::I64(caller.instance.reg(Reg::ARG_REGS[nth_reg]) as i64); + nth_reg += 1; + } else { + let value_lo = caller.instance.reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.instance.reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = + Value::I64((u64::from(value_lo) | (u64::from(value_hi) << 32)) as i64); + }, + ValueType::F64 => + if caller.instance.is_64_bit() { + args[nth_arg] = Value::F64(caller.instance.reg(Reg::ARG_REGS[nth_reg])); + nth_reg += 1; + } else { + let value_lo = caller.instance.reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.instance.reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = Value::F64(u64::from(value_lo) | (u64::from(value_hi) << 32)); + }, } } @@ -204,27 +226,33 @@ fn call_host_function( { Ok(value) => value, Err(error) => { - log::warn!("Call into the host function '{}' failed: {error}", function.name()); - return Err(polkavm::Trap::default()); + let name = function.name(); + return Err(format!("call into the host function '{name}' failed: {error}")) }, }; if let Some(value) = value { match value { Value::I32(value) => { - caller.set_reg(Reg::A0, value as u32); + caller.instance.set_reg(Reg::A0, value as u64); }, Value::F32(value) => { - caller.set_reg(Reg::A0, value); - }, - Value::I64(value) => { - caller.set_reg(Reg::A0, value as u32); - caller.set_reg(Reg::A1, (value >> 32) as u32); - }, - Value::F64(value) => { - caller.set_reg(Reg::A0, value as u32); - caller.set_reg(Reg::A1, (value >> 32) as u32); + caller.instance.set_reg(Reg::A0, value as u64); }, + Value::I64(value) => + if caller.instance.is_64_bit() { + caller.instance.set_reg(Reg::A0, value as u64); + } else { + caller.instance.set_reg(Reg::A0, value as u64); + caller.instance.set_reg(Reg::A1, (value >> 32) as u64); + }, + Value::F64(value) => + if caller.instance.is_64_bit() { + caller.instance.set_reg(Reg::A0, value as u64); + } else { + caller.instance.set_reg(Reg::A0, value as u64); + caller.instance.set_reg(Reg::A1, (value >> 32) as u64); + }, } } @@ -250,12 +278,16 @@ where }, }; - let module = polkavm::Module::from_blob(&engine, &polkavm::ModuleConfig::default(), blob)?; - let mut linker = polkavm::Linker::new(&engine); + let module = + polkavm::Module::from_blob(&engine, &polkavm::ModuleConfig::default(), blob.clone())?; + + let mut linker = polkavm::Linker::new(); + for function in H::host_functions() { - linker.func_new(function.name(), |mut caller| call_host_function(&mut caller, function))?; + linker.define_untyped(function.name(), |mut caller: Caller<()>| { + call_host_function(&mut caller, function) + })?; } - let instance_pre = linker.instantiate_pre(&module)?; Ok(Box::new(InstancePre(instance_pre))) } diff --git a/substrate/client/executor/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index 77dfc09c8807..8f189ca92388 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -441,18 +441,20 @@ where #[cfg(test)] mod tests { + extern crate alloc; + use super::*; + use alloc::borrow::Cow; use codec::Encode; use sp_api::{Core, RuntimeApiInfo}; - use sp_runtime::RuntimeString; use sp_version::{create_apis_vec, RuntimeVersion}; use sp_wasm_interface::HostFunctions; use substrate_test_runtime::Block; #[derive(Encode)] pub struct OldRuntimeVersion { - pub spec_name: RuntimeString, - pub impl_name: RuntimeString, + pub spec_name: Cow<'static, str>, + pub impl_name: Cow<'static, str>, pub authoring_version: u32, pub spec_version: u32, pub impl_version: u32, diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index ef8e5da876aa..7ea94568e1b7 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -16,13 +16,18 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { workspace = true, default-features = true } cfg-if = { workspace = true } libc = { workspace = true } +log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! +anyhow = { workspace = true } +sc-allocator = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +sp-runtime-interface = { workspace = true, default-features = true } +sp-wasm-interface = { features = ["wasmtime"], workspace = true, default-features = true } wasmtime = { features = [ "cache", "cranelift", @@ -30,11 +35,6 @@ wasmtime = { features = [ "parallel-compilation", "pooling-allocator", ], workspace = true } -anyhow = { workspace = true } -sc-allocator = { workspace = true, default-features = true } -sc-executor-common = { workspace = true, default-features = true } -sp-runtime-interface = { workspace = true, default-features = true } -sp-wasm-interface = { features = ["wasmtime"], workspace = true, default-features = true } # Here we include the rustix crate in the exactly same semver-compatible version as used by # wasmtime and enable its 'use-libc' flag. @@ -45,10 +45,10 @@ sp-wasm-interface = { features = ["wasmtime"], workspace = true, default-feature rustix = { features = ["fs", "mm", "param", "std", "use-libc"], workspace = true } [dev-dependencies] -wat = { workspace = true } +cargo_metadata = { workspace = true } +codec = { workspace = true, default-features = true } +paste = { workspace = true, default-features = true } sc-runtime-test = { workspace = true } sp-io = { workspace = true, default-features = true } tempfile = { workspace = true } -paste = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } -cargo_metadata = { workspace = true } +wat = { workspace = true } diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 87a4be320d68..209964e02ef3 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -21,8 +21,8 @@ futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index d338bb1af61a..e46fafbc3729 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -20,10 +20,10 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -thiserror = { workspace = true } sp-application-crypto = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] tempfile = { workspace = true } diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index 6639a10d33f1..7849eac5f516 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -17,14 +17,14 @@ workspace = true codec = { workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-offchain = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sp-consensus-beefy = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-consensus-beefy = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-mmr-primitives = { workspace = true, default-features = true } -sc-offchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } [dev-dependencies] diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 94bc9a671f84..ea52913aea16 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -21,18 +21,18 @@ ahash = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } -schnellru = { workspace = true } -tracing = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } +schnellru = { workspace = true } sp-runtime = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } [dev-dependencies] -tokio = { workspace = true, default-features = true } async-trait = { workspace = true } codec = { features = ["derive"], workspace = true, default-features = true } quickcheck = { workspace = true } substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index a4bd922a76d5..bff258a9a011 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -220,18 +220,16 @@ impl Future for GossipEngine { }, NotificationEvent::NotificationStreamOpened { peer, handshake, .. - } => { - let Some(role) = this.network.peer_role(peer, handshake) else { + } => + if let Some(role) = this.network.peer_role(peer, handshake) { + this.state_machine.new_peer( + &mut this.notification_service, + peer, + role, + ); + } else { log::debug!(target: "gossip", "role for {peer} couldn't be determined"); - continue - }; - - this.state_machine.new_peer( - &mut this.notification_service, - peer, - role, - ); - }, + }, NotificationEvent::NotificationStreamClosed { peer } => { this.state_machine .peer_disconnected(&mut this.notification_service, peer); @@ -256,10 +254,12 @@ impl Future for GossipEngine { match sync_event_stream { Poll::Ready(Some(event)) => match event { - SyncEvent::PeerConnected(remote) => - this.network.add_set_reserved(remote, this.protocol.clone()), - SyncEvent::PeerDisconnected(remote) => - this.network.remove_set_reserved(remote, this.protocol.clone()), + SyncEvent::InitialPeers(peer_ids) => + this.network.add_set_reserved(peer_ids, this.protocol.clone()), + SyncEvent::PeerConnected(peer_id) => + this.network.add_set_reserved(vec![peer_id], this.protocol.clone()), + SyncEvent::PeerDisconnected(peer_id) => + this.network.remove_set_reserved(peer_id, this.protocol.clone()), }, // The sync event stream closed. Do the same for [`GossipValidator`]. Poll::Ready(None) => { diff --git a/substrate/client/network-gossip/src/lib.rs b/substrate/client/network-gossip/src/lib.rs index 20d9922200c2..2ec573bf9e3e 100644 --- a/substrate/client/network-gossip/src/lib.rs +++ b/substrate/client/network-gossip/src/lib.rs @@ -82,15 +82,18 @@ mod validator; /// Abstraction over a network. pub trait Network: NetworkPeers + NetworkEventStream { - fn add_set_reserved(&self, who: PeerId, protocol: ProtocolName) { - let addr = Multiaddr::empty().with(Protocol::P2p(*who.as_ref())); - let result = self.add_peers_to_reserved_set(protocol, iter::once(addr).collect()); + fn add_set_reserved(&self, peer_ids: Vec, protocol: ProtocolName) { + let addrs = peer_ids + .into_iter() + .map(|peer_id| Multiaddr::empty().with(Protocol::P2p(peer_id.into()))) + .collect(); + let result = self.add_peers_to_reserved_set(protocol, addrs); if let Err(err) = result { log::error!(target: "gossip", "add_set_reserved failed: {}", err); } } - fn remove_set_reserved(&self, who: PeerId, protocol: ProtocolName) { - let result = self.remove_peers_from_reserved_set(protocol, iter::once(who).collect()); + fn remove_set_reserved(&self, peer_id: PeerId, protocol: ProtocolName) { + let result = self.remove_peers_from_reserved_set(protocol, iter::once(peer_id).collect()); if let Err(err) = result { log::error!(target: "gossip", "remove_set_reserved failed: {}", err); } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 8ae3de72f796..19af70867658 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -34,54 +34,66 @@ futures-timer = { workspace = true } ip_network = { workspace = true } libp2p = { features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "request-response", "tcp", "tokio", "websocket", "yamux"], workspace = true } linked_hash_set = { workspace = true } +litep2p = { workspace = true } log = { workspace = true, default-features = true } mockall = { workspace = true } +once_cell = { workspace = true } parking_lot = { workspace = true, default-features = true } partial_sort = { workspace = true } pin-project = { workspace = true } -rand = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -smallvec = { workspace = true, default-features = true } -thiserror = { workspace = true } -tokio = { features = ["macros", "sync"], workspace = true, default-features = true } -tokio-stream = { workspace = true } -unsigned-varint = { features = ["asynchronous_codec", "futures"], workspace = true } -zeroize = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } prost = { workspace = true } +rand = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +schnellru = { workspace = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +smallvec = { workspace = true, default-features = true } sp-arithmetic = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -wasm-timer = { workspace = true } -litep2p = { workspace = true } -once_cell = { workspace = true } +thiserror = { workspace = true } +tokio = { features = ["macros", "sync"], workspace = true, default-features = true } +tokio-stream = { workspace = true } +unsigned-varint = { features = ["asynchronous_codec", "futures"], workspace = true } void = { workspace = true } -schnellru = { workspace = true } +wasm-timer = { workspace = true } +zeroize = { workspace = true, default-features = true } [dev-dependencies] assert_matches = { workspace = true } mockall = { workspace = true } multistream-select = { workspace = true } rand = { workspace = true, default-features = true } -tempfile = { workspace = true } -tokio = { features = ["macros"], workspace = true, default-features = true } -tokio-util = { features = ["compat"], workspace = true } -tokio-test = { workspace = true } sc-block-builder = { workspace = true, default-features = true } sc-network-light = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } -sp-crypto-hashing = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } sp-test-primitives = { workspace = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime = { workspace = true } substrate-test-runtime-client = { workspace = true } +tempfile = { workspace = true } +tokio = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } +tokio-test = { workspace = true } +tokio-util = { features = ["compat"], workspace = true } + +criterion = { workspace = true, default-features = true, features = ["async_tokio"] } +sc-consensus = { workspace = true, default-features = true } [features] default = [] + + +[[bench]] +name = "notifications_protocol" +harness = false + +[[bench]] +name = "request_response_protocol" +harness = false diff --git a/substrate/client/network/benches/notifications_protocol.rs b/substrate/client/network/benches/notifications_protocol.rs new file mode 100644 index 000000000000..40a810d616b5 --- /dev/null +++ b/substrate/client/network/benches/notifications_protocol.rs @@ -0,0 +1,318 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use criterion::{ + criterion_group, criterion_main, AxisScale, BenchmarkId, Criterion, PlotConfiguration, + Throughput, +}; +use sc_network::{ + config::{ + FullNetworkConfiguration, MultiaddrWithPeerId, NetworkConfiguration, NonReservedPeerMode, + NotificationHandshake, Params, ProtocolId, Role, SetConfig, + }, + service::traits::{NetworkService, NotificationEvent}, + Litep2pNetworkBackend, NetworkBackend, NetworkWorker, NotificationMetrics, NotificationService, + PeerId, Roles, +}; +use sc_network_common::{sync::message::BlockAnnouncesHandshake, ExHashT}; +use sp_core::H256; +use sp_runtime::traits::{Block as BlockT, Zero}; +use std::{sync::Arc, time::Duration}; +use substrate_test_runtime_client::runtime; +use tokio::{sync::Mutex, task::JoinHandle}; + +const SMALL_PAYLOAD: &[(u32, usize, &'static str)] = &[ + // (Exponent of size, number of notifications, label) + (6, 100, "64B"), + (9, 100, "512B"), + (12, 100, "4KB"), + (15, 100, "64KB"), +]; +const LARGE_PAYLOAD: &[(u32, usize, &'static str)] = &[ + // (Exponent of size, number of notifications, label) + (18, 10, "256KB"), + (21, 10, "2MB"), + (24, 10, "16MB"), + (27, 10, "128MB"), +]; +const MAX_SIZE: u64 = 2u64.pow(30); + +fn create_network_worker( +) -> (N, Arc, Arc>>) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let role = Role::Full; + let net_conf = NetworkConfiguration::new_local(); + let network_config = FullNetworkConfiguration::::new(&net_conf, None); + let genesis_hash = runtime::Hash::zero(); + let (block_announce_config, notification_service) = N::notification_config( + "/block-announces/1".into(), + vec!["/bench-notifications-protocol/block-announces/1".into()], + MAX_SIZE, + Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + Roles::from(&role), + Zero::zero(), + genesis_hash, + genesis_hash, + ))), + SetConfig { + in_peers: 1, + out_peers: 1, + reserved_nodes: vec![], + non_reserved_mode: NonReservedPeerMode::Accept, + }, + NotificationMetrics::new(None), + network_config.peer_store_handle(), + ); + let worker = N::new(Params:: { + block_announce_config, + role, + executor: Box::new(|f| { + tokio::spawn(f); + }), + genesis_hash, + network_config, + protocol_id: ProtocolId::from("bench-protocol-name"), + fork_id: None, + metrics_registry: None, + bitswap_config: None, + notification_metrics: NotificationMetrics::new(None), + }) + .unwrap(); + let network_service = worker.network_service(); + let notification_service = Arc::new(Mutex::new(notification_service)); + + (worker, network_service, notification_service) +} + +struct BenchSetup { + notification_service1: Arc>>, + notification_service2: Arc>>, + peer_id2: PeerId, + handle1: JoinHandle<()>, + handle2: JoinHandle<()>, +} + +impl Drop for BenchSetup { + fn drop(&mut self) { + self.handle1.abort(); + self.handle2.abort(); + } +} + +fn setup_workers(rt: &tokio::runtime::Runtime) -> Arc +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let _guard = rt.enter(); + + let (worker1, network_service1, notification_service1) = create_network_worker::(); + let (worker2, network_service2, notification_service2) = create_network_worker::(); + let peer_id2: sc_network::PeerId = network_service2.local_peer_id().into(); + let handle1 = tokio::spawn(worker1.run()); + let handle2 = tokio::spawn(worker2.run()); + + let ready = tokio::spawn({ + let notification_service1 = Arc::clone(¬ification_service1); + let notification_service2 = Arc::clone(¬ification_service2); + + async move { + let listen_address2 = { + while network_service2.listen_addresses().is_empty() { + tokio::time::sleep(Duration::from_millis(10)).await; + } + network_service2.listen_addresses()[0].clone() + }; + network_service1 + .add_reserved_peer(MultiaddrWithPeerId { + multiaddr: listen_address2, + peer_id: peer_id2, + }) + .unwrap(); + + let mut notification_service1 = notification_service1.lock().await; + let mut notification_service2 = notification_service2.lock().await; + loop { + tokio::select! { + Some(event) = notification_service1.next_event() => { + if let NotificationEvent::NotificationStreamOpened { .. } = event { + break; + } + }, + Some(event) = notification_service2.next_event() => { + if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = event { + result_tx.send(sc_network::service::traits::ValidationResult::Accept).unwrap(); + } + }, + } + } + } + }); + + tokio::task::block_in_place(|| { + let _ = tokio::runtime::Handle::current().block_on(ready); + }); + + Arc::new(BenchSetup { + notification_service1, + notification_service2, + peer_id2, + handle1, + handle2, + }) +} + +async fn run_serially(setup: Arc, size: usize, limit: usize) { + let (tx, rx) = async_channel::bounded(1); + let _ = tx.send(Some(())).await; + let network1 = tokio::spawn({ + let notification_service1 = Arc::clone(&setup.notification_service1); + let peer_id2 = setup.peer_id2; + async move { + let mut notification_service1 = notification_service1.lock().await; + while let Ok(message) = rx.recv().await { + let Some(_) = message else { break }; + notification_service1 + .send_async_notification(&peer_id2, vec![0; size]) + .await + .unwrap(); + } + } + }); + let network2 = tokio::spawn({ + let notification_service2 = Arc::clone(&setup.notification_service2); + async move { + let mut notification_service2 = notification_service2.lock().await; + let mut received_counter = 0; + while let Some(event) = notification_service2.next_event().await { + if let NotificationEvent::NotificationReceived { .. } = event { + received_counter += 1; + if received_counter >= limit { + let _ = tx.send(None).await; + break; + } + let _ = tx.send(Some(())).await; + } + } + } + }); + + let _ = tokio::join!(network1, network2); +} + +async fn run_with_backpressure(setup: Arc, size: usize, limit: usize) { + let (tx, rx) = async_channel::bounded(1); + let network1 = tokio::spawn({ + let setup = Arc::clone(&setup); + async move { + let mut notification_service1 = setup.notification_service1.lock().await; + for _ in 0..limit { + notification_service1 + .send_async_notification(&setup.peer_id2, vec![0; size]) + .await + .unwrap(); + } + let _ = rx.recv().await; + } + }); + let network2 = tokio::spawn({ + let setup = Arc::clone(&setup); + async move { + let mut notification_service2 = setup.notification_service2.lock().await; + let mut received_counter = 0; + while let Some(event) = notification_service2.next_event().await { + if let NotificationEvent::NotificationReceived { .. } = event { + received_counter += 1; + if received_counter >= limit { + let _ = tx.send(()).await; + break; + } + } + } + } + }); + + let _ = tokio::join!(network1, network2); +} + +fn run_benchmark(c: &mut Criterion, payload: &[(u32, usize, &'static str)], group: &str) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic); + let mut group = c.benchmark_group(group); + group.plot_config(plot_config); + + let libp2p_setup = setup_workers::>(&rt); + for &(exponent, limit, label) in payload.iter() { + let size = 2usize.pow(exponent); + group.throughput(Throughput::Bytes(limit as u64 * size as u64)); + group.bench_with_input( + BenchmarkId::new("libp2p/serially", label), + &(size, limit), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| run_serially(Arc::clone(&libp2p_setup), size, limit)); + }, + ); + group.bench_with_input( + BenchmarkId::new("libp2p/with_backpressure", label), + &(size, limit), + |b, &(size, limit)| { + b.to_async(&rt) + .iter(|| run_with_backpressure(Arc::clone(&libp2p_setup), size, limit)); + }, + ); + } + drop(libp2p_setup); + + let litep2p_setup = setup_workers::(&rt); + for &(exponent, limit, label) in payload.iter() { + let size = 2usize.pow(exponent); + group.throughput(Throughput::Bytes(limit as u64 * size as u64)); + group.bench_with_input( + BenchmarkId::new("litep2p/serially", label), + &(size, limit), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| run_serially(Arc::clone(&litep2p_setup), size, limit)); + }, + ); + group.bench_with_input( + BenchmarkId::new("litep2p/with_backpressure", label), + &(size, limit), + |b, &(size, limit)| { + b.to_async(&rt) + .iter(|| run_with_backpressure(Arc::clone(&litep2p_setup), size, limit)); + }, + ); + } + drop(litep2p_setup); +} + +fn run_benchmark_with_small_payload(c: &mut Criterion) { + run_benchmark(c, SMALL_PAYLOAD, "notifications_protocol/small_payload"); +} + +fn run_benchmark_with_large_payload(c: &mut Criterion) { + run_benchmark(c, LARGE_PAYLOAD, "notifications_protocol/large_payload"); +} + +criterion_group!(benches, run_benchmark_with_small_payload, run_benchmark_with_large_payload); +criterion_main!(benches); diff --git a/substrate/client/network/benches/request_response_protocol.rs b/substrate/client/network/benches/request_response_protocol.rs new file mode 100644 index 000000000000..85381112b753 --- /dev/null +++ b/substrate/client/network/benches/request_response_protocol.rs @@ -0,0 +1,317 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use criterion::{ + criterion_group, criterion_main, AxisScale, BenchmarkId, Criterion, PlotConfiguration, + Throughput, +}; +use sc_network::{ + config::{ + FullNetworkConfiguration, IncomingRequest, NetworkConfiguration, NonReservedPeerMode, + NotificationHandshake, OutgoingResponse, Params, ProtocolId, Role, SetConfig, + }, + service::traits::NetworkService, + IfDisconnected, Litep2pNetworkBackend, NetworkBackend, NetworkRequest, NetworkWorker, + NotificationMetrics, NotificationService, PeerId, Roles, +}; +use sc_network_common::{sync::message::BlockAnnouncesHandshake, ExHashT}; +use sp_core::H256; +use sp_runtime::traits::{Block as BlockT, Zero}; +use std::{sync::Arc, time::Duration}; +use substrate_test_runtime_client::runtime; +use tokio::{sync::Mutex, task::JoinHandle}; + +const MAX_SIZE: u64 = 2u64.pow(30); +const SMALL_PAYLOAD: &[(u32, usize, &'static str)] = &[ + // (Exponent of size, number of requests, label) + (6, 100, "64B"), + (9, 100, "512B"), + (12, 100, "4KB"), + (15, 100, "64KB"), +]; +const LARGE_PAYLOAD: &[(u32, usize, &'static str)] = &[ + // (Exponent of size, number of requests, label) + (18, 10, "256KB"), + (21, 10, "2MB"), + (24, 10, "16MB"), + (27, 10, "128MB"), +]; + +pub fn create_network_worker() -> ( + N, + Arc, + async_channel::Receiver, + Arc>>, +) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let (tx, rx) = async_channel::bounded(10); + let request_response_config = N::request_response_config( + "/request-response/1".into(), + vec![], + MAX_SIZE, + MAX_SIZE, + Duration::from_secs(2), + Some(tx), + ); + let role = Role::Full; + let net_conf = NetworkConfiguration::new_local(); + let mut network_config = FullNetworkConfiguration::new(&net_conf, None); + network_config.add_request_response_protocol(request_response_config); + let genesis_hash = runtime::Hash::zero(); + let (block_announce_config, notification_service) = N::notification_config( + "/block-announces/1".into(), + vec![], + 1024, + Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + Roles::from(&Role::Full), + Zero::zero(), + genesis_hash, + genesis_hash, + ))), + SetConfig { + in_peers: 1, + out_peers: 1, + reserved_nodes: vec![], + non_reserved_mode: NonReservedPeerMode::Accept, + }, + NotificationMetrics::new(None), + network_config.peer_store_handle(), + ); + let worker = N::new(Params:: { + block_announce_config, + role, + executor: Box::new(|f| { + tokio::spawn(f); + }), + genesis_hash: runtime::Hash::zero(), + network_config, + protocol_id: ProtocolId::from("bench-request-response-protocol"), + fork_id: None, + metrics_registry: None, + bitswap_config: None, + notification_metrics: NotificationMetrics::new(None), + }) + .unwrap(); + let notification_service = Arc::new(Mutex::new(notification_service)); + let network_service = worker.network_service(); + + (worker, network_service, rx, notification_service) +} + +struct BenchSetup { + #[allow(dead_code)] + notification_service1: Arc>>, + #[allow(dead_code)] + notification_service2: Arc>>, + network_service1: Arc, + peer_id2: PeerId, + handle1: JoinHandle<()>, + handle2: JoinHandle<()>, + #[allow(dead_code)] + rx1: async_channel::Receiver, + rx2: async_channel::Receiver, +} + +impl Drop for BenchSetup { + fn drop(&mut self) { + self.handle1.abort(); + self.handle2.abort(); + } +} + +fn setup_workers(rt: &tokio::runtime::Runtime) -> Arc +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let _guard = rt.enter(); + + let (worker1, network_service1, rx1, notification_service1) = + create_network_worker::(); + let (worker2, network_service2, rx2, notification_service2) = + create_network_worker::(); + let peer_id2 = worker2.network_service().local_peer_id(); + let handle1 = tokio::spawn(worker1.run()); + let handle2 = tokio::spawn(worker2.run()); + + let ready = tokio::spawn({ + let network_service1 = Arc::clone(&network_service1); + + async move { + let listen_address2 = { + while network_service2.listen_addresses().is_empty() { + tokio::time::sleep(Duration::from_millis(10)).await; + } + network_service2.listen_addresses()[0].clone() + }; + network_service1.add_known_address(peer_id2, listen_address2.into()); + } + }); + + tokio::task::block_in_place(|| { + let _ = tokio::runtime::Handle::current().block_on(ready); + }); + + Arc::new(BenchSetup { + notification_service1, + notification_service2, + network_service1, + peer_id2, + handle1, + handle2, + rx1, + rx2, + }) +} + +async fn run_serially(setup: Arc, size: usize, limit: usize) { + let (break_tx, break_rx) = async_channel::bounded(1); + let network1 = tokio::spawn({ + let network_service1 = Arc::clone(&setup.network_service1); + let peer_id2 = setup.peer_id2; + async move { + for _ in 0..limit { + let _ = network_service1 + .request( + peer_id2.into(), + "/request-response/1".into(), + vec![0; 2], + None, + IfDisconnected::TryConnect, + ) + .await + .unwrap(); + } + let _ = break_tx.send(()).await; + } + }); + let network2 = tokio::spawn({ + let rx2 = setup.rx2.clone(); + async move { + loop { + tokio::select! { + res = rx2.recv() => { + let IncomingRequest { pending_response, .. } = res.unwrap(); + pending_response.send(OutgoingResponse { + result: Ok(vec![0; size]), + reputation_changes: vec![], + sent_feedback: None, + }).unwrap(); + }, + _ = break_rx.recv() => break, + } + } + } + }); + + let _ = tokio::join!(network1, network2); +} + +// The libp2p request-response implementation does not provide any backpressure feedback. +// So this benchmark is useless until we implement it for litep2p. +#[allow(dead_code)] +async fn run_with_backpressure(setup: Arc, size: usize, limit: usize) { + let (break_tx, break_rx) = async_channel::bounded(1); + let requests = futures::future::join_all((0..limit).into_iter().map(|_| { + let (tx, rx) = futures::channel::oneshot::channel(); + setup.network_service1.start_request( + setup.peer_id2.into(), + "/request-response/1".into(), + vec![0; 8], + None, + tx, + IfDisconnected::TryConnect, + ); + rx + })); + + let network1 = tokio::spawn(async move { + let responses = requests.await; + for res in responses { + res.unwrap().unwrap(); + } + let _ = break_tx.send(()).await; + }); + let network2 = tokio::spawn(async move { + for _ in 0..limit { + let IncomingRequest { pending_response, .. } = setup.rx2.recv().await.unwrap(); + pending_response + .send(OutgoingResponse { + result: Ok(vec![0; size]), + reputation_changes: vec![], + sent_feedback: None, + }) + .unwrap(); + } + break_rx.recv().await + }); + + let _ = tokio::join!(network1, network2); +} + +fn run_benchmark(c: &mut Criterion, payload: &[(u32, usize, &'static str)], group: &str) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic); + let mut group = c.benchmark_group(group); + group.plot_config(plot_config); + + let libp2p_setup = setup_workers::>(&rt); + for &(exponent, limit, label) in payload.iter() { + let size = 2usize.pow(exponent); + group.throughput(Throughput::Bytes(limit as u64 * size as u64)); + group.bench_with_input( + BenchmarkId::new("libp2p/serially", label), + &(size, limit), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| run_serially(Arc::clone(&libp2p_setup), size, limit)); + }, + ); + } + drop(libp2p_setup); + + // TODO: NetworkRequest::request should be implemented for Litep2pNetworkService + let litep2p_setup = setup_workers::(&rt); + // for &(exponent, limit, label) in payload.iter() { + // let size = 2usize.pow(exponent); + // group.throughput(Throughput::Bytes(limit as u64 * size as u64)); + // group.bench_with_input( + // BenchmarkId::new("litep2p/serially", label), + // &(size, limit), + // |b, &(size, limit)| { + // b.to_async(&rt).iter(|| run_serially(Arc::clone(&litep2p_setup), size, limit)); + // }, + // ); + // } + drop(litep2p_setup); +} + +fn run_benchmark_with_small_payload(c: &mut Criterion) { + run_benchmark(c, SMALL_PAYLOAD, "request_response_benchmark/small_payload"); +} + +fn run_benchmark_with_large_payload(c: &mut Criterion) { + run_benchmark(c, LARGE_PAYLOAD, "request_response_benchmark/large_payload"); +} + +criterion_group!(benches, run_benchmark_with_small_payload, run_benchmark_with_large_payload); +criterion_main!(benches); diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index 34ba4f061c44..fad7ae425858 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -19,18 +19,18 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = { workspace = true } [dependencies] -async-channel = { workspace = true } array-bytes = { workspace = true, default-features = true } +async-channel = { workspace = true } codec = { features = [ "derive", ], workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true, default-features = true } prost = { workspace = true } -sp-blockchain = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } -sc-network-types = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 5ecbec52d507..e2a91e961668 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -68,6 +68,7 @@ pub struct Behaviour { } /// Event generated by `Behaviour`. +#[derive(Debug)] pub enum BehaviourOut { /// Started a random iterative Kademlia discovery query. RandomKademliaStarted, @@ -310,6 +311,22 @@ impl Behaviour { ) { self.discovery.store_record(record_key, record_value, publisher, expires); } + + /// Start providing `key` on the DHT. + pub fn start_providing(&mut self, key: RecordKey) { + self.discovery.start_providing(key) + } + + /// Stop providing `key` on the DHT. + pub fn stop_providing(&mut self, key: &RecordKey) { + self.discovery.stop_providing(key) + } + + /// Start searching for providers on the DHT. Will later produce either a `ProvidersFound` + /// or `ProvidersNotFound` event. + pub fn get_providers(&mut self, key: RecordKey) { + self.discovery.get_providers(key) + } } impl From for BehaviourOut { @@ -375,18 +392,29 @@ impl From for BehaviourOut { }, DiscoveryOut::Discovered(peer_id) => BehaviourOut::Discovered(peer_id), DiscoveryOut::ValueFound(results, duration) => - BehaviourOut::Dht(DhtEvent::ValueFound(results), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValueFound(results.into()), Some(duration)), DiscoveryOut::ValueNotFound(key, duration) => - BehaviourOut::Dht(DhtEvent::ValueNotFound(key), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValueNotFound(key.into()), Some(duration)), DiscoveryOut::ValuePut(key, duration) => - BehaviourOut::Dht(DhtEvent::ValuePut(key), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValuePut(key.into()), Some(duration)), DiscoveryOut::PutRecordRequest(record_key, record_value, publisher, expires) => BehaviourOut::Dht( - DhtEvent::PutRecordRequest(record_key, record_value, publisher, expires), + DhtEvent::PutRecordRequest(record_key.into(), record_value, publisher, expires), None, ), DiscoveryOut::ValuePutFailed(key, duration) => - BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValuePutFailed(key.into()), Some(duration)), + DiscoveryOut::StartProvidingFailed(key) => + BehaviourOut::Dht(DhtEvent::StartProvidingFailed(key.into()), None), + DiscoveryOut::ProvidersFound(key, providers, duration) => BehaviourOut::Dht( + DhtEvent::ProvidersFound( + key.into(), + providers.into_iter().map(Into::into).collect(), + ), + Some(duration), + ), + DiscoveryOut::ProvidersNotFound(key, duration) => + BehaviourOut::Dht(DhtEvent::ProvidersNotFound(key.into()), Some(duration)), DiscoveryOut::RandomKademliaStarted => BehaviourOut::RandomKademliaStarted, } } diff --git a/substrate/client/network/src/discovery.rs b/substrate/client/network/src/discovery.rs index 49e0797c126c..917449cf228c 100644 --- a/substrate/client/network/src/discovery.rs +++ b/substrate/client/network/src/discovery.rs @@ -53,13 +53,13 @@ use futures::prelude::*; use futures_timer::Delay; use ip_network::IpNetwork; use libp2p::{ - core::{Endpoint, Multiaddr}, + core::{transport::PortUse, Endpoint, Multiaddr}, kad::{ self, - record::store::{MemoryStore, RecordStore}, + store::{MemoryStore, RecordStore}, Behaviour as Kademlia, BucketInserts, Config as KademliaConfig, Event as KademliaEvent, - GetClosestPeersError, GetRecordOk, PeerRecord, QueryId, QueryResult, Quorum, Record, - RecordKey, + Event, GetClosestPeersError, GetProvidersError, GetProvidersOk, GetRecordOk, PeerRecord, + QueryId, QueryResult, Quorum, Record, RecordKey, }, mdns::{self, tokio::Behaviour as TokioMdns}, multiaddr::Protocol, @@ -68,8 +68,8 @@ use libp2p::{ toggle::{Toggle, ToggleConnectionHandler}, DialFailure, ExternalAddrConfirmed, FromSwarm, }, - ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, PollParameters, - StreamProtocol, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, + ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, StreamProtocol, THandler, + THandlerInEvent, THandlerOutEvent, ToSwarm, }, PeerId, }; @@ -214,23 +214,14 @@ impl DiscoveryConfig { enable_mdns, kademlia_disjoint_query_paths, kademlia_protocol, - kademlia_legacy_protocol, + kademlia_legacy_protocol: _, kademlia_replication_factor, } = self; let kademlia = if let Some(ref kademlia_protocol) = kademlia_protocol { - let mut config = KademliaConfig::default(); + let mut config = KademliaConfig::new(kademlia_protocol.clone()); config.set_replication_factor(kademlia_replication_factor); - // Populate kad with both the legacy and the new protocol names. - // Remove the legacy protocol: - // https://github.com/paritytech/polkadot-sdk/issues/504 - let kademlia_protocols = if let Some(legacy_protocol) = kademlia_legacy_protocol { - vec![kademlia_protocol.clone(), legacy_protocol] - } else { - vec![kademlia_protocol.clone()] - }; - config.set_protocol_names(kademlia_protocols.into_iter().map(Into::into).collect()); config.set_record_filtering(libp2p::kad::StoreInserts::FilterBoth); @@ -466,6 +457,31 @@ impl DiscoveryBehaviour { } } } + + /// Register as a content provider on the DHT for `key`. + pub fn start_providing(&mut self, key: RecordKey) { + if let Some(kad) = self.kademlia.as_mut() { + if let Err(e) = kad.start_providing(key.clone()) { + warn!(target: "sub-libp2p", "Libp2p => Failed to start providing {key:?}: {e}."); + self.pending_events.push_back(DiscoveryOut::StartProvidingFailed(key)); + } + } + } + + /// Deregister as a content provider on the DHT for `key`. + pub fn stop_providing(&mut self, key: &RecordKey) { + if let Some(kad) = self.kademlia.as_mut() { + kad.stop_providing(key); + } + } + + /// Get content providers for `key` from the DHT. + pub fn get_providers(&mut self, key: RecordKey) { + if let Some(kad) = self.kademlia.as_mut() { + kad.get_providers(key); + } + } + /// Store a record in the Kademlia record store. pub fn store_record( &mut self, @@ -581,6 +597,15 @@ pub enum DiscoveryOut { /// Returning the corresponding key as well as the request duration. ValuePutFailed(RecordKey, Duration), + /// Starting providing a key failed. + StartProvidingFailed(RecordKey), + + /// The DHT yielded results for the providers request. + ProvidersFound(RecordKey, HashSet, Duration), + + /// Providers for the requested key were not found in the DHT. + ProvidersNotFound(RecordKey, Duration), + /// Started a random Kademlia query. /// /// Only happens if [`DiscoveryConfig::with_dht_random_walk`] has been configured to `true`. @@ -613,12 +638,14 @@ impl NetworkBehaviour for DiscoveryBehaviour { peer: PeerId, addr: &Multiaddr, role_override: Endpoint, + port_use: PortUse, ) -> Result, ConnectionDenied> { self.kademlia.handle_established_outbound_connection( connection_id, peer, addr, role_override, + port_use, ) } @@ -690,7 +717,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { Ok(list.into_iter().collect()) } - fn on_swarm_event(&mut self, event: FromSwarm) { + fn on_swarm_event(&mut self, event: FromSwarm) { match event { FromSwarm::ConnectionEstablished(e) => { self.num_connections += 1; @@ -749,22 +776,38 @@ impl NetworkBehaviour for DiscoveryBehaviour { self.mdns.on_swarm_event(FromSwarm::NewListenAddr(e)); }, FromSwarm::ExternalAddrConfirmed(e @ ExternalAddrConfirmed { addr }) => { - let new_addr = addr.clone().with(Protocol::P2p(self.local_peer_id)); + let mut address = addr.clone(); - if Self::can_add_to_dht(addr) { + if let Some(Protocol::P2p(peer_id)) = addr.iter().last() { + if peer_id != self.local_peer_id { + warn!( + target: "sub-libp2p", + "🔍 Discovered external address for a peer that is not us: {addr}", + ); + // Ensure this address is not propagated to kademlia. + return + } + } else { + address.push(Protocol::P2p(self.local_peer_id)); + } + + if Self::can_add_to_dht(&address) { // NOTE: we might re-discover the same address multiple times // in which case we just want to refrain from logging. - if self.known_external_addresses.insert(new_addr.clone()) { + if self.known_external_addresses.insert(address.clone()) { info!( target: "sub-libp2p", - "🔍 Discovered new external address for our node: {}", - new_addr, + "🔍 Discovered new external address for our node: {address}", ); } } self.kademlia.on_swarm_event(FromSwarm::ExternalAddrConfirmed(e)); }, + event => { + debug!(target: "sub-libp2p", "New unknown `FromSwarm` libp2p event: {event:?}"); + self.kademlia.on_swarm_event(event); + }, } } @@ -777,11 +820,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { self.kademlia.on_connection_handler_event(peer_id, connection_id, event); } - fn poll( - &mut self, - cx: &mut Context, - params: &mut impl PollParameters, - ) -> Poll>> { + fn poll(&mut self, cx: &mut Context) -> Poll>> { // Immediately process the content of `discovered`. if let Some(ev) = self.pending_events.pop_front() { return Poll::Ready(ToSwarm::GenerateEvent(ev)) @@ -824,7 +863,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { } } - while let Poll::Ready(ev) = self.kademlia.poll(cx, params) { + while let Poll::Ready(ev) = self.kademlia.poll(cx) { match ev { ToSwarm::GenerateEvent(ev) => match ev { KademliaEvent::RoutingUpdated { peer, .. } => { @@ -970,6 +1009,56 @@ impl NetworkBehaviour for DiscoveryBehaviour { }; return Poll::Ready(ToSwarm::GenerateEvent(ev)) }, + KademliaEvent::OutboundQueryProgressed { + result: QueryResult::GetProviders(res), + stats, + id, + .. + } => { + let ev = match res { + Ok(GetProvidersOk::FoundProviders { key, providers }) => { + debug!( + target: "sub-libp2p", + "Libp2p => Found providers {:?} for key {:?}, id {:?}, stats {:?}", + providers, + key, + id, + stats, + ); + + DiscoveryOut::ProvidersFound( + key, + providers, + stats.duration().unwrap_or_default(), + ) + }, + Ok(GetProvidersOk::FinishedWithNoAdditionalRecord { + closest_peers: _, + }) => { + debug!( + target: "sub-libp2p", + "Libp2p => Finished with no additional providers {:?}, stats {:?}, took {:?} ms", + id, + stats, + stats.duration().map(|val| val.as_millis()) + ); + + continue + }, + Err(GetProvidersError::Timeout { key, closest_peers: _ }) => { + debug!( + target: "sub-libp2p", + "Libp2p => Failed to get providers for {key:?} due to timeout.", + ); + + DiscoveryOut::ProvidersNotFound( + key, + stats.duration().unwrap_or_default(), + ) + }, + }; + return Poll::Ready(ToSwarm::GenerateEvent(ev)) + }, KademliaEvent::OutboundQueryProgressed { result: QueryResult::PutRecord(res), stats, @@ -1007,30 +1096,38 @@ impl NetworkBehaviour for DiscoveryBehaviour { e.key(), e, ), }, + KademliaEvent::OutboundQueryProgressed { + result: QueryResult::Bootstrap(res), + .. + } => match res { + Ok(ok) => debug!( + target: "sub-libp2p", + "Libp2p => DHT bootstrap progressed: {ok:?}", + ), + Err(e) => warn!( + target: "sub-libp2p", + "Libp2p => DHT bootstrap error: {e:?}", + ), + }, // We never start any other type of query. KademliaEvent::OutboundQueryProgressed { result: e, .. } => { warn!(target: "sub-libp2p", "Libp2p => Unhandled Kademlia event: {:?}", e) }, + Event::ModeChanged { new_mode } => { + debug!(target: "sub-libp2p", "Libp2p => Kademlia mode changed: {new_mode}") + }, }, ToSwarm::Dial { opts } => return Poll::Ready(ToSwarm::Dial { opts }), - ToSwarm::NotifyHandler { peer_id, handler, event } => - return Poll::Ready(ToSwarm::NotifyHandler { peer_id, handler, event }), - ToSwarm::CloseConnection { peer_id, connection } => - return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }), - ToSwarm::NewExternalAddrCandidate(observed) => - return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)), - ToSwarm::ExternalAddrConfirmed(addr) => - return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)), - ToSwarm::ExternalAddrExpired(addr) => - return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)), - ToSwarm::ListenOn { opts } => return Poll::Ready(ToSwarm::ListenOn { opts }), - ToSwarm::RemoveListener { id } => - return Poll::Ready(ToSwarm::RemoveListener { id }), + event => { + return Poll::Ready(event.map_out(|_| { + unreachable!("`GenerateEvent` is handled in a branch above; qed") + })); + }, } } // Poll mDNS. - while let Poll::Ready(ev) = self.mdns.poll(cx, params) { + while let Poll::Ready(ev) = self.mdns.poll(cx) { match ev { ToSwarm::GenerateEvent(event) => match event { mdns::Event::Discovered(list) => { @@ -1052,17 +1149,17 @@ impl NetworkBehaviour for DiscoveryBehaviour { }, // `event` is an enum with no variant ToSwarm::NotifyHandler { event, .. } => match event {}, - ToSwarm::CloseConnection { peer_id, connection } => - return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }), - ToSwarm::NewExternalAddrCandidate(observed) => - return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)), - ToSwarm::ExternalAddrConfirmed(addr) => - return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)), - ToSwarm::ExternalAddrExpired(addr) => - return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)), - ToSwarm::ListenOn { opts } => return Poll::Ready(ToSwarm::ListenOn { opts }), - ToSwarm::RemoveListener { id } => - return Poll::Ready(ToSwarm::RemoveListener { id }), + event => { + return Poll::Ready( + event + .map_in(|_| { + unreachable!("`NotifyHandler` is handled in a branch above; qed") + }) + .map_out(|_| { + unreachable!("`GenerateEvent` is handled in a branch above; qed") + }), + ); + }, } } @@ -1105,21 +1202,14 @@ mod tests { }, identity::Keypair, noise, - swarm::{Executor, Swarm, SwarmEvent}, + swarm::{Swarm, SwarmEvent}, yamux, Multiaddr, }; use sp_core::hash::H256; - use std::{collections::HashSet, pin::Pin, task::Poll}; + use std::{collections::HashSet, task::Poll, time::Duration}; - struct TokioExecutor(tokio::runtime::Runtime); - impl Executor for TokioExecutor { - fn exec(&self, f: Pin + Send>>) { - let _ = self.0.spawn(f); - } - } - - #[test] - fn discovery_working() { + #[tokio::test] + async fn discovery_working() { let mut first_swarm_peer_id_and_addr = None; let genesis_hash = H256::from_low_u64_be(1); @@ -1130,42 +1220,40 @@ mod tests { // the first swarm via `with_permanent_addresses`. let mut swarms = (0..25) .map(|i| { - let keypair = Keypair::generate_ed25519(); - - let transport = MemoryTransport::new() - .upgrade(upgrade::Version::V1) - .authenticate(noise::Config::new(&keypair).unwrap()) - .multiplex(yamux::Config::default()) - .boxed(); - - let behaviour = { - let mut config = DiscoveryConfig::new(keypair.public().to_peer_id()); - config - .with_permanent_addresses(first_swarm_peer_id_and_addr.clone()) - .allow_private_ip(true) - .allow_non_globals_in_dht(true) - .discovery_limit(50) - .with_kademlia(genesis_hash, fork_id, &protocol_id); - - config.finish() - }; - - let runtime = tokio::runtime::Runtime::new().unwrap(); - #[allow(deprecated)] - let mut swarm = libp2p::swarm::SwarmBuilder::with_executor( - transport, - behaviour, - keypair.public().to_peer_id(), - TokioExecutor(runtime), - ) - .build(); + let mut swarm = libp2p::SwarmBuilder::with_new_identity() + .with_tokio() + .with_other_transport(|keypair| { + MemoryTransport::new() + .upgrade(upgrade::Version::V1) + .authenticate(noise::Config::new(&keypair).unwrap()) + .multiplex(yamux::Config::default()) + .boxed() + }) + .unwrap() + .with_behaviour(|keypair| { + let mut config = DiscoveryConfig::new(keypair.public().to_peer_id()); + config + .with_permanent_addresses(first_swarm_peer_id_and_addr.clone()) + .allow_private_ip(true) + .allow_non_globals_in_dht(true) + .discovery_limit(50) + .with_kademlia(genesis_hash, fork_id, &protocol_id); + + config.finish() + }) + .unwrap() + .with_swarm_config(|config| { + // This is taken care of by notification protocols in non-test environment + config.with_idle_connection_timeout(Duration::from_secs(10)) + }) + .build(); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); if i == 0 { first_swarm_peer_id_and_addr = - Some((keypair.public().to_peer_id(), listen_addr.clone())) + Some((*swarm.local_peer_id(), listen_addr.clone())) } swarm.listen_on(listen_addr.clone()).unwrap(); @@ -1252,7 +1340,7 @@ mod tests { } }); - futures::executor::block_on(fut); + fut.await } #[test] diff --git a/substrate/client/network/src/event.rs b/substrate/client/network/src/event.rs index 5400d11cb6ac..e8ec1eee2545 100644 --- a/substrate/client/network/src/event.rs +++ b/substrate/client/network/src/event.rs @@ -22,12 +22,12 @@ use crate::types::ProtocolName; use bytes::Bytes; -use libp2p::{ - kad::{record::Key, PeerRecord}, - PeerId, -}; use sc_network_common::role::ObservedRole; +use sc_network_types::{ + kad::{Key, PeerRecord}, + PeerId, +}; /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] @@ -45,8 +45,17 @@ pub enum DhtEvent { /// An error has occurred while putting a record into the DHT. ValuePutFailed(Key), + /// An error occured while registering as a content provider on the DHT. + StartProvidingFailed(Key), + /// The DHT received a put record request. PutRecordRequest(Key, Vec, Option, Option), + + /// The providers for [`Key`] were found. + ProvidersFound(Key, Vec), + + /// The providers for [`Key`] were not found. + ProvidersNotFound(Key), } /// Type for events generated by networking layer. diff --git a/substrate/client/network/src/litep2p/discovery.rs b/substrate/client/network/src/litep2p/discovery.rs index 13cf8a4c6ee0..2bea2e5a80dc 100644 --- a/substrate/client/network/src/litep2p/discovery.rs +++ b/substrate/client/network/src/litep2p/discovery.rs @@ -27,13 +27,12 @@ use array_bytes::bytes2hex; use futures::{FutureExt, Stream}; use futures_timer::Delay; use ip_network::IpNetwork; -use libp2p::kad::record::Key as KademliaKey; use litep2p::{ protocol::{ libp2p::{ identify::{Config as IdentifyConfig, IdentifyEvent}, kademlia::{ - Config as KademliaConfig, ConfigBuilder as KademliaConfigBuilder, + Config as KademliaConfig, ConfigBuilder as KademliaConfigBuilder, ContentProvider, IncomingRecordValidationMode, KademliaEvent, KademliaHandle, QueryId, Quorum, Record, RecordKey, RecordsType, }, @@ -45,6 +44,7 @@ use litep2p::{ PeerId, ProtocolName, }; use parking_lot::RwLock; +use sc_network_types::kad::Key as KademliaKey; use schnellru::{ByLength, LruMap}; use std::{ @@ -144,6 +144,14 @@ pub enum DiscoveryEvent { query_id: QueryId, }, + /// Providers were successfully retrieved. + GetProvidersSuccess { + /// Query ID. + query_id: QueryId, + /// Found providers sorted by distance to provided key. + providers: Vec, + }, + /// Query failed. QueryFailed { /// Query ID. @@ -162,6 +170,9 @@ pub enum DiscoveryEvent { /// Discovery. pub struct Discovery { + /// Local peer ID. + local_peer_id: litep2p::PeerId, + /// Ping event stream. ping_event_stream: Box + Send + Unpin>, @@ -233,6 +244,7 @@ impl Discovery { /// Enables `/ipfs/ping/1.0.0` and `/ipfs/identify/1.0.0` by default and starts /// the mDNS peer discovery if it was enabled. pub fn new + Clone>( + local_peer_id: litep2p::PeerId, config: &NetworkConfiguration, genesis_hash: Hash, fork_id: Option<&str>, @@ -273,6 +285,7 @@ impl Discovery { ( Self { + local_peer_id, ping_event_stream, identify_event_stream, mdns_event_stream, @@ -402,6 +415,21 @@ impl Discovery { .await; } + /// Start providing `key`. + pub async fn start_providing(&mut self, key: KademliaKey) { + self.kademlia_handle.start_providing(key.into()).await; + } + + /// Stop providing `key`. + pub async fn stop_providing(&mut self, key: KademliaKey) { + self.kademlia_handle.stop_providing(key.into()).await; + } + + /// Get providers for `key`. + pub async fn get_providers(&mut self, key: KademliaKey) -> QueryId { + self.kademlia_handle.get_providers(key.into()).await + } + /// Check if the observed address is a known address. fn is_known_address(known: &Multiaddr, observed: &Multiaddr) -> bool { let mut known = known.iter(); @@ -553,7 +581,7 @@ impl Stream for Discovery { return Poll::Ready(Some(DiscoveryEvent::GetRecordSuccess { query_id, records })); }, - Poll::Ready(Some(KademliaEvent::PutRecordSucess { query_id, key: _ })) => + Poll::Ready(Some(KademliaEvent::PutRecordSuccess { query_id, key: _ })) => return Poll::Ready(Some(DiscoveryEvent::PutRecordSuccess { query_id })), Poll::Ready(Some(KademliaEvent::QueryFailed { query_id })) => { match this.find_node_query_id == Some(query_id) { @@ -576,6 +604,23 @@ impl Stream for Discovery { return Poll::Ready(Some(DiscoveryEvent::IncomingRecord { record })) }, + Poll::Ready(Some(KademliaEvent::GetProvidersSuccess { + provided_key, + providers, + query_id, + })) => { + log::trace!( + target: LOG_TARGET, + "`GET_PROVIDERS` for {query_id:?} with {provided_key:?} yielded {providers:?}", + ); + + return Poll::Ready(Some(DiscoveryEvent::GetProvidersSuccess { + query_id, + providers, + })) + }, + // We do not validate incoming providers. + Poll::Ready(Some(KademliaEvent::IncomingProvider { .. })) => {}, } match Pin::new(&mut this.identify_event_stream).poll_next(cx) { @@ -588,24 +633,43 @@ impl Stream for Discovery { observed_address, .. })) => { - let (is_new, expired_address) = - this.is_new_external_address(&observed_address, peer); - - if let Some(expired_address) = expired_address { - log::trace!( - target: LOG_TARGET, - "Removing expired external address expired={expired_address} is_new={is_new} observed={observed_address}", - ); - - this.pending_events.push_back(DiscoveryEvent::ExternalAddressExpired { - address: expired_address, - }); - } + let observed_address = + if let Some(Protocol::P2p(peer_id)) = observed_address.iter().last() { + if peer_id != *this.local_peer_id.as_ref() { + log::warn!( + target: LOG_TARGET, + "Discovered external address for a peer that is not us: {observed_address}", + ); + None + } else { + Some(observed_address) + } + } else { + Some(observed_address.with(Protocol::P2p(this.local_peer_id.into()))) + }; + + // Ensure that an external address with a different peer ID does not have + // side effects of evicting other external addresses via `ExternalAddressExpired`. + if let Some(observed_address) = observed_address { + let (is_new, expired_address) = + this.is_new_external_address(&observed_address, peer); + + if let Some(expired_address) = expired_address { + log::trace!( + target: LOG_TARGET, + "Removing expired external address expired={expired_address} is_new={is_new} observed={observed_address}", + ); + + this.pending_events.push_back(DiscoveryEvent::ExternalAddressExpired { + address: expired_address, + }); + } - if is_new { - this.pending_events.push_back(DiscoveryEvent::ExternalAddressDiscovered { - address: observed_address.clone(), - }); + if is_new { + this.pending_events.push_back(DiscoveryEvent::ExternalAddressDiscovered { + address: observed_address.clone(), + }); + } } return Poll::Ready(Some(DiscoveryEvent::Identified { diff --git a/substrate/client/network/src/litep2p/mod.rs b/substrate/client/network/src/litep2p/mod.rs index df4244890f96..52b2970525df 100644 --- a/substrate/client/network/src/litep2p/mod.rs +++ b/substrate/client/network/src/litep2p/mod.rs @@ -50,7 +50,6 @@ use crate::{ use codec::Encode; use futures::StreamExt; -use libp2p::kad::{PeerRecord, Record as P2PRecord, RecordKey}; use litep2p::{ config::ConfigBuilder, crypto::ed25519::Keypair, @@ -74,6 +73,7 @@ use litep2p::{ Litep2p, Litep2pEvent, ProtocolName as Litep2pProtocolName, }; use prometheus_endpoint::Registry; +use sc_network_types::kad::{Key as RecordKey, PeerRecord, Record as P2PRecord}; use sc_client_api::BlockBackend; use sc_network_common::{role::Roles, ExHashT}; @@ -143,6 +143,17 @@ struct ConnectionContext { num_connections: usize, } +/// Kademlia query we are tracking. +#[derive(Debug)] +enum KadQuery { + /// `GET_VALUE` query for key and when it was initiated. + GetValue(RecordKey, Instant), + /// `PUT_VALUE` query for key and when it was initiated. + PutValue(RecordKey, Instant), + /// `GET_PROVIDERS` query for key and when it was initiated. + GetProviders(RecordKey, Instant), +} + /// Networking backend for `litep2p`. pub struct Litep2pNetworkBackend { /// Main `litep2p` object. @@ -157,11 +168,8 @@ pub struct Litep2pNetworkBackend { /// `Peerset` handles to notification protocols. peerset_handles: HashMap, - /// Pending `GET_VALUE` queries. - pending_get_values: HashMap, - - /// Pending `PUT_VALUE` queries. - pending_put_values: HashMap, + /// Pending Kademlia queries. + pending_queries: HashMap, /// Discovery. discovery: Discovery, @@ -540,6 +548,7 @@ impl NetworkBackend for Litep2pNetworkBac let listen_addresses = Arc::new(Default::default()); let (discovery, ping_config, identify_config, kademlia_config, maybe_mdns_config) = Discovery::new( + local_peer_id, &network_config, params.genesis_hash, params.fork_id.as_deref(), @@ -614,8 +623,7 @@ impl NetworkBackend for Litep2pNetworkBac peerset_handles: notif_protocols, num_connected, discovery, - pending_put_values: HashMap::new(), - pending_get_values: HashMap::new(), + pending_queries: HashMap::new(), peerstore_handle: peer_store_handle, block_announce_protocol, event_streams: out_events::OutChannels::new(None)?, @@ -703,21 +711,30 @@ impl NetworkBackend for Litep2pNetworkBac Some(command) => match command { NetworkServiceCommand::GetValue{ key } => { let query_id = self.discovery.get_value(key.clone()).await; - self.pending_get_values.insert(query_id, (key, Instant::now())); + self.pending_queries.insert(query_id, KadQuery::GetValue(key, Instant::now())); } NetworkServiceCommand::PutValue { key, value } => { let query_id = self.discovery.put_value(key.clone(), value).await; - self.pending_put_values.insert(query_id, (key, Instant::now())); + self.pending_queries.insert(query_id, KadQuery::PutValue(key, Instant::now())); } NetworkServiceCommand::PutValueTo { record, peers, update_local_storage} => { - let kademlia_key = record.key.to_vec().into(); - let query_id = self.discovery.put_value_to_peers(record, peers, update_local_storage).await; - self.pending_put_values.insert(query_id, (kademlia_key, Instant::now())); + let kademlia_key = record.key.clone(); + let query_id = self.discovery.put_value_to_peers(record.into(), peers, update_local_storage).await; + self.pending_queries.insert(query_id, KadQuery::PutValue(kademlia_key, Instant::now())); } - NetworkServiceCommand::StoreRecord { key, value, publisher, expires } => { self.discovery.store_record(key, value, publisher.map(Into::into), expires).await; } + NetworkServiceCommand::StartProviding { key } => { + self.discovery.start_providing(key).await; + } + NetworkServiceCommand::StopProviding { key } => { + self.discovery.stop_providing(key).await; + } + NetworkServiceCommand::GetProviders { key } => { + let query_id = self.discovery.get_providers(key.clone()).await; + self.pending_queries.insert(query_id, KadQuery::GetProviders(key, Instant::now())); + } NetworkServiceCommand::EventStream { tx } => { self.event_streams.push(tx); } @@ -752,7 +769,7 @@ impl NetworkBackend for Litep2pNetworkBac } if self.litep2p.add_known_address(peer.into(), iter::once(address.clone())) == 0usize { - log::warn!( + log::debug!( target: LOG_TARGET, "couldn't add known address ({address}) for {peer:?}, unsupported transport" ); @@ -820,12 +837,8 @@ impl NetworkBackend for Litep2pNetworkBac } } Some(DiscoveryEvent::GetRecordSuccess { query_id, records }) => { - match self.pending_get_values.remove(&query_id) { - None => log::warn!( - target: LOG_TARGET, - "`GET_VALUE` succeeded for a non-existent query", - ), - Some((key, started)) => { + match self.pending_queries.remove(&query_id) { + Some(KadQuery::GetValue(key, started)) => { log::trace!( target: LOG_TARGET, "`GET_VALUE` for {:?} ({query_id:?}) succeeded", @@ -835,7 +848,7 @@ impl NetworkBackend for Litep2pNetworkBac self.event_streams.send( Event::Dht( DhtEvent::ValueFound( - record + record.into() ) ) ); @@ -847,23 +860,26 @@ impl NetworkBackend for Litep2pNetworkBac .with_label_values(&["value-get"]) .observe(started.elapsed().as_secs_f64()); } - } + }, + query => { + log::error!( + target: LOG_TARGET, + "Missing/invalid pending query for `GET_VALUE`: {query:?}" + ); + debug_assert!(false); + }, } } Some(DiscoveryEvent::PutRecordSuccess { query_id }) => { - match self.pending_put_values.remove(&query_id) { - None => log::warn!( - target: LOG_TARGET, - "`PUT_VALUE` succeeded for a non-existent query", - ), - Some((key, started)) => { + match self.pending_queries.remove(&query_id) { + Some(KadQuery::PutValue(key, started)) => { log::trace!( target: LOG_TARGET, "`PUT_VALUE` for {key:?} ({query_id:?}) succeeded", ); self.event_streams.send(Event::Dht( - DhtEvent::ValuePut(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValuePut(key) )); if let Some(ref metrics) = self.metrics { @@ -872,42 +888,57 @@ impl NetworkBackend for Litep2pNetworkBac .with_label_values(&["value-put"]) .observe(started.elapsed().as_secs_f64()); } + }, + query => { + log::error!( + target: LOG_TARGET, + "Missing/invalid pending query for `PUT_VALUE`: {query:?}" + ); + debug_assert!(false); } } } - Some(DiscoveryEvent::QueryFailed { query_id }) => { - match self.pending_get_values.remove(&query_id) { - None => match self.pending_put_values.remove(&query_id) { - None => log::warn!( + Some(DiscoveryEvent::GetProvidersSuccess { query_id, providers }) => { + match self.pending_queries.remove(&query_id) { + Some(KadQuery::GetProviders(key, started)) => { + log::trace!( target: LOG_TARGET, - "non-existent query failed ({query_id:?})", - ), - Some((key, started)) => { - log::debug!( - target: LOG_TARGET, - "`PUT_VALUE` ({query_id:?}) failed for key {key:?}", - ); + "`GET_PROVIDERS` for {key:?} ({query_id:?}) succeeded", + ); - self.event_streams.send(Event::Dht( - DhtEvent::ValuePutFailed(libp2p::kad::RecordKey::new(&key)) - )); + self.event_streams.send(Event::Dht( + DhtEvent::ProvidersFound( + key.into(), + providers.into_iter().map(|p| p.peer.into()).collect() + ) + )); - if let Some(ref metrics) = self.metrics { - metrics - .kademlia_query_duration - .with_label_values(&["value-put-failed"]) - .observe(started.elapsed().as_secs_f64()); - } + if let Some(ref metrics) = self.metrics { + metrics + .kademlia_query_duration + .with_label_values(&["providers-get"]) + .observe(started.elapsed().as_secs_f64()); } + }, + query => { + log::error!( + target: LOG_TARGET, + "Missing/invalid pending query for `GET_PROVIDERS`: {query:?}" + ); + debug_assert!(false); } - Some((key, started)) => { + } + } + Some(DiscoveryEvent::QueryFailed { query_id }) => { + match self.pending_queries.remove(&query_id) { + Some(KadQuery::GetValue(key, started)) => { log::debug!( target: LOG_TARGET, "`GET_VALUE` ({query_id:?}) failed for key {key:?}", ); self.event_streams.send(Event::Dht( - DhtEvent::ValueNotFound(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValueNotFound(key) )); if let Some(ref metrics) = self.metrics { @@ -916,6 +947,46 @@ impl NetworkBackend for Litep2pNetworkBac .with_label_values(&["value-get-failed"]) .observe(started.elapsed().as_secs_f64()); } + }, + Some(KadQuery::PutValue(key, started)) => { + log::debug!( + target: LOG_TARGET, + "`PUT_VALUE` ({query_id:?}) failed for key {key:?}", + ); + + self.event_streams.send(Event::Dht( + DhtEvent::ValuePutFailed(key) + )); + + if let Some(ref metrics) = self.metrics { + metrics + .kademlia_query_duration + .with_label_values(&["value-put-failed"]) + .observe(started.elapsed().as_secs_f64()); + } + }, + Some(KadQuery::GetProviders(key, started)) => { + log::debug!( + target: LOG_TARGET, + "`GET_PROVIDERS` ({query_id:?}) failed for key {key:?}" + ); + + self.event_streams.send(Event::Dht( + DhtEvent::ProvidersNotFound(key) + )); + + if let Some(ref metrics) = self.metrics { + metrics + .kademlia_query_duration + .with_label_values(&["providers-get-failed"]) + .observe(started.elapsed().as_secs_f64()); + } + }, + None => { + log::warn!( + target: LOG_TARGET, + "non-existent query failed ({query_id:?})", + ); } } } @@ -963,7 +1034,7 @@ impl NetworkBackend for Litep2pNetworkBac Some(DiscoveryEvent::IncomingRecord { record: Record { key, value, publisher, expires }} ) => { self.event_streams.send(Event::Dht( DhtEvent::PutRecordRequest( - libp2p::kad::RecordKey::new(&key), + key.into(), value, publisher.map(Into::into), expires, @@ -985,7 +1056,15 @@ impl NetworkBackend for Litep2pNetworkBac let direction = match endpoint { Endpoint::Dialer { .. } => "out", - Endpoint::Listener { .. } => "in", + Endpoint::Listener { .. } => { + // Increment incoming connections counter. + // + // Note: For litep2p these are represented by established negotiated connections, + // while for libp2p (legacy) these represent not-yet-negotiated connections. + metrics.incoming_connections_total.inc(); + + "in" + }, }; metrics.connections_opened_total.with_label_values(&[direction]).inc(); @@ -1057,6 +1136,7 @@ impl NetworkBackend for Litep2pNetworkBac NegotiationError::ParseError(_) => "parse-error", NegotiationError::IoError(_) => "io-error", NegotiationError::WebSocket(_) => "webscoket-error", + NegotiationError::BadSignature => "bad-signature", } }; @@ -1073,7 +1153,13 @@ impl NetworkBackend for Litep2pNetworkBac metrics.pending_connections_errors_total.with_label_values(&["transport-errors"]).inc(); } } - _ => {} + None => { + log::error!( + target: LOG_TARGET, + "Litep2p backend terminated" + ); + return + } }, } } diff --git a/substrate/client/network/src/litep2p/service.rs b/substrate/client/network/src/litep2p/service.rs index 693217f5ad94..d270e90efdf5 100644 --- a/substrate/client/network/src/litep2p/service.rs +++ b/substrate/client/network/src/litep2p/service.rs @@ -32,15 +32,15 @@ use crate::{ RequestFailure, Signature, }; -use crate::litep2p::Record; use codec::DecodeAll; use futures::{channel::oneshot, stream::BoxStream}; -use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; +use libp2p::identity::SigningError; use litep2p::{ addresses::PublicAddresses, crypto::ed25519::Keypair, types::multiaddr::Multiaddr as LiteP2pMultiaddr, }; use parking_lot::RwLock; +use sc_network_types::kad::{Key as KademliaKey, Record}; use sc_network_common::{ role::{ObservedRole, Roles}, @@ -104,6 +104,15 @@ pub enum NetworkServiceCommand { expires: Option, }, + /// Start providing `key`. + StartProviding { key: KademliaKey }, + + /// Stop providing `key`. + StopProviding { key: KademliaKey }, + + /// Get providers for `key`. + GetProviders { key: KademliaKey }, + /// Query network status. Status { /// `oneshot::Sender` for sending the status. @@ -266,12 +275,7 @@ impl NetworkDHTProvider for Litep2pNetworkService { let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::PutValue { key, value }); } - fn put_record_to( - &self, - record: libp2p::kad::Record, - peers: HashSet, - update_local_storage: bool, - ) { + fn put_record_to(&self, record: Record, peers: HashSet, update_local_storage: bool) { let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::PutValueTo { record: Record { key: record.key.to_vec().into(), @@ -301,6 +305,18 @@ impl NetworkDHTProvider for Litep2pNetworkService { expires, }); } + + fn start_providing(&self, key: KademliaKey) { + let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::StartProviding { key }); + } + + fn stop_providing(&self, key: KademliaKey) { + let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::StopProviding { key }); + } + + fn get_providers(&self, key: KademliaKey) { + let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::GetProviders { key }); + } } #[async_trait::async_trait] diff --git a/substrate/client/network/src/litep2p/shim/notification/peerset.rs b/substrate/client/network/src/litep2p/shim/notification/peerset.rs index 2fd7920909e3..fb822794ccf0 100644 --- a/substrate/client/network/src/litep2p/shim/notification/peerset.rs +++ b/substrate/client/network/src/litep2p/shim/notification/peerset.rs @@ -88,6 +88,8 @@ const DISCONNECT_ADJUSTMENT: Reputation = Reputation::new(-256, "Peer disconnect const OPEN_FAILURE_ADJUSTMENT: Reputation = Reputation::new(-1024, "Open failure"); /// Is the peer reserved? +/// +/// Regular peers count towards slot allocation. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Reserved { Yes, @@ -118,6 +120,15 @@ pub enum Direction { Outbound(Reserved), } +impl Direction { + fn set_reserved(&mut self, new_reserved: Reserved) { + match self { + Direction::Inbound(ref mut reserved) | Direction::Outbound(ref mut reserved) => + *reserved = new_reserved, + } + } +} + impl From for traits::Direction { fn from(direction: Direction) -> traits::Direction { match direction { @@ -784,7 +795,9 @@ impl Peerset { } /// Calculate how many of the connected peers were counted as normal inbound/outbound peers - /// which is needed to adjust slot counts when new reserved peers are added + /// which is needed to adjust slot counts when new reserved peers are added. + /// + /// If the peer is not already in the [`Peerset`], it is added as a disconnected peer. fn calculate_slot_adjustment<'a>( &'a mut self, peers: impl Iterator, @@ -819,6 +832,26 @@ impl Peerset { }) } + /// Checks if the peer should be disconnected based on the current state of the [`Peerset`] + /// and the provided direction. + /// + /// Note: The role of the peer is not checked. + fn should_disconnect(&self, direction: Direction) -> bool { + match direction { + Direction::Inbound(_) => self.num_in >= self.max_in, + Direction::Outbound(_) => self.num_out >= self.max_out, + } + } + + /// Increment the slot count for given peer. + fn increment_slot(&mut self, direction: Direction) { + match direction { + Direction::Inbound(Reserved::No) => self.num_in += 1, + Direction::Outbound(Reserved::No) => self.num_out += 1, + _ => {}, + } + } + /// Get the number of inbound peers. #[cfg(test)] pub fn num_in(&self) -> usize { @@ -949,8 +982,9 @@ impl Stream for Peerset { }, // set new reserved peers for the protocol // - // current reserved peers not in the new set are disconnected and the new reserved - // peers are scheduled for outbound substreams + // Current reserved peers not in the new set are moved to the regular set of peers + // or disconnected (if there are no slots available). The new reserved peers are + // scheduled for outbound substreams PeersetCommand::SetReservedPeers { peers } => { log::debug!(target: LOG_TARGET, "{}: set reserved peers {peers:?}", self.protocol); @@ -960,39 +994,58 @@ impl Stream for Peerset { // // calculate how many of the previously connected peers were counted as regular // peers and substract these counts from `num_out`/`num_in` + // + // If a reserved peer is not already tracked, it is added as disconnected by + // `calculate_slot_adjustment`. This ensures at the next slot allocation (1sec) + // that we'll try to establish a connection with the reserved peer. let (in_peers, out_peers) = self.calculate_slot_adjustment(peers.iter()); self.num_out -= out_peers; self.num_in -= in_peers; - // add all unknown peers to `self.peers` - peers.iter().for_each(|peer| { - if !self.peers.contains_key(peer) { - self.peers.insert(*peer, PeerState::Disconnected); - } - }); - - // collect all peers who are not in the new reserved set - let peers_to_remove = self - .peers - .iter() - .filter_map(|(peer, _)| (!peers.contains(peer)).then_some(*peer)) - .collect::>(); + // collect all *reserved* peers who are not in the new reserved set + let reserved_peers_maybe_remove = + self.reserved_peers.difference(&peers).cloned().collect::>(); self.reserved_peers = peers; - let peers = peers_to_remove + let peers_to_remove = reserved_peers_maybe_remove .into_iter() .filter(|peer| { match self.peers.remove(&peer) { - Some(PeerState::Connected { direction }) => { - log::trace!( - target: LOG_TARGET, - "{}: close connection to {peer:?}, direction {direction:?}", - self.protocol, - ); - - self.peers.insert(*peer, PeerState::Closing { direction }); - true + Some(PeerState::Connected { mut direction }) => { + // The direction contains a `Reserved::Yes` flag, because this + // is a reserve peer that we want to close. + // The `Reserved::Yes` ensures we don't adjust the slot count + // when the substream is closed. + + let disconnect = + self.reserved_only || self.should_disconnect(direction); + + if disconnect { + log::trace!( + target: LOG_TARGET, + "{}: close connection to previously reserved {peer:?}, direction {direction:?}", + self.protocol, + ); + + self.peers.insert(*peer, PeerState::Closing { direction }); + true + } else { + log::trace!( + target: LOG_TARGET, + "{}: {peer:?} is no longer reserved, move to regular peers, direction {direction:?}", + self.protocol, + ); + + // The peer is kept connected as non-reserved. This will + // further count towards the slot count. + direction.set_reserved(Reserved::No); + self.increment_slot(direction); + + self.peers + .insert(*peer, PeerState::Connected { direction }); + false + } }, // substream might have been opening but not yet fully open when // the protocol request the reserved set to be changed @@ -1021,11 +1074,13 @@ impl Stream for Peerset { log::trace!( target: LOG_TARGET, - "{}: close substreams to {peers:?}", + "{}: close substreams to {peers_to_remove:?}", self.protocol, ); - return Poll::Ready(Some(PeersetNotificationCommand::CloseSubstream { peers })) + return Poll::Ready(Some(PeersetNotificationCommand::CloseSubstream { + peers: peers_to_remove, + })) }, PeersetCommand::AddReservedPeers { peers } => { log::debug!(target: LOG_TARGET, "{}: add reserved peers {peers:?}", self.protocol); @@ -1102,6 +1157,7 @@ impl Stream for Peerset { self.peers.insert(*peer, PeerState::Backoff); None }, + // if there is a rapid change in substream state, the peer may // be canceled when the substream is asked to be closed. // @@ -1122,6 +1178,7 @@ impl Stream for Peerset { self.peers.insert(*peer, PeerState::Canceled { direction }); None }, + // substream to the peer might have failed to open which caused // the peer to be backed off // @@ -1138,6 +1195,7 @@ impl Stream for Peerset { self.peers.insert(*peer, PeerState::Disconnected); None }, + // if a node disconnects, it's put into `PeerState::Closing` // which indicates that `Peerset` wants the substream closed and // has asked litep2p to close it but it hasn't yet received a @@ -1167,125 +1225,70 @@ impl Stream for Peerset { // if there are enough slots, the peer is just converted to // a regular peer and the used slot count is increased and if the // peer cannot be accepted, litep2p is asked to close the substream. - PeerState::Connected { direction } => match direction { - Direction::Inbound(_) => match self.num_in < self.max_in { - true => { - log::trace!( - target: LOG_TARGET, - "{}: {peer:?} converted to regular inbound peer (inbound open)", - self.protocol, - ); - - self.num_in += 1; - self.peers.insert( - *peer, - PeerState::Connected { - direction: Direction::Inbound(Reserved::No), - }, - ); - - None - }, - false => { - self.peers.insert( - *peer, - PeerState::Closing { - direction: Direction::Inbound(Reserved::Yes), - }, - ); - - Some(*peer) - }, - }, - Direction::Outbound(_) => match self.num_out < self.max_out { - true => { - log::trace!( - target: LOG_TARGET, - "{}: {peer:?} converted to regular outbound peer (outbound open)", - self.protocol, - ); - - self.num_out += 1; - self.peers.insert( - *peer, - PeerState::Connected { - direction: Direction::Outbound(Reserved::No), - }, - ); - - None - }, - false => { - self.peers.insert( - *peer, - PeerState::Closing { - direction: Direction::Outbound(Reserved::Yes), - }, - ); - - Some(*peer) - }, - }, + PeerState::Connected { mut direction } => { + let disconnect = self.should_disconnect(direction); + + if disconnect { + log::trace!( + target: LOG_TARGET, + "{}: close connection to removed reserved {peer:?}, direction {direction:?}", + self.protocol, + ); + + self.peers.insert(*peer, PeerState::Closing { direction }); + Some(*peer) + } else { + log::trace!( + target: LOG_TARGET, + "{}: {peer:?} converted to regular peer {peer:?} direction {direction:?}", + self.protocol, + ); + + // The peer is kept connected as non-reserved. This will + // further count towards the slot count. + direction.set_reserved(Reserved::No); + self.increment_slot(direction); + + self.peers + .insert(*peer, PeerState::Connected { direction }); + + None + } }, - PeerState::Opening { direction } => match direction { - Direction::Inbound(_) => match self.num_in < self.max_in { - true => { - log::trace!( - target: LOG_TARGET, - "{}: {peer:?} converted to regular inbound peer (inbound opening)", - self.protocol, - ); - - self.num_in += 1; - self.peers.insert( - *peer, - PeerState::Opening { - direction: Direction::Inbound(Reserved::No), - }, - ); - - None - }, - false => { - self.peers.insert( - *peer, - PeerState::Canceled { - direction: Direction::Inbound(Reserved::Yes), - }, - ); - - None - }, - }, - Direction::Outbound(_) => match self.num_out < self.max_out { - true => { - log::trace!( - target: LOG_TARGET, - "{}: {peer:?} converted to regular outbound peer (outbound opening)", - self.protocol, - ); - - self.num_out += 1; - self.peers.insert( - *peer, - PeerState::Opening { - direction: Direction::Outbound(Reserved::No), - }, - ); - - None - }, - false => { - self.peers.insert( - *peer, - PeerState::Canceled { - direction: Direction::Outbound(Reserved::Yes), - }, - ); - - None - }, - }, + + PeerState::Opening { mut direction } => { + let disconnect = self.should_disconnect(direction); + + if disconnect { + log::trace!( + target: LOG_TARGET, + "{}: cancel substream to disconnect removed reserved peer {peer:?}, direction {direction:?}", + self.protocol, + ); + + self.peers.insert( + *peer, + PeerState::Canceled { + direction + }, + ); + } else { + log::trace!( + target: LOG_TARGET, + "{}: {peer:?} converted to regular peer {peer:?} direction {direction:?}", + self.protocol, + ); + + // The peer is kept connected as non-reserved. This will + // further count towards the slot count. + direction.set_reserved(Reserved::No); + self.increment_slot(direction); + + self.peers + .insert(*peer, PeerState::Opening { direction }); + } + + None }, } }) @@ -1373,12 +1376,17 @@ impl Stream for Peerset { // if the number of outbound peers is lower than the desired amount of outbound peers, // query `PeerStore` and try to get a new outbound candidated. if self.num_out < self.max_out && !self.reserved_only { + // From the candidates offered by the peerstore we need to ignore: + // - all peers that are not in the `PeerState::Disconnected` state (ie they are + // connected / closing) + // - reserved peers since we initiated a connection to them in the previous step let ignore: HashSet = self .peers .iter() .filter_map(|(peer, state)| { (!std::matches!(state, PeerState::Disconnected)).then_some(*peer) }) + .chain(self.reserved_peers.iter().cloned()) .collect(); let peers: Vec<_> = diff --git a/substrate/client/network/src/litep2p/shim/notification/tests/peerset.rs b/substrate/client/network/src/litep2p/shim/notification/tests/peerset.rs index 4f7bfffaa1fc..295a5b441b3e 100644 --- a/substrate/client/network/src/litep2p/shim/notification/tests/peerset.rs +++ b/substrate/client/network/src/litep2p/shim/notification/tests/peerset.rs @@ -794,8 +794,6 @@ async fn set_reserved_peers_but_available_slots() { // when `Peerset` is polled (along with two random peers) and later on `SetReservedPeers` // is called with the common peer and with two new random peers let common_peer = *known_peers.iter().next().unwrap(); - let disconnected_peers = known_peers.iter().skip(1).copied().collect::>(); - assert_eq!(disconnected_peers.len(), 2); let (mut peerset, to_peerset) = Peerset::new( ProtocolName::from("/notif/1"), @@ -809,6 +807,8 @@ async fn set_reserved_peers_but_available_slots() { assert_eq!(peerset.num_in(), 0usize); assert_eq!(peerset.num_out(), 0usize); + // We have less than 25 outbound peers connected. At the next slot allocation we + // query the `peerstore_handle` for more peers to connect to. match peerset.next().await { Some(PeersetNotificationCommand::OpenSubstream { peers: out_peers }) => { assert_eq!(out_peers.len(), 3); @@ -845,29 +845,167 @@ async fn set_reserved_peers_but_available_slots() { .unbounded_send(PeersetCommand::SetReservedPeers { peers: reserved_peers.clone() }) .unwrap(); + // The command `SetReservedPeers` might evict currently reserved peers if + // we don't have enough slot capacity to move them to regular nodes. + // In this case, we did not have previously any reserved peers. match peerset.next().await { - Some(PeersetNotificationCommand::CloseSubstream { peers: out_peers }) => { - assert_eq!(out_peers.len(), 2); + Some(PeersetNotificationCommand::CloseSubstream { peers }) => { + // This ensures we don't disconnect peers when receiving `SetReservedPeers`. + assert_eq!(peers.len(), 0); + }, + event => panic!("invalid event: {event:?}"), + } - for peer in &out_peers { - assert!(disconnected_peers.contains(peer)); + // verify that `Peerset` is aware of five peers, with two of them as outbound. + assert_eq!(peerset.peers().len(), 5); + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 2usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); + + match peerset.next().await { + Some(PeersetNotificationCommand::OpenSubstream { peers }) => { + assert_eq!(peers.len(), 2); + assert!(!peers.contains(&common_peer)); + + for peer in &peers { + assert!(reserved_peers.contains(peer)); + assert!(peerset.reserved_peers().contains(peer)); assert_eq!( peerset.peers().get(peer), - Some(&PeerState::Closing { direction: Direction::Outbound(Reserved::No) }), + Some(&PeerState::Opening { direction: Direction::Outbound(Reserved::Yes) }), + ); + } + }, + event => panic!("invalid event: {event:?}"), + } + + assert_eq!(peerset.peers().len(), 5); + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 2usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); +} + +#[tokio::test] +async fn set_reserved_peers_move_previously_reserved() { + sp_tracing::try_init_simple(); + + let peerstore_handle = Arc::new(peerstore_handle_test()); + let known_peers = (0..3) + .map(|_| { + let peer = PeerId::random(); + peerstore_handle.add_known_peer(peer); + peer + }) + .collect::>(); + + // We'll keep this peer as reserved and move the the others to regular nodes. + let common_peer = *known_peers.iter().next().unwrap(); + let moved_peers = known_peers.iter().skip(1).copied().collect::>(); + let known_peers = known_peers.into_iter().collect::>(); + assert_eq!(moved_peers.len(), 2); + + let (mut peerset, to_peerset) = Peerset::new( + ProtocolName::from("/notif/1"), + 25, + 25, + false, + known_peers.clone(), + Default::default(), + peerstore_handle, + ); + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 0usize); + + // We are not connected to the reserved peers. + match peerset.next().await { + Some(PeersetNotificationCommand::OpenSubstream { peers: out_peers }) => { + assert_eq!(out_peers.len(), 3); + + for peer in &out_peers { + assert_eq!( + peerset.peers().get(&peer), + Some(&PeerState::Opening { direction: Direction::Outbound(Reserved::Yes) }) ); } }, event => panic!("invalid event: {event:?}"), } - // verify that `Peerset` is aware of five peers, with two of them as outbound - // (the two disconnected peers) + // verify all three peers are marked as reserved peers and they don't count towards + // slot allocation. + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 0usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); + + // report that all substreams were opened + for peer in &known_peers { + assert!(std::matches!( + peerset.report_substream_opened(*peer, traits::Direction::Outbound), + OpenResult::Accept { .. } + )); + assert_eq!( + peerset.peers().get(peer), + Some(&PeerState::Connected { direction: Direction::Outbound(Reserved::Yes) }) + ); + } + + // set reserved peers with `common_peer` being one of them + let reserved_peers = HashSet::from_iter([common_peer, PeerId::random(), PeerId::random()]); + to_peerset + .unbounded_send(PeersetCommand::SetReservedPeers { peers: reserved_peers.clone() }) + .unwrap(); + + // The command `SetReservedPeers` might evict currently reserved peers if + // we don't have enough slot capacity to move them to regular nodes. + // In this case, we have enough capacity. + match peerset.next().await { + Some(PeersetNotificationCommand::CloseSubstream { peers }) => { + // This ensures we don't disconnect peers when receiving `SetReservedPeers`. + assert_eq!(peers.len(), 0); + }, + event => panic!("invalid event: {event:?}"), + } + + // verify that `Peerset` is aware of five peers. + // 2 of the previously reserved peers are moved as outbound regular peers and + // count towards slot allocation. assert_eq!(peerset.peers().len(), 5); assert_eq!(peerset.num_in(), 0usize); assert_eq!(peerset.num_out(), 2usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); + + // Ensure the previously reserved are not regular nodes. + for (peer, state) in peerset.peers() { + // This peer was previously reserved and remained reserved after `SetReservedPeers`. + if peer == &common_peer { + assert_eq!( + state, + &PeerState::Connected { direction: Direction::Outbound(Reserved::Yes) } + ); + continue + } + + // Part of the new reserved nodes. + if reserved_peers.contains(peer) { + assert_eq!(state, &PeerState::Disconnected); + continue + } + + // Previously reserved, but remained connected. + if moved_peers.contains(peer) { + // This was previously `Reseved::Yes` but moved to regular nodes. + assert_eq!( + state, + &PeerState::Connected { direction: Direction::Outbound(Reserved::No) } + ); + continue + } + panic!("Invalid state peer={peer:?} state={state:?}"); + } match peerset.next().await { Some(PeersetNotificationCommand::OpenSubstream { peers }) => { + // Open desires with newly reserved. assert_eq!(peers.len(), 2); assert!(!peers.contains(&common_peer)); @@ -885,7 +1023,103 @@ async fn set_reserved_peers_but_available_slots() { assert_eq!(peerset.peers().len(), 5); assert_eq!(peerset.num_in(), 0usize); - - // two substreams are closing still closing assert_eq!(peerset.num_out(), 2usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); +} + +#[tokio::test] +async fn set_reserved_peers_cannot_move_previously_reserved() { + sp_tracing::try_init_simple(); + + let peerstore_handle = Arc::new(peerstore_handle_test()); + let known_peers = (0..3) + .map(|_| { + let peer = PeerId::random(); + peerstore_handle.add_known_peer(peer); + peer + }) + .collect::>(); + + // We'll keep this peer as reserved and move the the others to regular nodes. + let common_peer = *known_peers.iter().next().unwrap(); + let moved_peers = known_peers.iter().skip(1).copied().collect::>(); + let known_peers = known_peers.into_iter().collect::>(); + assert_eq!(moved_peers.len(), 2); + + // We don't have capacity to move peers. + let (mut peerset, to_peerset) = Peerset::new( + ProtocolName::from("/notif/1"), + 0, + 0, + false, + known_peers.clone(), + Default::default(), + peerstore_handle, + ); + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 0usize); + + // We are not connected to the reserved peers. + match peerset.next().await { + Some(PeersetNotificationCommand::OpenSubstream { peers: out_peers }) => { + assert_eq!(out_peers.len(), 3); + + for peer in &out_peers { + assert_eq!( + peerset.peers().get(&peer), + Some(&PeerState::Opening { direction: Direction::Outbound(Reserved::Yes) }) + ); + } + }, + event => panic!("invalid event: {event:?}"), + } + + // verify all three peers are marked as reserved peers and they don't count towards + // slot allocation. + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 0usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); + + // report that all substreams were opened + for peer in &known_peers { + assert!(std::matches!( + peerset.report_substream_opened(*peer, traits::Direction::Outbound), + OpenResult::Accept { .. } + )); + assert_eq!( + peerset.peers().get(peer), + Some(&PeerState::Connected { direction: Direction::Outbound(Reserved::Yes) }) + ); + } + + // set reserved peers with `common_peer` being one of them + let reserved_peers = HashSet::from_iter([common_peer, PeerId::random(), PeerId::random()]); + to_peerset + .unbounded_send(PeersetCommand::SetReservedPeers { peers: reserved_peers.clone() }) + .unwrap(); + + // The command `SetReservedPeers` might evict currently reserved peers if + // we don't have enough slot capacity to move them to regular nodes. + // In this case, we don't have enough capacity. + match peerset.next().await { + Some(PeersetNotificationCommand::CloseSubstream { peers }) => { + // This ensures we don't disconnect peers when receiving `SetReservedPeers`. + assert_eq!(peers.len(), 2); + + for peer in peers { + // Ensure common peer is not disconnected. + assert_ne!(common_peer, peer); + + assert_eq!( + peerset.peers().get(&peer), + Some(&PeerState::Closing { direction: Direction::Outbound(Reserved::Yes) }) + ); + } + }, + event => panic!("invalid event: {event:?}"), + } + + assert_eq!(peerset.num_in(), 0usize); + assert_eq!(peerset.num_out(), 0usize); + assert_eq!(peerset.reserved_peers().len(), 3usize); } diff --git a/substrate/client/network/src/litep2p/shim/request_response/mod.rs b/substrate/client/network/src/litep2p/shim/request_response/mod.rs index bfd7a60ef9fe..146f2e4add97 100644 --- a/substrate/client/network/src/litep2p/shim/request_response/mod.rs +++ b/substrate/client/network/src/litep2p/shim/request_response/mod.rs @@ -320,7 +320,7 @@ impl RequestResponseProtocol { &mut self, peer: litep2p::PeerId, request_id: RequestId, - fallback: Option, + _fallback: Option, response: Vec, ) { match self.pending_inbound_responses.remove(&request_id) { @@ -337,10 +337,7 @@ impl RequestResponseProtocol { response.len(), ); - let _ = tx.send(Ok(( - response, - fallback.map_or_else(|| self.protocol.clone(), Into::into), - ))); + let _ = tx.send(Ok((response, self.protocol.clone()))); self.metrics.register_outbound_request_success(started.elapsed()); }, } diff --git a/substrate/client/network/src/network_state.rs b/substrate/client/network/src/network_state.rs index cf8b8b55a7ff..65fd494739ee 100644 --- a/substrate/client/network/src/network_state.rs +++ b/substrate/client/network/src/network_state.rs @@ -106,7 +106,7 @@ pub enum Endpoint { impl From for PeerEndpoint { fn from(endpoint: ConnectedPoint) -> Self { match endpoint { - ConnectedPoint::Dialer { address, role_override } => + ConnectedPoint::Dialer { address, role_override, port_use: _ } => Self::Dialing(address, role_override.into()), ConnectedPoint::Listener { local_addr, send_back_addr } => Self::Listening { local_addr, send_back_addr }, diff --git a/substrate/client/network/src/peer_info.rs b/substrate/client/network/src/peer_info.rs index 21eeea6bcc0c..a673f06fd622 100644 --- a/substrate/client/network/src/peer_info.rs +++ b/substrate/client/network/src/peer_info.rs @@ -25,7 +25,7 @@ use either::Either; use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ - core::{ConnectedPoint, Endpoint}, + core::{transport::PortUse, ConnectedPoint, Endpoint}, identify::{ Behaviour as Identify, Config as IdentifyConfig, Event as IdentifyEvent, Info as IdentifyInfo, @@ -38,8 +38,8 @@ use libp2p::{ ExternalAddrConfirmed, FromSwarm, ListenFailure, }, ConnectionDenied, ConnectionHandler, ConnectionHandlerSelect, ConnectionId, - NetworkBehaviour, NewExternalAddrCandidate, PollParameters, THandler, THandlerInEvent, - THandlerOutEvent, ToSwarm, + NetworkBehaviour, NewExternalAddrCandidate, THandler, THandlerInEvent, THandlerOutEvent, + ToSwarm, }, Multiaddr, PeerId, }; @@ -275,23 +275,26 @@ impl NetworkBehaviour for PeerInfoBehaviour { peer: PeerId, addr: &Multiaddr, role_override: Endpoint, + port_use: PortUse, ) -> Result, ConnectionDenied> { let ping_handler = self.ping.handle_established_outbound_connection( connection_id, peer, addr, role_override, + port_use, )?; let identify_handler = self.identify.handle_established_outbound_connection( connection_id, peer, addr, role_override, + port_use, )?; Ok(ping_handler.select(identify_handler)) } - fn on_swarm_event(&mut self, event: FromSwarm) { + fn on_swarm_event(&mut self, event: FromSwarm) { match event { FromSwarm::ConnectionEstablished( e @ ConnectionEstablished { peer_id, endpoint, .. }, @@ -319,22 +322,21 @@ impl NetworkBehaviour for PeerInfoBehaviour { peer_id, connection_id, endpoint, - handler, + cause, remaining_established, }) => { - let (ping_handler, identity_handler) = handler.into_inner(); self.ping.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed { peer_id, connection_id, endpoint, - handler: ping_handler, + cause, remaining_established, })); self.identify.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed { peer_id, connection_id, endpoint, - handler: identity_handler, + cause, remaining_established, })); @@ -369,18 +371,21 @@ impl NetworkBehaviour for PeerInfoBehaviour { send_back_addr, error, connection_id, + peer_id, }) => { self.ping.on_swarm_event(FromSwarm::ListenFailure(ListenFailure { local_addr, send_back_addr, error, connection_id, + peer_id, })); self.identify.on_swarm_event(FromSwarm::ListenFailure(ListenFailure { local_addr, send_back_addr, error, connection_id, + peer_id, })); }, FromSwarm::ListenerError(e) => { @@ -438,6 +443,11 @@ impl NetworkBehaviour for PeerInfoBehaviour { self.ping.on_swarm_event(FromSwarm::NewListenAddr(e)); self.identify.on_swarm_event(FromSwarm::NewListenAddr(e)); }, + event => { + debug!(target: "sub-libp2p", "New unknown `FromSwarm` libp2p event: {event:?}"); + self.ping.on_swarm_event(event); + self.identify.on_swarm_event(event); + }, } } @@ -455,47 +465,29 @@ impl NetworkBehaviour for PeerInfoBehaviour { } } - fn poll( - &mut self, - cx: &mut Context, - params: &mut impl PollParameters, - ) -> Poll>> { + fn poll(&mut self, cx: &mut Context) -> Poll>> { if let Some(event) = self.pending_actions.pop_front() { return Poll::Ready(event) } loop { - match self.ping.poll(cx, params) { + match self.ping.poll(cx) { Poll::Pending => break, Poll::Ready(ToSwarm::GenerateEvent(ev)) => { if let PingEvent { peer, result: Ok(rtt), connection } = ev { self.handle_ping_report(&peer, rtt, connection) } }, - Poll::Ready(ToSwarm::Dial { opts }) => return Poll::Ready(ToSwarm::Dial { opts }), - Poll::Ready(ToSwarm::NotifyHandler { peer_id, handler, event }) => - return Poll::Ready(ToSwarm::NotifyHandler { - peer_id, - handler, - event: Either::Left(event), - }), - Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }) => - return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }), - Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)) => - return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)), - Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)) => - return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)), - Poll::Ready(ToSwarm::ExternalAddrExpired(addr)) => - return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)), - Poll::Ready(ToSwarm::ListenOn { opts }) => - return Poll::Ready(ToSwarm::ListenOn { opts }), - Poll::Ready(ToSwarm::RemoveListener { id }) => - return Poll::Ready(ToSwarm::RemoveListener { id }), + Poll::Ready(event) => { + return Poll::Ready(event.map_in(Either::Left).map_out(|_| { + unreachable!("`GenerateEvent` is handled in a branch above; qed") + })); + }, } } loop { - match self.identify.poll(cx, params) { + match self.identify.poll(cx) { Poll::Pending => break, Poll::Ready(ToSwarm::GenerateEvent(event)) => match event { IdentifyEvent::Received { peer_id, info, .. } => { @@ -503,31 +495,20 @@ impl NetworkBehaviour for PeerInfoBehaviour { let event = PeerInfoEvent::Identified { peer_id, info }; return Poll::Ready(ToSwarm::GenerateEvent(event)) }, - IdentifyEvent::Error { peer_id, error } => { - debug!(target: "sub-libp2p", "Identification with peer {:?} failed => {}", peer_id, error) + IdentifyEvent::Error { connection_id, peer_id, error } => { + debug!( + target: "sub-libp2p", + "Identification with peer {peer_id:?}({connection_id}) failed => {error}" + ); }, IdentifyEvent::Pushed { .. } => {}, IdentifyEvent::Sent { .. } => {}, }, - Poll::Ready(ToSwarm::Dial { opts }) => return Poll::Ready(ToSwarm::Dial { opts }), - Poll::Ready(ToSwarm::NotifyHandler { peer_id, handler, event }) => - return Poll::Ready(ToSwarm::NotifyHandler { - peer_id, - handler, - event: Either::Right(event), - }), - Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }) => - return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }), - Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)) => - return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)), - Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)) => - return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)), - Poll::Ready(ToSwarm::ExternalAddrExpired(addr)) => - return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)), - Poll::Ready(ToSwarm::ListenOn { opts }) => - return Poll::Ready(ToSwarm::ListenOn { opts }), - Poll::Ready(ToSwarm::RemoveListener { id }) => - return Poll::Ready(ToSwarm::RemoveListener { id }), + Poll::Ready(event) => { + return Poll::Ready(event.map_in(Either::Right).map_out(|_| { + unreachable!("`GenerateEvent` is handled in a branch above; qed") + })); + }, } } diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 402baa7bb2a4..81e1848adefa 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -27,14 +27,14 @@ use crate::{ use codec::Encode; use libp2p::{ - core::Endpoint, + core::{transport::PortUse, Endpoint}, swarm::{ - behaviour::FromSwarm, ConnectionDenied, ConnectionId, NetworkBehaviour, PollParameters, - THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, + behaviour::FromSwarm, ConnectionDenied, ConnectionId, NetworkBehaviour, THandler, + THandlerInEvent, THandlerOutEvent, ToSwarm, }, Multiaddr, PeerId, }; -use log::warn; +use log::{debug, warn}; use codec::DecodeAll; use sc_network_common::role::Roles; @@ -47,14 +47,15 @@ use notifications::{Notifications, NotificationsOut}; pub(crate) use notifications::ProtocolHandle; -pub use notifications::{ - notification_service, NotificationsSink, NotifsHandlerError, ProtocolHandlePair, Ready, -}; +pub use notifications::{notification_service, NotificationsSink, ProtocolHandlePair, Ready}; mod notifications; pub mod message; +// Log target for this file. +const LOG_TARGET: &str = "sub-libp2p"; + /// Maximum size used for notifications in the block announce and transaction protocols. // Must be equal to `max(MAX_BLOCK_ANNOUNCE_SIZE, MAX_TRANSACTIONS_SIZE)`. pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = MAX_RESPONSE_SIZE; @@ -126,6 +127,10 @@ impl Protocol { handle.set_metrics(notification_metrics.clone()); }); + protocol_configs.iter().enumerate().for_each(|(i, (p, _, _))| { + debug!(target: LOG_TARGET, "Notifications protocol {:?}: {}", SetId::from(i), p.name); + }); + ( Notifications::new( protocol_controller_handles, @@ -166,7 +171,7 @@ impl Protocol { { self.behaviour.disconnect_peer(peer_id, SetId::from(position)); } else { - warn!(target: "sub-libp2p", "disconnect_peer() with invalid protocol name") + warn!(target: LOG_TARGET, "disconnect_peer() with invalid protocol name") } } @@ -250,12 +255,14 @@ impl NetworkBehaviour for Protocol { peer: PeerId, addr: &Multiaddr, role_override: Endpoint, + port_use: PortUse, ) -> Result, ConnectionDenied> { self.behaviour.handle_established_outbound_connection( connection_id, peer, addr, role_override, + port_use, ) } @@ -271,7 +278,7 @@ impl NetworkBehaviour for Protocol { Ok(Vec::new()) } - fn on_swarm_event(&mut self, event: FromSwarm) { + fn on_swarm_event(&mut self, event: FromSwarm) { self.behaviour.on_swarm_event(event); } @@ -287,26 +294,15 @@ impl NetworkBehaviour for Protocol { fn poll( &mut self, cx: &mut std::task::Context, - params: &mut impl PollParameters, ) -> Poll>> { - let event = match self.behaviour.poll(cx, params) { + let event = match self.behaviour.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(ToSwarm::GenerateEvent(ev)) => ev, - Poll::Ready(ToSwarm::Dial { opts }) => return Poll::Ready(ToSwarm::Dial { opts }), - Poll::Ready(ToSwarm::NotifyHandler { peer_id, handler, event }) => - return Poll::Ready(ToSwarm::NotifyHandler { peer_id, handler, event }), - Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }) => - return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }), - Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)) => - return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)), - Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)) => - return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)), - Poll::Ready(ToSwarm::ExternalAddrExpired(addr)) => - return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)), - Poll::Ready(ToSwarm::ListenOn { opts }) => - return Poll::Ready(ToSwarm::ListenOn { opts }), - Poll::Ready(ToSwarm::RemoveListener { id }) => - return Poll::Ready(ToSwarm::RemoveListener { id }), + Poll::Ready(event) => { + return Poll::Ready(event.map_out(|_| { + unreachable!("`GenerateEvent` is handled in a branch above; qed") + })); + }, }; let outcome = match event { diff --git a/substrate/client/network/src/protocol/notifications.rs b/substrate/client/network/src/protocol/notifications.rs index 10fa329097d1..2691496234ad 100644 --- a/substrate/client/network/src/protocol/notifications.rs +++ b/substrate/client/network/src/protocol/notifications.rs @@ -21,7 +21,7 @@ pub use self::{ behaviour::{Notifications, NotificationsOut, ProtocolConfig}, - handler::{NotificationsSink, NotifsHandlerError, Ready}, + handler::{NotificationsSink, Ready}, service::{notification_service, ProtocolHandlePair}, }; diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index a562546145c8..e6909fcdefea 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -33,11 +33,11 @@ use bytes::BytesMut; use fnv::FnvHashMap; use futures::{future::BoxFuture, prelude::*, stream::FuturesUnordered}; use libp2p::{ - core::{Endpoint, Multiaddr}, + core::{transport::PortUse, Endpoint, Multiaddr}, swarm::{ behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}, - ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, NotifyHandler, PollParameters, - THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, + ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, NotifyHandler, THandler, + THandlerInEvent, THandlerOutEvent, ToSwarm, }, PeerId, }; @@ -49,6 +49,7 @@ use smallvec::SmallVec; use tokio::sync::oneshot::error::RecvError; use tokio_stream::StreamMap; +use libp2p::swarm::CloseConnection; use std::{ cmp, collections::{hash_map::Entry, VecDeque}, @@ -1233,11 +1234,12 @@ impl NetworkBehaviour for Notifications { peer: PeerId, _addr: &Multiaddr, _role_override: Endpoint, + _port_use: PortUse, ) -> Result, ConnectionDenied> { Ok(NotifsHandler::new(peer, self.notif_protocols.clone(), Some(self.metrics.clone()))) } - fn on_swarm_event(&mut self, event: FromSwarm) { + fn on_swarm_event(&mut self, event: FromSwarm) { match event { FromSwarm::ConnectionEstablished(ConnectionEstablished { peer_id, @@ -1670,6 +1672,9 @@ impl NetworkBehaviour for Notifications { FromSwarm::ExternalAddrConfirmed(_) => {}, FromSwarm::AddressChange(_) => {}, FromSwarm::NewListenAddr(_) => {}, + event => { + warn!(target: "sub-libp2p", "New unknown `FromSwarm` libp2p event: {event:?}"); + }, } } @@ -2217,14 +2222,19 @@ impl NetworkBehaviour for Notifications { ); } }, + NotifsHandlerOut::Close { protocol_index } => { + let set_id = SetId::from(protocol_index); + + trace!(target: "sub-libp2p", "Handler({}, {:?}) => SyncNotificationsClogged({:?})", peer_id, connection_id, set_id); + self.events.push_back(ToSwarm::CloseConnection { + peer_id, + connection: CloseConnection::One(connection_id), + }); + }, } } - fn poll( - &mut self, - cx: &mut Context, - _params: &mut impl PollParameters, - ) -> Poll>> { + fn poll(&mut self, cx: &mut Context) -> Poll>> { if let Some(event) = self.events.pop_front() { return Poll::Ready(event) } @@ -2359,7 +2369,6 @@ impl NetworkBehaviour for Notifications { } #[cfg(test)] -#[allow(deprecated)] mod tests { use super::*; use crate::{ @@ -2386,17 +2395,6 @@ mod tests { } } - #[derive(Clone)] - struct MockPollParams {} - - impl PollParameters for MockPollParams { - type SupportedProtocolsIter = std::vec::IntoIter>; - - fn supported_protocols(&self) -> Self::SupportedProtocolsIter { - vec![].into_iter() - } - } - fn development_notifs( ) -> (Notifications, ProtocolController, Box) { @@ -2654,7 +2652,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -2854,7 +2852,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3007,7 +3005,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3051,7 +3049,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3121,7 +3119,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3269,7 +3267,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3395,7 +3393,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3469,7 +3467,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3532,7 +3530,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3546,7 +3544,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3600,7 +3598,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3658,7 +3656,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3719,7 +3717,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3788,7 +3786,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3829,7 +3827,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3952,7 +3950,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -3972,11 +3970,9 @@ mod tests { assert!(notif.peers.get(&(peer, set_id)).is_some()); if tokio::time::timeout(Duration::from_secs(5), async { - let mut params = MockPollParams {}; - loop { futures::future::poll_fn(|cx| { - let _ = notif.poll(cx, &mut params); + let _ = notif.poll(cx); Poll::Ready(()) }) .await; @@ -4080,11 +4076,9 @@ mod tests { // verify that the code continues to keep the peer disabled by resetting the timer // after the first one expired. if tokio::time::timeout(Duration::from_secs(5), async { - let mut params = MockPollParams {}; - loop { futures::future::poll_fn(|cx| { - let _ = notif.poll(cx, &mut params); + let _ = notif.poll(cx); Poll::Ready(()) }) .await; @@ -4262,7 +4256,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4503,7 +4497,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4605,7 +4599,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4687,7 +4681,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &endpoint.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4804,7 +4798,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4839,7 +4833,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4890,7 +4884,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4937,7 +4931,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -4987,7 +4981,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -5030,7 +5024,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); @@ -5041,7 +5035,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, vec![], None), + cause: None, remaining_established: 0usize, }, )); diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index bff60ba1125f..332de9f19c41 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -74,12 +74,12 @@ use futures::{ }; use libp2p::{ swarm::{ - handler::ConnectionEvent, ConnectionHandler, ConnectionHandlerEvent, KeepAlive, Stream, + handler::ConnectionEvent, ConnectionHandler, ConnectionHandlerEvent, Stream, SubstreamProtocol, }, PeerId, }; -use log::error; +use log::{error, warn}; use parking_lot::{Mutex, RwLock}; use std::{ collections::VecDeque, @@ -87,7 +87,7 @@ use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, - time::{Duration, Instant}, + time::Duration, }; /// Number of pending notifications in asynchronous contexts. @@ -113,16 +113,18 @@ pub struct NotifsHandler { /// List of notification protocols, specified by the user at initialization. protocols: Vec, - /// When the connection with the remote has been successfully established. - when_connection_open: Instant, + /// Whether to keep connection alive + keep_alive: bool, + + /// Optional future that keeps connection alive for a certain amount of time. + // TODO: this should be safe to remove, see https://github.com/paritytech/polkadot-sdk/issues/6350 + keep_alive_timeout_future: Option + Send + 'static>>>, /// Remote we are connected to. peer_id: PeerId, /// Events to return in priority from `poll`. - events_queue: VecDeque< - ConnectionHandlerEvent, - >, + events_queue: VecDeque>, /// Metrics. metrics: Option>, @@ -149,7 +151,12 @@ impl NotifsHandler { }) .collect(), peer_id, - when_connection_open: Instant::now(), + // Keep connection alive initially until below timeout expires + keep_alive: true, + // A grace period of `INITIAL_KEEPALIVE_TIME` must be given to leave time for the remote + // to express desire to open substreams. + // TODO: This is a hack and ideally should not be necessary + keep_alive_timeout_future: Some(Box::pin(tokio::time::sleep(INITIAL_KEEPALIVE_TIME))), events_queue: VecDeque::with_capacity(16), metrics: metrics.map_or(None, |metrics| Some(Arc::new(metrics))), } @@ -327,6 +334,12 @@ pub enum NotifsHandlerOut { /// Message that has been received. message: BytesMut, }, + + /// Close connection + Close { + /// Index of the protocol in the list of protocols passed at initialization. + protocol_index: usize, + }, } /// Sink connected directly to the node background task. Allows sending notifications to the peer. @@ -465,17 +478,9 @@ impl<'a> Ready<'a> { } } -/// Error specific to the collection of protocols. -#[derive(Debug, thiserror::Error)] -pub enum NotifsHandlerError { - #[error("Channel of synchronous notifications is full.")] - SyncNotificationsClogged, -} - impl ConnectionHandler for NotifsHandler { type FromBehaviour = NotifsHandlerIn; type ToBehaviour = NotifsHandlerOut; - type Error = NotifsHandlerError; type InboundProtocol = UpgradeCollec; type OutboundProtocol = NotificationsOut; // Index within the `out_protocols`. @@ -616,6 +621,9 @@ impl ConnectionHandler for NotifsHandler { State::Open { .. } => debug_assert!(false), }, ConnectionEvent::ListenUpgradeError(_listen_upgrade_error) => {}, + event => { + warn!(target: "sub-libp2p", "New unknown `ConnectionEvent` libp2p event: {event:?}"); + }, } } @@ -711,35 +719,36 @@ impl ConnectionHandler for NotifsHandler { } } - fn connection_keep_alive(&self) -> KeepAlive { + fn connection_keep_alive(&self) -> bool { // `Yes` if any protocol has some activity. if self.protocols.iter().any(|p| !matches!(p.state, State::Closed { .. })) { - return KeepAlive::Yes + return true; } - // A grace period of `INITIAL_KEEPALIVE_TIME` must be given to leave time for the remote - // to express desire to open substreams. - #[allow(deprecated)] - KeepAlive::Until(self.when_connection_open + INITIAL_KEEPALIVE_TIME) + self.keep_alive } - #[allow(deprecated)] fn poll( &mut self, cx: &mut Context, ) -> Poll< - ConnectionHandlerEvent< - Self::OutboundProtocol, - Self::OutboundOpenInfo, - Self::ToBehaviour, - Self::Error, - >, + ConnectionHandlerEvent, > { + { + let maybe_keep_alive_timeout_future = &mut self.keep_alive_timeout_future; + if let Some(keep_alive_timeout_future) = maybe_keep_alive_timeout_future { + if keep_alive_timeout_future.poll_unpin(cx).is_ready() { + maybe_keep_alive_timeout_future.take(); + self.keep_alive = false; + } + } + } + if let Some(ev) = self.events_queue.pop_front() { return Poll::Ready(ev) } - // For each open substream, try send messages from `notifications_sink_rx` to the + // For each open substream, try to send messages from `notifications_sink_rx` to the // substream. for protocol_index in 0..self.protocols.len() { if let State::Open { @@ -750,11 +759,10 @@ impl ConnectionHandler for NotifsHandler { // Only proceed with `out_substream.poll_ready_unpin` if there is an element // available in `notifications_sink_rx`. This avoids waking up the task when // a substream is ready to send if there isn't actually something to send. - #[allow(deprecated)] match Pin::new(&mut *notifications_sink_rx).as_mut().poll_peek(cx) { Poll::Ready(Some(&NotificationsSinkMessage::ForceClose)) => - return Poll::Ready(ConnectionHandlerEvent::Close( - NotifsHandlerError::SyncNotificationsClogged, + return Poll::Ready(ConnectionHandlerEvent::NotifyBehaviour( + NotifsHandlerOut::Close { protocol_index }, )), Poll::Ready(Some(&NotificationsSinkMessage::Notification { .. })) => {}, Poll::Ready(None) | Poll::Pending => break, @@ -975,6 +983,17 @@ pub mod tests { rx_buffer: BytesMut, } + /// Mirror of `ActiveStreamCounter` in `libp2p` + #[allow(dead_code)] + struct MockActiveStreamCounter(Arc<()>); + + // Mirror of `Stream` in `libp2p` + #[allow(dead_code)] + struct MockStream { + stream: Negotiated, + counter: Option, + } + impl MockSubstream { /// Create new substream pair. pub fn new() -> (Self, Self) { @@ -1004,16 +1023,11 @@ pub mod tests { /// Unsafe substitute for `Stream::new` private constructor. fn stream_new(stream: Negotiated) -> Stream { + let stream = MockStream { stream, counter: None }; // Static asserts to make sure this doesn't break. const _: () = { - assert!( - core::mem::size_of::() == - core::mem::size_of::>() - ); - assert!( - core::mem::align_of::() == - core::mem::align_of::>() - ); + assert!(core::mem::size_of::() == core::mem::size_of::()); + assert!(core::mem::align_of::() == core::mem::align_of::()); }; unsafe { core::mem::transmute(stream) } @@ -1084,24 +1098,16 @@ pub mod tests { /// Create new [`NotifsHandler`]. fn notifs_handler() -> NotifsHandler { - let proto = Protocol { - config: ProtocolConfig { + NotifsHandler::new( + PeerId::random(), + vec![ProtocolConfig { name: "/foo".into(), fallback_names: vec![], handshake: Arc::new(RwLock::new(b"hello, world".to_vec())), max_notification_size: u64::MAX, - }, - in_upgrade: NotificationsIn::new("/foo", Vec::new(), u64::MAX), - state: State::Closed { pending_opening: false }, - }; - - NotifsHandler { - protocols: vec![proto], - when_connection_open: Instant::now(), - peer_id: PeerId::random(), - events_queue: VecDeque::new(), - metrics: None, - } + }], + None, + ) } // verify that if another substream is attempted to be opened by remote while an inbound @@ -1608,12 +1614,11 @@ pub mod tests { notifications_sink.send_sync_notification(vec![1, 3, 3, 9]); notifications_sink.send_sync_notification(vec![1, 3, 4, 0]); - #[allow(deprecated)] futures::future::poll_fn(|cx| { assert!(std::matches!( handler.poll(cx), - Poll::Ready(ConnectionHandlerEvent::Close( - NotifsHandlerError::SyncNotificationsClogged, + Poll::Ready(ConnectionHandlerEvent::NotifyBehaviour( + NotifsHandlerOut::Close { .. } )) )); Poll::Ready(()) diff --git a/substrate/client/network/src/protocol/notifications/tests.rs b/substrate/client/network/src/protocol/notifications/tests.rs index a8eeb2bb1980..50f03b5911b6 100644 --- a/substrate/client/network/src/protocol/notifications/tests.rs +++ b/substrate/client/network/src/protocol/notifications/tests.rs @@ -30,30 +30,25 @@ use crate::{ use futures::{future::BoxFuture, prelude::*}; use libp2p::{ - core::{transport::MemoryTransport, upgrade, Endpoint}, + core::{ + transport::{MemoryTransport, PortUse}, + upgrade, Endpoint, + }, identity, noise, swarm::{ - self, behaviour::FromSwarm, ConnectionDenied, ConnectionId, Executor, NetworkBehaviour, - PollParameters, Swarm, SwarmEvent, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, + behaviour::FromSwarm, ConnectionDenied, ConnectionId, NetworkBehaviour, Swarm, SwarmEvent, + THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, }, - yamux, Multiaddr, PeerId, Transport, + yamux, Multiaddr, PeerId, SwarmBuilder, Transport, }; use sc_utils::mpsc::tracing_unbounded; use std::{ iter, - pin::Pin, sync::Arc, task::{Context, Poll}, time::Duration, }; -struct TokioExecutor(tokio::runtime::Runtime); -impl Executor for TokioExecutor { - fn exec(&self, f: Pin + Send>>) { - let _ = self.0.spawn(f); - } -} - /// Builds two nodes that have each other as bootstrap nodes. /// This is to be used only for testing, and a panic will happen if something goes wrong. fn build_nodes() -> (Swarm, Swarm) { @@ -67,13 +62,6 @@ fn build_nodes() -> (Swarm, Swarm) { for index in 0..2 { let keypair = keypairs[index].clone(); - let transport = MemoryTransport::new() - .upgrade(upgrade::Version::V1) - .authenticate(noise::Config::new(&keypair).unwrap()) - .multiplex(yamux::Config::default()) - .timeout(Duration::from_secs(20)) - .boxed(); - let (protocol_handle_pair, mut notif_service) = crate::protocol::notifications::service::notification_service("/foo".into()); // The first swarm has the second peer ID present in the peerstore. @@ -102,39 +90,8 @@ fn build_nodes() -> (Swarm, Swarm) { ); let (notif_handle, command_stream) = protocol_handle_pair.split(); - let behaviour = CustomProtoWithAddr { - inner: Notifications::new( - vec![controller_handle], - from_controller, - NotificationMetrics::new(None), - iter::once(( - ProtocolConfig { - name: "/foo".into(), - fallback_names: Vec::new(), - handshake: Vec::new(), - max_notification_size: 1024 * 1024, - }, - notif_handle, - command_stream, - )), - ), - peer_store_future: peer_store.run().boxed(), - protocol_controller_future: controller.run().boxed(), - addrs: addrs - .iter() - .enumerate() - .filter_map(|(n, a)| { - if n != index { - Some((keypairs[n].public().to_peer_id(), a.clone())) - } else { - None - } - }) - .collect(), - }; - let runtime = tokio::runtime::Runtime::new().unwrap(); - runtime.spawn(async move { + tokio::spawn(async move { loop { if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = notif_service.next_event().await.unwrap() @@ -144,12 +101,49 @@ fn build_nodes() -> (Swarm, Swarm) { } }); - let mut swarm = Swarm::new( - transport, - behaviour, - keypairs[index].public().to_peer_id(), - swarm::Config::with_executor(TokioExecutor(runtime)), - ); + let mut swarm = SwarmBuilder::with_existing_identity(keypair) + .with_tokio() + .with_other_transport(|keypair| { + MemoryTransport::new() + .upgrade(upgrade::Version::V1) + .authenticate(noise::Config::new(&keypair).unwrap()) + .multiplex(yamux::Config::default()) + .timeout(Duration::from_secs(20)) + .boxed() + }) + .unwrap() + .with_behaviour(|_keypair| CustomProtoWithAddr { + inner: Notifications::new( + vec![controller_handle], + from_controller, + NotificationMetrics::new(None), + iter::once(( + ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: Vec::new(), + max_notification_size: 1024 * 1024, + }, + notif_handle, + command_stream, + )), + ), + peer_store_future: peer_store.run().boxed(), + protocol_controller_future: controller.run().boxed(), + addrs: addrs + .iter() + .enumerate() + .filter_map(|(n, a)| { + if n != index { + Some((keypairs[n].public().to_peer_id(), a.clone())) + } else { + None + } + }) + .collect(), + }) + .unwrap() + .build(); swarm.listen_on(addrs[index].clone()).unwrap(); out.push(swarm); } @@ -241,12 +235,18 @@ impl NetworkBehaviour for CustomProtoWithAddr { peer: PeerId, addr: &Multiaddr, role_override: Endpoint, + port_use: PortUse, ) -> Result, ConnectionDenied> { - self.inner - .handle_established_outbound_connection(connection_id, peer, addr, role_override) + self.inner.handle_established_outbound_connection( + connection_id, + peer, + addr, + role_override, + port_use, + ) } - fn on_swarm_event(&mut self, event: FromSwarm) { + fn on_swarm_event(&mut self, event: FromSwarm) { self.inner.on_swarm_event(event); } @@ -259,19 +259,15 @@ impl NetworkBehaviour for CustomProtoWithAddr { self.inner.on_connection_handler_event(peer_id, connection_id, event); } - fn poll( - &mut self, - cx: &mut Context, - params: &mut impl PollParameters, - ) -> Poll>> { + fn poll(&mut self, cx: &mut Context) -> Poll>> { let _ = self.peer_store_future.poll_unpin(cx); let _ = self.protocol_controller_future.poll_unpin(cx); - self.inner.poll(cx, params) + self.inner.poll(cx) } } -#[test] -fn reconnect_after_disconnect() { +#[tokio::test] +async fn reconnect_after_disconnect() { // We connect two nodes together, then force a disconnect (through the API of the `Service`), // check that the disconnect worked, and finally check whether they successfully reconnect. @@ -288,108 +284,106 @@ fn reconnect_after_disconnect() { let mut service1_state = ServiceState::NotConnected; let mut service2_state = ServiceState::NotConnected; - futures::executor::block_on(async move { - loop { - // Grab next event from services. - let event = { - let s1 = service1.select_next_some(); - let s2 = service2.select_next_some(); - futures::pin_mut!(s1, s2); - match future::select(s1, s2).await { - future::Either::Left((ev, _)) => future::Either::Left(ev), - future::Either::Right((ev, _)) => future::Either::Right(ev), - } - }; - - match event { - future::Either::Left(SwarmEvent::Behaviour( - NotificationsOut::CustomProtocolOpen { .. }, - )) => match service1_state { - ServiceState::NotConnected => { - service1_state = ServiceState::FirstConnec; - if service2_state == ServiceState::FirstConnec { - service1 - .behaviour_mut() - .disconnect_peer(Swarm::local_peer_id(&service2), SetId::from(0)); - } - }, - ServiceState::Disconnected => service1_state = ServiceState::ConnectedAgain, - ServiceState::FirstConnec | ServiceState::ConnectedAgain => panic!(), - }, - future::Either::Left(SwarmEvent::Behaviour( - NotificationsOut::CustomProtocolClosed { .. }, - )) => match service1_state { - ServiceState::FirstConnec => service1_state = ServiceState::Disconnected, - ServiceState::ConnectedAgain | - ServiceState::NotConnected | - ServiceState::Disconnected => panic!(), - }, - future::Either::Right(SwarmEvent::Behaviour( - NotificationsOut::CustomProtocolOpen { .. }, - )) => match service2_state { - ServiceState::NotConnected => { - service2_state = ServiceState::FirstConnec; - if service1_state == ServiceState::FirstConnec { - service1 - .behaviour_mut() - .disconnect_peer(Swarm::local_peer_id(&service2), SetId::from(0)); - } - }, - ServiceState::Disconnected => service2_state = ServiceState::ConnectedAgain, - ServiceState::FirstConnec | ServiceState::ConnectedAgain => panic!(), - }, - future::Either::Right(SwarmEvent::Behaviour( - NotificationsOut::CustomProtocolClosed { .. }, - )) => match service2_state { - ServiceState::FirstConnec => service2_state = ServiceState::Disconnected, - ServiceState::ConnectedAgain | - ServiceState::NotConnected | - ServiceState::Disconnected => panic!(), - }, - _ => {}, + loop { + // Grab next event from services. + let event = { + let s1 = service1.select_next_some(); + let s2 = service2.select_next_some(); + futures::pin_mut!(s1, s2); + match future::select(s1, s2).await { + future::Either::Left((ev, _)) => future::Either::Left(ev), + future::Either::Right((ev, _)) => future::Either::Right(ev), } + }; - // Due to the bug in `Notifications`, the disconnected node does not always detect that - // it was disconnected. The closed inbound substream is tolerated by design, and the - // closed outbound substream is not detected until something is sent into it. - // See [PR #13396](https://github.com/paritytech/substrate/pull/13396). - // This happens if the disconnecting node reconnects to it fast enough. - // In this case the disconnected node does not transit via `ServiceState::NotConnected` - // and stays in `ServiceState::FirstConnec`. - // TODO: update this once the fix is finally merged. - if service1_state == ServiceState::ConnectedAgain && - service2_state == ServiceState::ConnectedAgain || - service1_state == ServiceState::ConnectedAgain && - service2_state == ServiceState::FirstConnec || - service1_state == ServiceState::FirstConnec && - service2_state == ServiceState::ConnectedAgain - { - break - } + match event { + future::Either::Left(SwarmEvent::Behaviour(NotificationsOut::CustomProtocolOpen { + .. + })) => match service1_state { + ServiceState::NotConnected => { + service1_state = ServiceState::FirstConnec; + if service2_state == ServiceState::FirstConnec { + service1 + .behaviour_mut() + .disconnect_peer(Swarm::local_peer_id(&service2), SetId::from(0)); + } + }, + ServiceState::Disconnected => service1_state = ServiceState::ConnectedAgain, + ServiceState::FirstConnec | ServiceState::ConnectedAgain => panic!(), + }, + future::Either::Left(SwarmEvent::Behaviour( + NotificationsOut::CustomProtocolClosed { .. }, + )) => match service1_state { + ServiceState::FirstConnec => service1_state = ServiceState::Disconnected, + ServiceState::ConnectedAgain | + ServiceState::NotConnected | + ServiceState::Disconnected => panic!(), + }, + future::Either::Right(SwarmEvent::Behaviour( + NotificationsOut::CustomProtocolOpen { .. }, + )) => match service2_state { + ServiceState::NotConnected => { + service2_state = ServiceState::FirstConnec; + if service1_state == ServiceState::FirstConnec { + service1 + .behaviour_mut() + .disconnect_peer(Swarm::local_peer_id(&service2), SetId::from(0)); + } + }, + ServiceState::Disconnected => service2_state = ServiceState::ConnectedAgain, + ServiceState::FirstConnec | ServiceState::ConnectedAgain => panic!(), + }, + future::Either::Right(SwarmEvent::Behaviour( + NotificationsOut::CustomProtocolClosed { .. }, + )) => match service2_state { + ServiceState::FirstConnec => service2_state = ServiceState::Disconnected, + ServiceState::ConnectedAgain | + ServiceState::NotConnected | + ServiceState::Disconnected => panic!(), + }, + _ => {}, } - // Now that the two services have disconnected and reconnected, wait for 3 seconds and - // check whether they're still connected. - let mut delay = futures_timer::Delay::new(Duration::from_secs(3)); - - loop { - // Grab next event from services. - let event = { - let s1 = service1.select_next_some(); - let s2 = service2.select_next_some(); - futures::pin_mut!(s1, s2); - match future::select(future::select(s1, s2), &mut delay).await { - future::Either::Right(_) => break, // success - future::Either::Left((future::Either::Left((ev, _)), _)) => ev, - future::Either::Left((future::Either::Right((ev, _)), _)) => ev, - } - }; + // Due to the bug in `Notifications`, the disconnected node does not always detect that + // it was disconnected. The closed inbound substream is tolerated by design, and the + // closed outbound substream is not detected until something is sent into it. + // See [PR #13396](https://github.com/paritytech/substrate/pull/13396). + // This happens if the disconnecting node reconnects to it fast enough. + // In this case the disconnected node does not transit via `ServiceState::NotConnected` + // and stays in `ServiceState::FirstConnec`. + // TODO: update this once the fix is finally merged. + if service1_state == ServiceState::ConnectedAgain && + service2_state == ServiceState::ConnectedAgain || + service1_state == ServiceState::ConnectedAgain && + service2_state == ServiceState::FirstConnec || + service1_state == ServiceState::FirstConnec && + service2_state == ServiceState::ConnectedAgain + { + break + } + } - match event { - SwarmEvent::Behaviour(NotificationsOut::CustomProtocolOpen { .. }) | - SwarmEvent::Behaviour(NotificationsOut::CustomProtocolClosed { .. }) => panic!(), - _ => {}, + // Now that the two services have disconnected and reconnected, wait for 3 seconds and + // check whether they're still connected. + let mut delay = futures_timer::Delay::new(Duration::from_secs(3)); + + loop { + // Grab next event from services. + let event = { + let s1 = service1.select_next_some(); + let s2 = service2.select_next_some(); + futures::pin_mut!(s1, s2); + match future::select(future::select(s1, s2), &mut delay).await { + future::Either::Right(_) => break, // success + future::Either::Left((future::Either::Left((ev, _)), _)) => ev, + future::Either::Left((future::Either::Right((ev, _)), _)) => ev, } + }; + + match event { + SwarmEvent::Behaviour(NotificationsOut::CustomProtocolOpen { .. }) | + SwarmEvent::Behaviour(NotificationsOut::CustomProtocolClosed { .. }) => panic!(), + _ => {}, } - }); + } } diff --git a/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs b/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs index e01bcbe0bad7..9e8a03fc07c9 100644 --- a/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -39,12 +39,12 @@ use crate::types::ProtocolName; use asynchronous_codec::Framed; use bytes::BytesMut; use futures::prelude::*; -use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; +use libp2p::core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use log::{error, warn}; use unsigned_varint::codec::UviBytes; use std::{ - io, mem, + fmt, io, mem, pin::Pin, task::{Context, Poll}, vec, @@ -187,6 +187,14 @@ pub struct NotificationsInOpen { pub substream: NotificationsInSubstream, } +impl fmt::Debug for NotificationsInOpen { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NotificationsInOpen") + .field("handshake", &self.handshake) + .finish_non_exhaustive() + } +} + impl NotificationsInSubstream where TSubstream: AsyncRead + AsyncWrite + Unpin, @@ -370,7 +378,14 @@ where fn upgrade_outbound(self, mut socket: TSubstream, negotiated_name: Self::Info) -> Self::Future { Box::pin(async move { - upgrade::write_length_prefixed(&mut socket, &self.initial_message).await?; + { + let mut len_data = unsigned_varint::encode::usize_buffer(); + let encoded_len = + unsigned_varint::encode::usize(self.initial_message.len(), &mut len_data).len(); + socket.write_all(&len_data[..encoded_len]).await?; + } + socket.write_all(&self.initial_message).await?; + socket.flush().await?; // Reading handshake. let handshake_len = unsigned_varint::aio::read_usize(&mut socket).await?; @@ -413,6 +428,15 @@ pub struct NotificationsOutOpen { pub substream: NotificationsOutSubstream, } +impl fmt::Debug for NotificationsOutOpen { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NotificationsOutOpen") + .field("handshake", &self.handshake) + .field("negotiated_fallback", &self.negotiated_fallback) + .finish_non_exhaustive() + } +} + impl Sink> for NotificationsOutSubstream where TSubstream: AsyncRead + AsyncWrite + Unpin, diff --git a/substrate/client/network/src/protocol_controller.rs b/substrate/client/network/src/protocol_controller.rs index af7adb50907f..11f5321294d0 100644 --- a/substrate/client/network/src/protocol_controller.rs +++ b/substrate/client/network/src/protocol_controller.rs @@ -464,7 +464,7 @@ impl ProtocolController { /// maintain connections with such peers. fn on_add_reserved_peer(&mut self, peer_id: PeerId) { if self.reserved_nodes.contains_key(&peer_id) { - warn!( + debug!( target: LOG_TARGET, "Trying to add an already reserved node {peer_id} as reserved on {:?}.", self.set_id, diff --git a/substrate/client/network/src/request_responses.rs b/substrate/client/network/src/request_responses.rs index 6c2631924df4..5fe34c781378 100644 --- a/substrate/client/network/src/request_responses.rs +++ b/substrate/client/network/src/request_responses.rs @@ -43,13 +43,11 @@ use crate::{ use futures::{channel::oneshot, prelude::*}; use libp2p::{ - core::{Endpoint, Multiaddr}, + core::{transport::PortUse, Endpoint, Multiaddr}, request_response::{self, Behaviour, Codec, Message, ProtocolSupport, ResponseChannel}, swarm::{ - behaviour::{ConnectionClosed, FromSwarm}, - handler::multi::MultiHandler, - ConnectionDenied, ConnectionId, NetworkBehaviour, PollParameters, THandler, - THandlerInEvent, THandlerOutEvent, ToSwarm, + behaviour::FromSwarm, handler::multi::MultiHandler, ConnectionDenied, ConnectionId, + NetworkBehaviour, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, }, PeerId, }; @@ -64,11 +62,11 @@ use std::{ time::{Duration, Instant}, }; -pub use libp2p::request_response::{Config, RequestId}; +pub use libp2p::request_response::{Config, InboundRequestId, OutboundRequestId}; /// Possible failures occurring in the context of sending an outbound request and receiving the /// response. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Clone, thiserror::Error)] pub enum OutboundFailure { /// The request could not be sent because a dialing attempt failed. #[error("Failed to dial the requested peer")] @@ -82,6 +80,9 @@ pub enum OutboundFailure { /// The remote supports none of the requested protocols. #[error("The remote supports none of the requested protocols")] UnsupportedProtocols, + /// An IO failure happened on an outbound stream. + #[error("An IO failure happened on an outbound stream")] + Io(Arc), } impl From for OutboundFailure { @@ -93,6 +94,7 @@ impl From for OutboundFailure { OutboundFailure::ConnectionClosed, request_response::OutboundFailure::UnsupportedProtocols => OutboundFailure::UnsupportedProtocols, + request_response::OutboundFailure::Io(error) => OutboundFailure::Io(Arc::new(error)), } } } @@ -114,6 +116,9 @@ pub enum InboundFailure { /// The local peer failed to respond to an inbound request #[error("The response channel was dropped without sending a response to the remote")] ResponseOmission, + /// An IO failure happened on an inbound stream. + #[error("An IO failure happened on an inbound stream")] + Io(Arc), } impl From for InboundFailure { @@ -124,6 +129,7 @@ impl From for InboundFailure { request_response::InboundFailure::ConnectionClosed => InboundFailure::ConnectionClosed, request_response::InboundFailure::UnsupportedProtocols => InboundFailure::UnsupportedProtocols, + request_response::InboundFailure::Io(error) => InboundFailure::Io(Arc::new(error)), } } } @@ -319,12 +325,12 @@ pub enum Event { /// requests. There is no uniqueness guarantee in a set of both inbound and outbound /// [`ProtocolRequestId`]s. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -struct ProtocolRequestId { +struct ProtocolRequestId { protocol: ProtocolName, request_id: RequestId, } -impl From<(ProtocolName, RequestId)> for ProtocolRequestId { +impl From<(ProtocolName, RequestId)> for ProtocolRequestId { fn from((protocol, request_id): (ProtocolName, RequestId)) -> Self { Self { protocol, request_id } } @@ -342,7 +348,7 @@ pub struct RequestResponsesBehaviour { >, /// Pending requests, passed down to a request-response [`Behaviour`], awaiting a reply. - pending_requests: HashMap, + pending_requests: HashMap, PendingRequest>, /// Whenever an incoming request arrives, a `Future` is added to this list and will yield the /// start time and the response to send back to the remote. @@ -351,11 +357,11 @@ pub struct RequestResponsesBehaviour { >, /// Whenever an incoming request arrives, the arrival [`Instant`] is recorded here. - pending_responses_arrival_time: HashMap, + pending_responses_arrival_time: HashMap, Instant>, /// Whenever a response is received on `pending_responses`, insert a channel to be notified /// when the request has been sent out. - send_feedback: HashMap>, + send_feedback: HashMap, oneshot::Sender<()>>, /// Primarily used to get a reputation of a node. peer_store: Arc, @@ -364,7 +370,7 @@ pub struct RequestResponsesBehaviour { /// Generated by the response builder and waiting to be processed. struct RequestProcessingOutcome { peer: PeerId, - request_id: RequestId, + request_id: InboundRequestId, protocol: ProtocolName, inner_channel: ResponseChannel, ()>>, response: OutgoingResponse, @@ -379,8 +385,7 @@ impl RequestResponsesBehaviour { ) -> Result { let mut protocols = HashMap::new(); for protocol in list { - let mut cfg = Config::default(); - cfg.set_request_timeout(protocol.request_timeout); + let cfg = Config::default().with_request_timeout(protocol.request_timeout); let protocol_support = if protocol.inbound_queue.is_some() { ProtocolSupport::Full @@ -455,7 +460,7 @@ impl RequestResponsesBehaviour { fn send_request_inner( behaviour: &mut Behaviour, - pending_requests: &mut HashMap, + pending_requests: &mut HashMap, PendingRequest>, target: &PeerId, protocol_name: ProtocolName, request: Vec, @@ -541,11 +546,16 @@ impl NetworkBehaviour for RequestResponsesBehaviour { peer: PeerId, addr: &Multiaddr, role_override: Endpoint, + port_use: PortUse, ) -> Result, ConnectionDenied> { let iter = self.protocols.iter_mut().filter_map(|(p, (r, _))| { - if let Ok(handler) = - r.handle_established_outbound_connection(connection_id, peer, addr, role_override) - { + if let Ok(handler) = r.handle_established_outbound_connection( + connection_id, + peer, + addr, + role_override, + port_use, + ) { Some((p.to_string(), handler)) } else { None @@ -558,80 +568,9 @@ impl NetworkBehaviour for RequestResponsesBehaviour { )) } - fn on_swarm_event(&mut self, event: FromSwarm) { - match event { - FromSwarm::ConnectionEstablished(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ConnectionEstablished(e)); - }, - FromSwarm::ConnectionClosed(ConnectionClosed { - peer_id, - connection_id, - endpoint, - handler, - remaining_established, - }) => - for (p_name, p_handler) in handler.into_iter() { - if let Some((proto, _)) = self.protocols.get_mut(p_name.as_str()) { - proto.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed { - peer_id, - connection_id, - endpoint, - handler: p_handler, - remaining_established, - })); - } else { - log::error!( - target: "sub-libp2p", - "on_swarm_event/connection_closed: no request-response instance registered for protocol {:?}", - p_name, - ) - } - }, - FromSwarm::DialFailure(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::DialFailure(e)); - }, - FromSwarm::ListenerClosed(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ListenerClosed(e)); - }, - FromSwarm::ListenFailure(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ListenFailure(e)); - }, - FromSwarm::ListenerError(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ListenerError(e)); - }, - FromSwarm::ExternalAddrExpired(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ExternalAddrExpired(e)); - }, - FromSwarm::NewListener(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::NewListener(e)); - }, - FromSwarm::ExpiredListenAddr(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ExpiredListenAddr(e)); - }, - FromSwarm::NewExternalAddrCandidate(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::NewExternalAddrCandidate(e)); - }, - FromSwarm::ExternalAddrConfirmed(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::ExternalAddrConfirmed(e)); - }, - FromSwarm::AddressChange(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::AddressChange(e)); - }, - FromSwarm::NewListenAddr(e) => - for (p, _) in self.protocols.values_mut() { - NetworkBehaviour::on_swarm_event(p, FromSwarm::NewListenAddr(e)); - }, + fn on_swarm_event(&mut self, event: FromSwarm) { + for (protocol, _) in self.protocols.values_mut() { + protocol.on_swarm_event(event); } } @@ -653,11 +592,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { } } - fn poll( - &mut self, - cx: &mut Context, - params: &mut impl PollParameters, - ) -> Poll>> { + fn poll(&mut self, cx: &mut Context) -> Poll>> { 'poll_all: loop { // Poll to see if any response is ready to be sent back. while let Poll::Ready(Some(outcome)) = self.pending_responses.poll_next_unpin(cx) { @@ -707,7 +642,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { // Poll request-responses protocols. for (protocol, (ref mut behaviour, ref mut resp_builder)) in &mut self.protocols { - 'poll_protocol: while let Poll::Ready(ev) = behaviour.poll(cx, params) { + 'poll_protocol: while let Poll::Ready(ev) = behaviour.poll(cx) { let ev = match ev { // Main events we are interested in. ToSwarm::GenerateEvent(ev) => ev, @@ -717,29 +652,23 @@ impl NetworkBehaviour for RequestResponsesBehaviour { ToSwarm::Dial { opts } => { if opts.get_peer_id().is_none() { log::error!( + target: "sub-libp2p", "The request-response isn't supposed to start dialing addresses" ); } return Poll::Ready(ToSwarm::Dial { opts }) }, - ToSwarm::NotifyHandler { peer_id, handler, event } => - return Poll::Ready(ToSwarm::NotifyHandler { - peer_id, - handler, - event: ((*protocol).to_string(), event), - }), - ToSwarm::CloseConnection { peer_id, connection } => - return Poll::Ready(ToSwarm::CloseConnection { peer_id, connection }), - ToSwarm::NewExternalAddrCandidate(observed) => - return Poll::Ready(ToSwarm::NewExternalAddrCandidate(observed)), - ToSwarm::ExternalAddrConfirmed(addr) => - return Poll::Ready(ToSwarm::ExternalAddrConfirmed(addr)), - ToSwarm::ExternalAddrExpired(addr) => - return Poll::Ready(ToSwarm::ExternalAddrExpired(addr)), - ToSwarm::ListenOn { opts } => - return Poll::Ready(ToSwarm::ListenOn { opts }), - ToSwarm::RemoveListener { id } => - return Poll::Ready(ToSwarm::RemoveListener { id }), + event => { + return Poll::Ready( + event.map_in(|event| ((*protocol).to_string(), event)).map_out( + |_| { + unreachable!( + "`GenerateEvent` is handled in a branch above; qed" + ) + }, + ), + ); + }, }; match ev { @@ -859,6 +788,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { error, .. } => { + let error = OutboundFailure::from(error); let started = match self .pending_requests .remove(&(protocol.clone(), request_id).into()) @@ -870,9 +800,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { }) => { // Try using the fallback request if the protocol was not // supported. - if let request_response::OutboundFailure::UnsupportedProtocols = - error - { + if matches!(error, OutboundFailure::UnsupportedProtocols) { if let Some((fallback_request, fallback_protocol)) = fallback_request { @@ -893,7 +821,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { } if response_tx - .send(Err(RequestFailure::Network(error.clone().into()))) + .send(Err(RequestFailure::Network(error.clone()))) .is_err() { log::debug!( @@ -920,7 +848,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour { peer, protocol: protocol.clone(), duration: started.elapsed(), - result: Err(RequestFailure::Network(error.into())), + result: Err(RequestFailure::Network(error)), }; return Poll::Ready(ToSwarm::GenerateEvent(out)) @@ -1184,7 +1112,10 @@ mod tests { transport, behaviour, keypair.public().to_peer_id(), - SwarmConfig::with_executor(TokioExecutor(runtime)), + SwarmConfig::with_executor(TokioExecutor(runtime)) + // This is taken care of by notification protocols in non-test environment + // It is very slow in test environment for some reason, hence larger timeout + .with_idle_connection_timeout(Duration::from_secs(10)), ); let listen_addr: Multiaddr = format!("/memory/{}", rand::random::()).parse().unwrap(); @@ -1354,7 +1285,9 @@ mod tests { match swarm.select_next_some().await { SwarmEvent::Behaviour(Event::InboundRequest { result, .. }) => { assert!(result.is_ok()); - break + }, + SwarmEvent::ConnectionClosed { .. } => { + break; }, _ => {}, } @@ -1394,20 +1327,20 @@ mod tests { } match response_receiver.unwrap().await.unwrap().unwrap_err() { - RequestFailure::Network(OutboundFailure::ConnectionClosed) => {}, - _ => panic!(), + RequestFailure::Network(OutboundFailure::Io(_)) => {}, + request_failure => panic!("Unexpected failure: {request_failure:?}"), } }); } - /// A [`RequestId`] is a unique identifier among either all inbound or all outbound requests for + /// A `RequestId` is a unique identifier among either all inbound or all outbound requests for /// a single [`RequestResponsesBehaviour`] behaviour. It is not guaranteed to be unique across - /// multiple [`RequestResponsesBehaviour`] behaviours. Thus when handling [`RequestId`] in the + /// multiple [`RequestResponsesBehaviour`] behaviours. Thus, when handling `RequestId` in the /// context of multiple [`RequestResponsesBehaviour`] behaviours, one needs to couple the - /// protocol name with the [`RequestId`] to get a unique request identifier. + /// protocol name with the `RequestId` to get a unique request identifier. /// /// This test ensures that two requests on different protocols can be handled concurrently - /// without a [`RequestId`] collision. + /// without a `RequestId` collision. /// /// See [`ProtocolRequestId`] for additional information. #[test] diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 71d0b45aa06d..751183ae19a9 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -41,7 +41,7 @@ use crate::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, peer_store::{PeerStore, PeerStoreProvider}, - protocol::{self, NotifsHandlerError, Protocol, Ready}, + protocol::{self, Protocol, Ready}, protocol_controller::{self, ProtoSetConfig, ProtocolController, SetId}, request_responses::{IfDisconnected, ProtocolConfig as RequestResponseConfig, RequestFailure}, service::{ @@ -59,16 +59,12 @@ use crate::{ }; use codec::DecodeAll; -use either::Either; use futures::{channel::oneshot, prelude::*}; -#[allow(deprecated)] -use libp2p::swarm::THandlerErr; use libp2p::{ connection_limits::{ConnectionLimits, Exceeded}, core::{upgrade, ConnectedPoint, Endpoint}, identify::Info as IdentifyInfo, identity::ed25519, - kad::{record::Key as KademliaKey, Record}, multiaddr::{self, Multiaddr}, swarm::{ Config as SwarmConfig, ConnectionError, ConnectionId, DialError, Executor, ListenError, @@ -80,6 +76,7 @@ use log::{debug, error, info, trace, warn}; use metrics::{Histogram, MetricSources, Metrics}; use parking_lot::Mutex; use prometheus_endpoint::Registry; +use sc_network_types::kad::{Key as KademliaKey, Record}; use sc_client_api::BlockBackend; use sc_network_common::{ @@ -94,7 +91,6 @@ pub use libp2p::identity::{DecodingError, Keypair, PublicKey}; pub use metrics::NotificationMetrics; pub use protocol::NotificationsSink; use std::{ - cmp, collections::{HashMap, HashSet}, fs, iter, marker::PhantomData, @@ -115,6 +111,7 @@ pub mod signature; pub mod traits; struct Libp2pBandwidthSink { + #[allow(deprecated)] sink: Arc, } @@ -336,7 +333,7 @@ where "🏷 Local node identity is: {}", local_peer_id.to_base58(), ); - log::info!(target: "sub-libp2p", "Running libp2p network backend"); + info!(target: "sub-libp2p", "Running libp2p network backend"); let (transport, bandwidth) = { let config_mem = match network_config.transport { @@ -344,46 +341,7 @@ where TransportConfig::Normal { .. } => false, }; - // The yamux buffer size limit is configured to be equal to the maximum frame size - // of all protocols. 10 bytes are added to each limit for the length prefix that - // is not included in the upper layer protocols limit but is still present in the - // yamux buffer. These 10 bytes correspond to the maximum size required to encode - // a variable-length-encoding 64bits number. In other words, we make the - // assumption that no notification larger than 2^64 will ever be sent. - let yamux_maximum_buffer_size = { - let requests_max = request_response_protocols - .iter() - .map(|cfg| usize::try_from(cfg.max_request_size).unwrap_or(usize::MAX)); - let responses_max = request_response_protocols - .iter() - .map(|cfg| usize::try_from(cfg.max_response_size).unwrap_or(usize::MAX)); - let notifs_max = notification_protocols - .iter() - .map(|cfg| usize::try_from(cfg.max_notification_size()).unwrap_or(usize::MAX)); - - // A "default" max is added to cover all the other protocols: ping, identify, - // kademlia, block announces, and transactions. - let default_max = cmp::max( - 1024 * 1024, - usize::try_from(protocol::BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE) - .unwrap_or(usize::MAX), - ); - - iter::once(default_max) - .chain(requests_max) - .chain(responses_max) - .chain(notifs_max) - .max() - .expect("iterator known to always yield at least one element; qed") - .saturating_add(10) - }; - - transport::build_transport( - local_identity.clone().into(), - config_mem, - network_config.yamux_window_size, - yamux_maximum_buffer_size, - ) + transport::build_transport(local_identity.clone().into(), config_mem) }; let (to_notifications, from_protocol_controllers) = @@ -973,6 +931,18 @@ where expires, )); } + + fn start_providing(&self, key: KademliaKey) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::StartProviding(key)); + } + + fn stop_providing(&self, key: KademliaKey) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::StopProviding(key)); + } + + fn get_providers(&self, key: KademliaKey) { + let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::GetProviders(key)); + } } #[async_trait::async_trait] @@ -1333,6 +1303,9 @@ enum ServiceToWorkerMsg { update_local_storage: bool, }, StoreRecord(KademliaKey, Vec, Option, Option), + StartProviding(KademliaKey), + StopProviding(KademliaKey), + GetProviders(KademliaKey), AddKnownAddress(PeerId, Multiaddr), EventStream(out_events::Sender), Request { @@ -1455,17 +1428,23 @@ where fn handle_worker_message(&mut self, msg: ServiceToWorkerMsg) { match msg { ServiceToWorkerMsg::GetValue(key) => - self.network_service.behaviour_mut().get_value(key), + self.network_service.behaviour_mut().get_value(key.into()), ServiceToWorkerMsg::PutValue(key, value) => - self.network_service.behaviour_mut().put_value(key, value), + self.network_service.behaviour_mut().put_value(key.into(), value), ServiceToWorkerMsg::PutRecordTo { record, peers, update_local_storage } => self .network_service .behaviour_mut() - .put_record_to(record, peers, update_local_storage), + .put_record_to(record.into(), peers, update_local_storage), ServiceToWorkerMsg::StoreRecord(key, value, publisher, expires) => self .network_service .behaviour_mut() - .store_record(key, value, publisher, expires), + .store_record(key.into(), value, publisher, expires), + ServiceToWorkerMsg::StartProviding(key) => + self.network_service.behaviour_mut().start_providing(key.into()), + ServiceToWorkerMsg::StopProviding(key) => + self.network_service.behaviour_mut().stop_providing(&key.into()), + ServiceToWorkerMsg::GetProviders(key) => + self.network_service.behaviour_mut().get_providers(key.into()), ServiceToWorkerMsg::AddKnownAddress(peer_id, addr) => self.network_service.behaviour_mut().add_known_address(peer_id, addr), ServiceToWorkerMsg::EventStream(sender) => self.event_streams.push(sender), @@ -1501,8 +1480,7 @@ where } /// Process the next event coming from `Swarm`. - #[allow(deprecated)] - fn handle_swarm_event(&mut self, event: SwarmEvent>>) { + fn handle_swarm_event(&mut self, event: SwarmEvent) { match event { SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, .. }) => { if let Some(metrics) = self.metrics.as_ref() { @@ -1527,6 +1505,7 @@ where Some("busy-omitted"), ResponseFailure::Network(InboundFailure::ConnectionClosed) => Some("connection-closed"), + ResponseFailure::Network(InboundFailure::Io(_)) => Some("io"), }; if let Some(reason) = reason { @@ -1566,6 +1545,7 @@ where "connection-closed", RequestFailure::Network(OutboundFailure::UnsupportedProtocols) => "unsupported", + RequestFailure::Network(OutboundFailure::Io(_)) => "io", }; metrics @@ -1678,6 +1658,9 @@ where DhtEvent::ValuePut(_) => "value-put", DhtEvent::ValuePutFailed(_) => "value-put-failed", DhtEvent::PutRecordRequest(_, _, _, _) => "put-record-request", + DhtEvent::StartProvidingFailed(_) => "start-providing-failed", + DhtEvent::ProvidersFound(_, _) => "providers-found", + DhtEvent::ProvidersNotFound(_) => "providers-not-found", }; metrics .kademlia_query_duration @@ -1732,15 +1715,6 @@ where }; let reason = match cause { Some(ConnectionError::IO(_)) => "transport-error", - Some(ConnectionError::Handler(Either::Left(Either::Left( - Either::Left(Either::Right( - NotifsHandlerError::SyncNotificationsClogged, - )), - )))) => "sync-notifications-clogged", - Some(ConnectionError::Handler(Either::Left(Either::Left( - Either::Right(Either::Left(_)), - )))) => "ping-timeout", - Some(ConnectionError::Handler(_)) => "protocol-error", Some(ConnectionError::KeepAliveTimeout) => "keep-alive-timeout", None => "actively-closed", }; @@ -1779,7 +1753,12 @@ where not_reported.then(|| self.boot_node_ids.get(&peer_id)).flatten() { if let DialError::WrongPeerId { obtained, endpoint } = &error { - if let ConnectedPoint::Dialer { address, role_override: _ } = endpoint { + if let ConnectedPoint::Dialer { + address, + role_override: _, + port_use: _, + } = endpoint + { let address_without_peer_id = parse_addr(address.clone().into()) .map_or_else(|_| address.clone(), |r| r.1.into()); @@ -1800,7 +1779,6 @@ where } if let Some(metrics) = self.metrics.as_ref() { - #[allow(deprecated)] let reason = match error { DialError::Denied { cause } => if cause.downcast::().is_ok() { @@ -1840,7 +1818,6 @@ where "Libp2p => IncomingConnectionError({local_addr},{send_back_addr} via {connection_id:?}): {error}" ); if let Some(metrics) = self.metrics.as_ref() { - #[allow(deprecated)] let reason = match error { ListenError::Denied { cause } => if cause.downcast::().is_ok() { @@ -1893,6 +1870,21 @@ where metrics.listeners_errors_total.inc(); } }, + SwarmEvent::NewExternalAddrCandidate { address } => { + trace!(target: "sub-libp2p", "Libp2p => NewExternalAddrCandidate: {address:?}"); + }, + SwarmEvent::ExternalAddrConfirmed { address } => { + trace!(target: "sub-libp2p", "Libp2p => ExternalAddrConfirmed: {address:?}"); + }, + SwarmEvent::ExternalAddrExpired { address } => { + trace!(target: "sub-libp2p", "Libp2p => ExternalAddrExpired: {address:?}"); + }, + SwarmEvent::NewExternalAddrOfPeer { peer_id, address } => { + trace!(target: "sub-libp2p", "Libp2p => NewExternalAddrOfPeer({peer_id:?}): {address:?}") + }, + event => { + warn!(target: "sub-libp2p", "New unknown SwarmEvent libp2p event: {event:?}"); + }, } } } diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index bd4f83c7fd44..acfed9ea894c 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -32,12 +32,15 @@ use crate::{ }; use futures::{channel::oneshot, Stream}; -use libp2p::kad::Record; use prometheus_endpoint::Registry; use sc_client_api::BlockBackend; use sc_network_common::{role::ObservedRole, ExHashT}; -use sc_network_types::{multiaddr::Multiaddr, PeerId}; +pub use sc_network_types::{ + kad::{Key as KademliaKey, Record}, + multiaddr::Multiaddr, + PeerId, +}; use sp_runtime::traits::Block as BlockT; use std::{ @@ -49,7 +52,7 @@ use std::{ time::{Duration, Instant}, }; -pub use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; +pub use libp2p::identity::SigningError; /// Supertrait defining the services provided by [`NetworkBackend`] service handle. pub trait NetworkService: @@ -231,6 +234,15 @@ pub trait NetworkDHTProvider { publisher: Option, expires: Option, ); + + /// Register this node as a provider for `key` on the DHT. + fn start_providing(&self, key: KademliaKey); + + /// Deregister this node as a provider for `key` on the DHT. + fn stop_providing(&self, key: KademliaKey); + + /// Start getting the list of providers for `key` on the DHT. + fn get_providers(&self, key: KademliaKey); } impl NetworkDHTProvider for Arc @@ -259,6 +271,18 @@ where ) { T::store_record(self, key, value, publisher, expires) } + + fn start_providing(&self, key: KademliaKey) { + T::start_providing(self, key) + } + + fn stop_providing(&self, key: KademliaKey) { + T::stop_providing(self, key) + } + + fn get_providers(&self, key: KademliaKey) { + T::get_providers(self, key) + } } /// Provides an ability to set a fork sync request for a particular block. diff --git a/substrate/client/network/src/transport.rs b/substrate/client/network/src/transport.rs index ed7e7c574e16..2f6b7a643c48 100644 --- a/substrate/client/network/src/transport.rs +++ b/substrate/client/network/src/transport.rs @@ -29,6 +29,8 @@ use libp2p::{ }; use std::{sync::Arc, time::Duration}; +// TODO: Create a wrapper similar to upstream `BandwidthTransport` that tracks sent/received bytes +#[allow(deprecated)] pub use libp2p::bandwidth::BandwidthSinks; /// Builds the transport that serves as a common ground for all connections. @@ -36,21 +38,12 @@ pub use libp2p::bandwidth::BandwidthSinks; /// If `memory_only` is true, then only communication within the same process are allowed. Only /// addresses with the format `/memory/...` are allowed. /// -/// `yamux_window_size` is the maximum size of the Yamux receive windows. `None` to leave the -/// default (256kiB). -/// -/// `yamux_maximum_buffer_size` is the maximum allowed size of the Yamux buffer. This should be -/// set either to the maximum of all the maximum allowed sizes of messages frames of all -/// high-level protocols combined, or to some generously high value if you are sure that a maximum -/// size is enforced on all high-level protocols. -/// /// Returns a `BandwidthSinks` object that allows querying the average bandwidth produced by all /// the connections spawned with this transport. +#[allow(deprecated)] pub fn build_transport( keypair: identity::Keypair, memory_only: bool, - yamux_window_size: Option, - yamux_maximum_buffer_size: usize, ) -> (Boxed<(PeerId, StreamMuxerBox)>, Arc) { // Build the base layer of the transport. let transport = if !memory_only { @@ -81,19 +74,7 @@ pub fn build_transport( }; let authentication_config = noise::Config::new(&keypair).expect("Can create noise config. qed"); - let multiplexing_config = { - let mut yamux_config = libp2p::yamux::Config::default(); - // Enable proper flow-control: window updates are only sent when - // buffered data has been consumed. - yamux_config.set_window_update_mode(libp2p::yamux::WindowUpdateMode::on_read()); - yamux_config.set_max_buffer_size(yamux_maximum_buffer_size); - - if let Some(yamux_window_size) = yamux_window_size { - yamux_config.set_receive_window_size(yamux_window_size); - } - - yamux_config - }; + let multiplexing_config = libp2p::yamux::Config::default(); let transport = transport .upgrade(upgrade::Version::V1Lazy) diff --git a/substrate/client/network/src/types.rs b/substrate/client/network/src/types.rs index 0652bbcdddec..5289389de381 100644 --- a/substrate/client/network/src/types.rs +++ b/substrate/client/network/src/types.rs @@ -26,8 +26,6 @@ use std::{ sync::Arc, }; -pub use libp2p::{multiaddr, Multiaddr, PeerId}; - /// The protocol name transmitted on the wire. #[derive(Debug, Clone)] pub enum ProtocolName { diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index 43933f066edd..dd3a8bef8a2f 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -22,10 +22,10 @@ codec = { features = ["derive"], workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-statement-store = { workspace = true, default-features = true } diff --git a/substrate/client/network/statement/src/lib.rs b/substrate/client/network/statement/src/lib.rs index df93788696e3..586a15cadd68 100644 --- a/substrate/client/network/statement/src/lib.rs +++ b/substrate/client/network/statement/src/lib.rs @@ -33,7 +33,8 @@ use futures::{channel::oneshot, prelude::*, stream::FuturesUnordered, FutureExt} use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::{ config::{NonReservedPeerMode, SetConfig}, - error, multiaddr, + error, + multiaddr::{Multiaddr, Protocol}, peer_store::PeerStoreProvider, service::{ traits::{NotificationEvent, NotificationService, ValidationResult}, @@ -296,9 +297,19 @@ where fn handle_sync_event(&mut self, event: SyncEvent) { match event { - SyncEvent::PeerConnected(remote) => { - let addr = iter::once(multiaddr::Protocol::P2p(remote.into())) - .collect::(); + SyncEvent::InitialPeers(peer_ids) => { + let addrs = peer_ids + .into_iter() + .map(|peer_id| Multiaddr::empty().with(Protocol::P2p(peer_id.into()))) + .collect(); + let result = + self.network.add_peers_to_reserved_set(self.protocol_name.clone(), addrs); + if let Err(err) = result { + log::error!(target: LOG_TARGET, "Add reserved peers failed: {}", err); + } + }, + SyncEvent::PeerConnected(peer_id) => { + let addr = Multiaddr::empty().with(Protocol::P2p(peer_id.into())); let result = self.network.add_peers_to_reserved_set( self.protocol_name.clone(), iter::once(addr).collect(), @@ -307,10 +318,10 @@ where log::error!(target: LOG_TARGET, "Add reserved peer failed: {}", err); } }, - SyncEvent::PeerDisconnected(remote) => { + SyncEvent::PeerDisconnected(peer_id) => { let result = self.network.remove_peers_from_reserved_set( self.protocol_name.clone(), - iter::once(remote).collect(), + iter::once(peer_id).collect(), ); if let Err(err) = result { log::error!(target: LOG_TARGET, "Failed to remove reserved peer: {err}"); diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index 378b7c12e9b7..fdc290a2d01e 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -23,30 +23,30 @@ array-bytes = { workspace = true, default-features = true } async-channel = { workspace = true } async-trait = { workspace = true } codec = { features = ["derive"], workspace = true, default-features = true } +fork-tree = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } log = { workspace = true, default-features = true } mockall = { workspace = true } -prost = { workspace = true } -schnellru = { workspace = true } -smallvec = { workspace = true, default-features = true } -thiserror = { workspace = true } -tokio-stream = { workspace = true } -tokio = { features = ["macros", "time"], workspace = true, default-features = true } -fork-tree = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +prost = { workspace = true } sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +schnellru = { workspace = true } +smallvec = { workspace = true, default-features = true } sp-arithmetic = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } +tokio = { features = ["macros", "time"], workspace = true, default-features = true } +tokio-stream = { workspace = true } [dev-dependencies] mockall = { workspace = true } diff --git a/substrate/client/network/sync/src/block_relay_protocol.rs b/substrate/client/network/sync/src/block_relay_protocol.rs index 3c5b3739e822..13639d851b27 100644 --- a/substrate/client/network/sync/src/block_relay_protocol.rs +++ b/substrate/client/network/sync/src/block_relay_protocol.rs @@ -21,7 +21,7 @@ use sc_network::{request_responses::RequestFailure, NetworkBackend, ProtocolName use sc_network_common::sync::message::{BlockData, BlockRequest}; use sc_network_types::PeerId; use sp_runtime::traits::Block as BlockT; -use std::sync::Arc; +use std::{fmt, sync::Arc}; /// The serving side of the block relay protocol. It runs a single instance /// of the server task that processes the incoming protocol messages. @@ -34,7 +34,10 @@ pub trait BlockServer: Send { /// The client side stub to download blocks from peers. This is a handle /// that can be used to initiate concurrent downloads. #[async_trait::async_trait] -pub trait BlockDownloader: Send + Sync { +pub trait BlockDownloader: fmt::Debug + Send + Sync { + /// Protocol name used by block downloader. + fn protocol_name(&self) -> &ProtocolName; + /// Performs the protocol specific sequence to fetch the blocks from the peer. /// Output: if the download succeeds, the response is a `Vec` which is /// in a format specific to the protocol implementation. The block data diff --git a/substrate/client/network/sync/src/block_request_handler.rs b/substrate/client/network/sync/src/block_request_handler.rs index 6e970b399310..80234170bc20 100644 --- a/substrate/client/network/sync/src/block_request_handler.rs +++ b/substrate/client/network/sync/src/block_request_handler.rs @@ -502,6 +502,7 @@ enum HandleRequestError { } /// The full block downloader implementation of [`BlockDownloader]. +#[derive(Debug)] pub struct FullBlockDownloader { protocol_name: ProtocolName, network: NetworkServiceHandle, @@ -576,6 +577,10 @@ impl FullBlockDownloader { #[async_trait::async_trait] impl BlockDownloader for FullBlockDownloader { + fn protocol_name(&self) -> &ProtocolName { + &self.protocol_name + } + async fn download_blocks( &self, who: PeerId, diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index dceea9954c6e..4003361525e1 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -23,30 +23,22 @@ use crate::{ block_announce_validator::{ BlockAnnounceValidationResult, BlockAnnounceValidator as BlockAnnounceValidatorStream, }, - block_relay_protocol::{BlockDownloader, BlockResponseError}, pending_responses::{PendingResponses, ResponseEvent}, - schema::v1::{StateRequest, StateResponse}, service::{ self, syncing_service::{SyncingService, ToServiceCommand}, }, - strategy::{ - warp::{EncodedProof, WarpProofRequest}, - StrategyKey, SyncingAction, SyncingStrategy, - }, - types::{ - BadPeer, ExtendedPeerInfo, OpaqueStateRequest, OpaqueStateResponse, PeerRequest, SyncEvent, - }, + strategy::{SyncingAction, SyncingStrategy}, + types::{BadPeer, ExtendedPeerInfo, SyncEvent}, LOG_TARGET, }; use codec::{Decode, DecodeAll, Encode}; -use futures::{channel::oneshot, FutureExt, StreamExt}; +use futures::{channel::oneshot, StreamExt}; use log::{debug, error, trace, warn}; use prometheus_endpoint::{ register, Counter, Gauge, MetricSource, Opts, PrometheusError, Registry, SourcedGauge, U64, }; -use prost::Message; use schnellru::{ByLength, LruMap}; use tokio::time::{Interval, MissedTickBehavior}; @@ -55,7 +47,7 @@ use sc_consensus::{import_queue::ImportQueueService, IncomingBlock}; use sc_network::{ config::{FullNetworkConfiguration, NotificationHandshake, ProtocolId, SetConfig}, peer_store::PeerStoreProvider, - request_responses::{IfDisconnected, OutboundFailure, RequestFailure}, + request_responses::{OutboundFailure, RequestFailure}, service::{ traits::{Direction, NotificationConfig, NotificationEvent, ValidationResult}, NotificationMetrics, @@ -66,7 +58,7 @@ use sc_network::{ }; use sc_network_common::{ role::Roles, - sync::message::{BlockAnnounce, BlockAnnouncesHandshake, BlockRequest, BlockState}, + sync::message::{BlockAnnounce, BlockAnnouncesHandshake, BlockState}, }; use sc_network_types::PeerId; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -102,14 +94,14 @@ mod rep { pub const GENESIS_MISMATCH: Rep = Rep::new_fatal("Genesis mismatch"); /// Peer send us a block announcement that failed at validation. pub const BAD_BLOCK_ANNOUNCEMENT: Rep = Rep::new(-(1 << 12), "Bad block announcement"); - /// We received a message that failed to decode. - pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); /// Peer is on unsupported protocol version. pub const BAD_PROTOCOL: Rep = Rep::new_fatal("Unsupported protocol"); /// Reputation change when a peer refuses a request. pub const REFUSED: Rep = Rep::new(-(1 << 10), "Request refused"); /// Reputation change when a peer doesn't respond in time to our messages. pub const TIMEOUT: Rep = Rep::new(-(1 << 10), "Request timeout"); + /// Reputation change when a peer connection failed with IO error. + pub const IO: Rep = Rep::new(-(1 << 10), "IO error during request"); } struct Metrics { @@ -264,10 +256,7 @@ pub struct SyncingEngine { peer_store_handle: Arc, /// Pending responses - pending_responses: PendingResponses, - - /// Block downloader - block_downloader: Arc>, + pending_responses: PendingResponses, /// Handle to import queue. import_queue: Box>, @@ -291,12 +280,11 @@ where network_metrics: NotificationMetrics, net_config: &FullNetworkConfiguration::Hash, N>, protocol_id: ProtocolId, - fork_id: &Option, + fork_id: Option<&str>, block_announce_validator: Box + Send>, syncing_strategy: Box>, network_service: service::network::NetworkServiceHandle, import_queue: Box>, - block_downloader: Arc>, peer_store_handle: Arc, ) -> Result<(Self, SyncingService, N::NotificationProtocolConfig), ClientError> where @@ -417,7 +405,6 @@ where None }, pending_responses: PendingResponses::new(), - block_downloader, import_queue, }, SyncingService::new(tx, num_connected, is_major_syncing), @@ -560,7 +547,14 @@ where self.process_service_command(command), notification_event = self.notification_service.next_event() => match notification_event { Some(event) => self.process_notification_event(event), - None => return, + None => { + error!( + target: LOG_TARGET, + "Terminating `SyncingEngine` because `NotificationService` has terminated.", + ); + + return; + } }, response_event = self.pending_responses.select_next_some() => self.process_response_event(response_event), @@ -583,57 +577,42 @@ where } fn process_strategy_actions(&mut self) -> Result<(), ClientError> { - for action in self.strategy.actions()? { + for action in self.strategy.actions(&self.network_service)? { match action { - SyncingAction::SendBlockRequest { peer_id, key, request } => { - // Sending block request implies dropping obsolete pending response as we are - // not interested in it anymore (see [`SyncingAction::SendBlockRequest`]). - let removed = self.pending_responses.remove(peer_id, key); - self.send_block_request(peer_id, key, request.clone()); - - if removed { - warn!( - target: LOG_TARGET, - "Processed `ChainSyncAction::SendBlockRequest` to {} from {:?} with {:?}. \ - Stale response removed!", - peer_id, - key, - request, - ) - } else { + SyncingAction::StartRequest { peer_id, key, request, remove_obsolete } => { + if !self.peers.contains_key(&peer_id) { trace!( target: LOG_TARGET, - "Processed `ChainSyncAction::SendBlockRequest` to {} from {:?} with {:?}.", - peer_id, - key, - request, - ) + "Cannot start request with strategy key {key:?} to unknown peer \ + {peer_id}", + ); + debug_assert!(false); + continue; } + if remove_obsolete { + if self.pending_responses.remove(peer_id, key) { + warn!( + target: LOG_TARGET, + "Processed `SyncingAction::StartRequest` to {peer_id} with \ + strategy key {key:?}. Stale response removed!", + ) + } else { + trace!( + target: LOG_TARGET, + "Processed `SyncingAction::StartRequest` to {peer_id} with \ + strategy key {key:?}.", + ) + } + } + + self.pending_responses.insert(peer_id, key, request); }, SyncingAction::CancelRequest { peer_id, key } => { let removed = self.pending_responses.remove(peer_id, key); trace!( target: LOG_TARGET, - "Processed {action:?}, response removed: {removed}.", - ); - }, - SyncingAction::SendStateRequest { peer_id, key, protocol_name, request } => { - self.send_state_request(peer_id, key, protocol_name, request); - - trace!( - target: LOG_TARGET, - "Processed `ChainSyncAction::SendStateRequest` to {peer_id}.", - ); - }, - SyncingAction::SendWarpProofRequest { peer_id, key, protocol_name, request } => { - self.send_warp_proof_request(peer_id, key, protocol_name, request.clone()); - - trace!( - target: LOG_TARGET, - "Processed `ChainSyncAction::SendWarpProofRequest` to {}, request: {:?}.", - peer_id, - request, + "Processed `SyncingAction::CancelRequest`, response removed: {removed}.", ); }, SyncingAction::DropPeer(BadPeer(peer_id, rep)) => { @@ -677,7 +656,11 @@ where ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { self.strategy.set_sync_fork_request(peers, &hash, number); }, - ToServiceCommand::EventStream(tx) => self.event_streams.push(tx), + ToServiceCommand::EventStream(tx) => { + let _ = tx + .unbounded_send(SyncEvent::InitialPeers(self.peers.keys().cloned().collect())); + self.event_streams.push(tx); + }, ToServiceCommand::RequestJustification(hash, number) => self.strategy.request_justification(&hash, number), ToServiceCommand::ClearJustificationRequests => @@ -1000,160 +983,12 @@ where Ok(()) } - fn send_block_request(&mut self, peer_id: PeerId, key: StrategyKey, request: BlockRequest) { - if !self.peers.contains_key(&peer_id) { - trace!(target: LOG_TARGET, "Cannot send block request to unknown peer {peer_id}"); - debug_assert!(false); - return; - } - - let downloader = self.block_downloader.clone(); - - self.pending_responses.insert( - peer_id, - key, - PeerRequest::Block(request.clone()), - async move { downloader.download_blocks(peer_id, request).await }.boxed(), - ); - } - - fn send_state_request( - &mut self, - peer_id: PeerId, - key: StrategyKey, - protocol_name: ProtocolName, - request: OpaqueStateRequest, - ) { - if !self.peers.contains_key(&peer_id) { - trace!(target: LOG_TARGET, "Cannot send state request to unknown peer {peer_id}"); - debug_assert!(false); - return; - } - - let (tx, rx) = oneshot::channel(); - - self.pending_responses.insert(peer_id, key, PeerRequest::State, rx.boxed()); - - match Self::encode_state_request(&request) { - Ok(data) => { - self.network_service.start_request( - peer_id, - protocol_name, - data, - tx, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: LOG_TARGET, - "Failed to encode state request {request:?}: {err:?}", - ); - }, - } - } - - fn send_warp_proof_request( - &mut self, - peer_id: PeerId, - key: StrategyKey, - protocol_name: ProtocolName, - request: WarpProofRequest, - ) { - if !self.peers.contains_key(&peer_id) { - trace!(target: LOG_TARGET, "Cannot send warp proof request to unknown peer {peer_id}"); - debug_assert!(false); - return; - } - - let (tx, rx) = oneshot::channel(); - - self.pending_responses.insert(peer_id, key, PeerRequest::WarpProof, rx.boxed()); - - self.network_service.start_request( - peer_id, - protocol_name, - request.encode(), - tx, - IfDisconnected::ImmediateError, - ); - } - - fn encode_state_request(request: &OpaqueStateRequest) -> Result, String> { - let request: &StateRequest = request.0.downcast_ref().ok_or_else(|| { - "Failed to downcast opaque state response during encoding, this is an \ - implementation bug." - .to_string() - })?; + fn process_response_event(&mut self, response_event: ResponseEvent) { + let ResponseEvent { peer_id, key, response: response_result } = response_event; - Ok(request.encode_to_vec()) - } - - fn decode_state_response(response: &[u8]) -> Result { - let response = StateResponse::decode(response) - .map_err(|error| format!("Failed to decode state response: {error}"))?; - - Ok(OpaqueStateResponse(Box::new(response))) - } - - fn process_response_event(&mut self, response_event: ResponseEvent) { - let ResponseEvent { peer_id, key, request, response } = response_event; - - match response { - Ok(Ok((resp, _))) => match request { - PeerRequest::Block(req) => { - match self.block_downloader.block_response_into_blocks(&req, resp) { - Ok(blocks) => { - self.strategy.on_block_response(peer_id, key, req, blocks); - }, - Err(BlockResponseError::DecodeFailed(e)) => { - debug!( - target: LOG_TARGET, - "Failed to decode block response from peer {:?}: {:?}.", - peer_id, - e - ); - self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); - self.network_service.disconnect_peer( - peer_id, - self.block_announce_protocol_name.clone(), - ); - return; - }, - Err(BlockResponseError::ExtractionFailed(e)) => { - debug!( - target: LOG_TARGET, - "Failed to extract blocks from peer response {:?}: {:?}.", - peer_id, - e - ); - self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); - return; - }, - } - }, - PeerRequest::State => { - let response = match Self::decode_state_response(&resp[..]) { - Ok(proto) => proto, - Err(e) => { - debug!( - target: LOG_TARGET, - "Failed to decode state response from peer {peer_id:?}: {e:?}.", - ); - self.network_service.report_peer(peer_id, rep::BAD_MESSAGE); - self.network_service.disconnect_peer( - peer_id, - self.block_announce_protocol_name.clone(), - ); - return; - }, - }; - - self.strategy.on_state_response(peer_id, key, response); - }, - PeerRequest::WarpProof => { - self.strategy.on_warp_proof_response(&peer_id, key, EncodedProof(resp)); - }, + match response_result { + Ok(Ok((response, protocol_name))) => { + self.strategy.on_generic_response(&peer_id, key, protocol_name, response); }, Ok(Err(e)) => { debug!(target: LOG_TARGET, "Request to peer {peer_id:?} failed: {e:?}."); @@ -1190,9 +1025,14 @@ where debug_assert!( false, "Can not receive `RequestFailure::Obsolete` after dropping the \ - response receiver.", + response receiver.", ); }, + RequestFailure::Network(OutboundFailure::Io(_)) => { + self.network_service.report_peer(peer_id, rep::IO); + self.network_service + .disconnect_peer(peer_id, self.block_announce_protocol_name.clone()); + }, } }, Err(oneshot::Canceled) => { @@ -1214,7 +1054,7 @@ where /// Get config for the block announcement protocol fn get_block_announce_proto_config::Hash>>( protocol_id: ProtocolId, - fork_id: &Option, + fork_id: Option<&str>, roles: Roles, best_number: NumberFor, best_hash: B::Hash, @@ -1225,7 +1065,7 @@ where ) -> (N::NotificationProtocolConfig, Box) { let block_announces_protocol = { let genesis_hash = genesis_hash.as_ref(); - if let Some(ref fork_id) = fork_id { + if let Some(fork_id) = fork_id { format!( "/{}/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash), diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index c458c7a5da49..e503a1cbdb18 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -18,6 +18,7 @@ //! Blockchain syncing implementation in Substrate. +pub use schema::v1::*; pub use service::syncing_service::SyncingService; pub use strategy::warp::{WarpSyncConfig, WarpSyncPhase, WarpSyncProgress}; pub use types::{SyncEvent, SyncEventStream, SyncState, SyncStatus, SyncStatusProvider}; diff --git a/substrate/client/network/sync/src/mock.rs b/substrate/client/network/sync/src/mock.rs index 741fa7139583..bf25156f9703 100644 --- a/substrate/client/network/sync/src/mock.rs +++ b/substrate/client/network/sync/src/mock.rs @@ -27,10 +27,13 @@ use sc_network_types::PeerId; use sp_runtime::traits::Block as BlockT; mockall::mock! { + #[derive(Debug)] pub BlockDownloader {} #[async_trait::async_trait] impl BlockDownloaderT for BlockDownloader { + fn protocol_name(&self) -> &ProtocolName; + async fn download_blocks( &self, who: PeerId, diff --git a/substrate/client/network/sync/src/pending_responses.rs b/substrate/client/network/sync/src/pending_responses.rs index 7d2d598a2e06..46e6ae626328 100644 --- a/substrate/client/network/sync/src/pending_responses.rs +++ b/substrate/client/network/sync/src/pending_responses.rs @@ -19,7 +19,7 @@ //! [`PendingResponses`] is responsible for keeping track of pending responses and //! polling them. [`Stream`] implemented by [`PendingResponses`] never terminates. -use crate::{strategy::StrategyKey, types::PeerRequest, LOG_TARGET}; +use crate::{strategy::StrategyKey, LOG_TARGET}; use futures::{ channel::oneshot, future::BoxFuture, @@ -27,61 +27,49 @@ use futures::{ FutureExt, StreamExt, }; use log::error; +use std::any::Any; use sc_network::{request_responses::RequestFailure, types::ProtocolName}; use sc_network_types::PeerId; -use sp_runtime::traits::Block as BlockT; use std::task::{Context, Poll, Waker}; use tokio_stream::StreamMap; /// Response result. -type ResponseResult = Result, ProtocolName), RequestFailure>, oneshot::Canceled>; +type ResponseResult = + Result, ProtocolName), RequestFailure>, oneshot::Canceled>; /// A future yielding [`ResponseResult`]. -type ResponseFuture = BoxFuture<'static, ResponseResult>; +pub(crate) type ResponseFuture = BoxFuture<'static, ResponseResult>; /// An event we receive once a pending response future resolves. -pub(crate) struct ResponseEvent { +pub(crate) struct ResponseEvent { pub peer_id: PeerId, pub key: StrategyKey, - pub request: PeerRequest, pub response: ResponseResult, } /// Stream taking care of polling pending responses. -pub(crate) struct PendingResponses { +pub(crate) struct PendingResponses { /// Pending responses - pending_responses: - StreamMap<(PeerId, StrategyKey), BoxStream<'static, (PeerRequest, ResponseResult)>>, + pending_responses: StreamMap<(PeerId, StrategyKey), BoxStream<'static, ResponseResult>>, /// Waker to implement never terminating stream waker: Option, } -impl PendingResponses { +impl PendingResponses { pub fn new() -> Self { Self { pending_responses: StreamMap::new(), waker: None } } - pub fn insert( - &mut self, - peer_id: PeerId, - key: StrategyKey, - request: PeerRequest, - response_future: ResponseFuture, - ) { - let request_type = request.get_type(); - + pub fn insert(&mut self, peer_id: PeerId, key: StrategyKey, response_future: ResponseFuture) { if self .pending_responses - .insert( - (peer_id, key), - Box::pin(async move { (request, response_future.await) }.into_stream()), - ) + .insert((peer_id, key), Box::pin(response_future.into_stream())) .is_some() { error!( target: LOG_TARGET, - "Discarded pending response from peer {peer_id}, request type: {request_type:?}.", + "Discarded pending response from peer {peer_id}, strategy key: {key:?}.", ); debug_assert!(false); } @@ -112,21 +100,21 @@ impl PendingResponses { } } -impl Stream for PendingResponses { - type Item = ResponseEvent; +impl Stream for PendingResponses { + type Item = ResponseEvent; fn poll_next( mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { match self.pending_responses.poll_next_unpin(cx) { - Poll::Ready(Some(((peer_id, key), (request, response)))) => { + Poll::Ready(Some(((peer_id, key), response))) => { // We need to manually remove the stream, because `StreamMap` doesn't know yet that // it's going to yield `None`, so may not remove it before the next request is made // to the same peer. self.pending_responses.remove(&(peer_id, key)); - Poll::Ready(Some(ResponseEvent { peer_id, key, request, response })) + Poll::Ready(Some(ResponseEvent { peer_id, key, response })) }, Poll::Ready(None) | Poll::Pending => { self.waker = Some(cx.waker().clone()); @@ -138,7 +126,7 @@ impl Stream for PendingResponses { } // As [`PendingResponses`] never terminates, we can easily implement [`FusedStream`] for it. -impl FusedStream for PendingResponses { +impl FusedStream for PendingResponses { fn is_terminated(&self) -> bool { false } diff --git a/substrate/client/network/sync/src/service/mock.rs b/substrate/client/network/sync/src/service/mock.rs index 141edc7c8841..300aa076515f 100644 --- a/substrate/client/network/sync/src/service/mock.rs +++ b/substrate/client/network/sync/src/service/mock.rs @@ -45,19 +45,19 @@ mockall::mock! { impl sc_consensus::Link for ChainSyncInterface { fn blocks_processed( - &mut self, + &self, imported: usize, count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, ); fn justification_imported( - &mut self, + &self, who: PeerId, hash: &B::Hash, number: NumberFor, success: bool, ); - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor); + fn request_justification(&self, hash: &B::Hash, number: NumberFor); } } diff --git a/substrate/client/network/sync/src/service/network.rs b/substrate/client/network/sync/src/service/network.rs index e848b5f62c1b..139e1a986a92 100644 --- a/substrate/client/network/sync/src/service/network.rs +++ b/substrate/client/network/sync/src/service/network.rs @@ -39,9 +39,11 @@ impl Network for T where T: NetworkPeers + NetworkRequest {} /// calls the `NetworkService` on its behalf. pub struct NetworkServiceProvider { rx: TracingUnboundedReceiver, + handle: NetworkServiceHandle, } /// Commands that `ChainSync` wishes to send to `NetworkService` +#[derive(Debug)] pub enum ToServiceCommand { /// Call `NetworkPeers::disconnect_peer()` DisconnectPeer(PeerId, ProtocolName), @@ -61,7 +63,7 @@ pub enum ToServiceCommand { /// Handle that is (temporarily) passed to `ChainSync` so it can /// communicate with `NetworkService` through `SyncingEngine` -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct NetworkServiceHandle { tx: TracingUnboundedSender, } @@ -99,15 +101,23 @@ impl NetworkServiceHandle { impl NetworkServiceProvider { /// Create new `NetworkServiceProvider` - pub fn new() -> (Self, NetworkServiceHandle) { + pub fn new() -> Self { let (tx, rx) = tracing_unbounded("mpsc_network_service_provider", 100_000); - (Self { rx }, NetworkServiceHandle::new(tx)) + Self { rx, handle: NetworkServiceHandle::new(tx) } + } + + /// Get handle to talk to the provider + pub fn handle(&self) -> NetworkServiceHandle { + self.handle.clone() } /// Run the `NetworkServiceProvider` - pub async fn run(mut self, service: Arc) { - while let Some(inner) = self.rx.next().await { + pub async fn run(self, service: Arc) { + let Self { mut rx, handle } = self; + drop(handle); + + while let Some(inner) = rx.next().await { match inner { ToServiceCommand::DisconnectPeer(peer, protocol_name) => service.disconnect_peer(peer, protocol_name), @@ -129,7 +139,8 @@ mod tests { // and then reported #[tokio::test] async fn disconnect_and_report_peer() { - let (provider, handle) = NetworkServiceProvider::new(); + let provider = NetworkServiceProvider::new(); + let handle = provider.handle(); let peer = PeerId::random(); let proto = ProtocolName::from("test-protocol"); diff --git a/substrate/client/network/sync/src/service/syncing_service.rs b/substrate/client/network/sync/src/service/syncing_service.rs index 08a2b36118a9..b56af2b9976a 100644 --- a/substrate/client/network/sync/src/service/syncing_service.rs +++ b/substrate/client/network/sync/src/service/syncing_service.rs @@ -177,7 +177,7 @@ impl SyncStatusProvider for SyncingService { impl Link for SyncingService { fn blocks_processed( - &mut self, + &self, imported: usize, count: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, @@ -188,7 +188,7 @@ impl Link for SyncingService { } fn justification_imported( - &mut self, + &self, who: PeerId, hash: &B::Hash, number: NumberFor, @@ -199,7 +199,7 @@ impl Link for SyncingService { .unbounded_send(ToServiceCommand::JustificationImported(who, *hash, number, success)); } - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + fn request_justification(&self, hash: &B::Hash, number: NumberFor) { let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number)); } } diff --git a/substrate/client/network/sync/src/strategy.rs b/substrate/client/network/sync/src/strategy.rs index 81998b7576bb..2ac6674231e5 100644 --- a/substrate/client/network/sync/src/strategy.rs +++ b/substrate/client/network/sync/src/strategy.rs @@ -16,50 +16,35 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! [`PolkadotSyncingStrategy`] is a proxy between [`crate::engine::SyncingEngine`] -//! and specific syncing algorithms. +//! [`SyncingStrategy`] defines an interface [`crate::engine::SyncingEngine`] uses as a specific +//! syncing algorithm. +//! +//! A few different strategies are provided by Substrate out of the box with custom strategies +//! possible too. pub mod chain_sync; mod disconnected_peers; -mod state; +pub mod polkadot; +pub mod state; pub mod state_sync; pub mod warp; use crate::{ - block_request_handler::MAX_BLOCKS_IN_RESPONSE, - types::{BadPeer, OpaqueStateRequest, OpaqueStateResponse, SyncStatus}, - LOG_TARGET, + pending_responses::ResponseFuture, + service::network::NetworkServiceHandle, + types::{BadPeer, SyncStatus}, }; -use chain_sync::{ChainSync, ChainSyncMode}; -use log::{debug, error, info}; -use prometheus_endpoint::Registry; -use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; use sc_network::ProtocolName; -use sc_network_common::sync::{ - message::{BlockAnnounce, BlockData, BlockRequest}, - SyncMode, -}; +use sc_network_common::sync::message::BlockAnnounce; use sc_network_types::PeerId; -use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; +use sp_blockchain::Error as ClientError; use sp_consensus::BlockOrigin; use sp_runtime::{ - traits::{Block as BlockT, Header, NumberFor}, + traits::{Block as BlockT, NumberFor}, Justifications, }; -use state::{StateStrategy, StateStrategyAction}; -use std::{collections::HashMap, sync::Arc}; -use warp::{EncodedProof, WarpProofRequest, WarpSync, WarpSyncAction, WarpSyncConfig}; - -/// Corresponding `ChainSync` mode. -fn chain_sync_mode(sync_mode: SyncMode) -> ChainSyncMode { - match sync_mode { - SyncMode::Full => ChainSyncMode::Full, - SyncMode::LightState { skip_proofs, storage_chain_mode } => - ChainSyncMode::LightState { skip_proofs, storage_chain_mode }, - SyncMode::Warp => ChainSyncMode::Full, - } -} +use std::any::Any; /// Syncing strategy for syncing engine to use pub trait SyncingStrategy: Send @@ -101,29 +86,16 @@ where /// Report a justification import (successful or not). fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool); - /// Process block response. - fn on_block_response( - &mut self, - peer_id: PeerId, - key: StrategyKey, - request: BlockRequest, - blocks: Vec>, - ); - - /// Process state response. - fn on_state_response( - &mut self, - peer_id: PeerId, - key: StrategyKey, - response: OpaqueStateResponse, - ); - - /// Process warp proof response. - fn on_warp_proof_response( + /// Process generic response. + /// + /// Strategy has to create opaque response and should be to downcast it back into concrete type + /// internally. Failure to downcast is an implementation bug. + fn on_generic_response( &mut self, peer_id: &PeerId, key: StrategyKey, - response: EncodedProof, + protocol_name: ProtocolName, + response: Box, ); /// A batch of blocks that have been processed, with or without errors. @@ -160,52 +132,32 @@ where /// Get actions that should be performed by the owner on the strategy's behalf #[must_use] - fn actions(&mut self) -> Result>, ClientError>; -} - -/// Syncing configuration containing data for all strategies. -#[derive(Clone, Debug)] -pub struct SyncingConfig { - /// Syncing mode. - pub mode: SyncMode, - /// The number of parallel downloads to guard against slow peers. - pub max_parallel_downloads: u32, - /// Maximum number of blocks to request. - pub max_blocks_per_request: u32, - /// Prometheus metrics registry. - pub metrics_registry: Option, - /// Protocol name used to send out state requests - pub state_request_protocol_name: ProtocolName, + fn actions( + &mut self, + // TODO: Consider making this internal property of the strategy + network_service: &NetworkServiceHandle, + ) -> Result>, ClientError>; } /// The key identifying a specific strategy for responses routing. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum StrategyKey { - /// Warp sync initiated this request. - Warp, - /// State sync initiated this request. - State, - /// `ChainSync` initiated this request. - ChainSync, +pub struct StrategyKey(&'static str); + +impl StrategyKey { + /// Instantiate opaque strategy key. + pub const fn new(key: &'static str) -> Self { + Self(key) + } } -#[derive(Debug)] pub enum SyncingAction { - /// Send block request to peer. Always implies dropping a stale block request to the same peer. - SendBlockRequest { peer_id: PeerId, key: StrategyKey, request: BlockRequest }, - /// Send state request to peer. - SendStateRequest { - peer_id: PeerId, - key: StrategyKey, - protocol_name: ProtocolName, - request: OpaqueStateRequest, - }, - /// Send warp proof request to peer. - SendWarpProofRequest { + /// Start request to peer. + StartRequest { peer_id: PeerId, key: StrategyKey, - protocol_name: ProtocolName, - request: WarpProofRequest, + request: ResponseFuture, + // Whether to remove obsolete pending responses. + remove_obsolete: bool, }, /// Drop stale request. CancelRequest { peer_id: PeerId, key: StrategyKey }, @@ -225,444 +177,20 @@ pub enum SyncingAction { } impl SyncingAction { - fn is_finished(&self) -> bool { + /// Returns `true` if the syncing action has completed. + pub fn is_finished(&self) -> bool { matches!(self, SyncingAction::Finished) } -} - -impl From> for SyncingAction { - fn from(action: WarpSyncAction) -> Self { - match action { - WarpSyncAction::SendWarpProofRequest { peer_id, protocol_name, request } => - SyncingAction::SendWarpProofRequest { - peer_id, - key: StrategyKey::Warp, - protocol_name, - request, - }, - WarpSyncAction::SendBlockRequest { peer_id, request } => - SyncingAction::SendBlockRequest { peer_id, key: StrategyKey::Warp, request }, - WarpSyncAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), - WarpSyncAction::Finished => SyncingAction::Finished, - } - } -} - -impl From> for SyncingAction { - fn from(action: StateStrategyAction) -> Self { - match action { - StateStrategyAction::SendStateRequest { peer_id, protocol_name, request } => - SyncingAction::SendStateRequest { - peer_id, - key: StrategyKey::State, - protocol_name, - request, - }, - StateStrategyAction::DropPeer(bad_peer) => SyncingAction::DropPeer(bad_peer), - StateStrategyAction::ImportBlocks { origin, blocks } => - SyncingAction::ImportBlocks { origin, blocks }, - StateStrategyAction::Finished => SyncingAction::Finished, - } - } -} - -/// Proxy to specific syncing strategies used in Polkadot. -pub struct PolkadotSyncingStrategy { - /// Initial syncing configuration. - config: SyncingConfig, - /// Client used by syncing strategies. - client: Arc, - /// Warp strategy. - warp: Option>, - /// State strategy. - state: Option>, - /// `ChainSync` strategy.` - chain_sync: Option>, - /// Connected peers and their best blocks used to seed a new strategy when switching to it in - /// `PolkadotSyncingStrategy::proceed_to_next`. - peer_best_blocks: HashMap)>, -} - -impl SyncingStrategy for PolkadotSyncingStrategy -where - B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, -{ - fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { - self.peer_best_blocks.insert(peer_id, (best_hash, best_number)); - - self.warp.as_mut().map(|s| s.add_peer(peer_id, best_hash, best_number)); - self.state.as_mut().map(|s| s.add_peer(peer_id, best_hash, best_number)); - self.chain_sync.as_mut().map(|s| s.add_peer(peer_id, best_hash, best_number)); - } - - fn remove_peer(&mut self, peer_id: &PeerId) { - self.warp.as_mut().map(|s| s.remove_peer(peer_id)); - self.state.as_mut().map(|s| s.remove_peer(peer_id)); - self.chain_sync.as_mut().map(|s| s.remove_peer(peer_id)); - - self.peer_best_blocks.remove(peer_id); - } - - fn on_validated_block_announce( - &mut self, - is_best: bool, - peer_id: PeerId, - announce: &BlockAnnounce, - ) -> Option<(B::Hash, NumberFor)> { - let new_best = if let Some(ref mut warp) = self.warp { - warp.on_validated_block_announce(is_best, peer_id, announce) - } else if let Some(ref mut state) = self.state { - state.on_validated_block_announce(is_best, peer_id, announce) - } else if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.on_validated_block_announce(is_best, peer_id, announce) - } else { - error!(target: LOG_TARGET, "No syncing strategy is active."); - debug_assert!(false); - Some((announce.header.hash(), *announce.header.number())) - }; - - if let Some(new_best) = new_best { - if let Some(best) = self.peer_best_blocks.get_mut(&peer_id) { - *best = new_best; - } else { - debug!( - target: LOG_TARGET, - "Cannot update `peer_best_blocks` as peer {peer_id} is not known to `Strategy` \ - (already disconnected?)", - ); - } - } - - new_best - } - - fn set_sync_fork_request(&mut self, peers: Vec, hash: &B::Hash, number: NumberFor) { - // Fork requests are only handled by `ChainSync`. - if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.set_sync_fork_request(peers.clone(), hash, number); - } - } - - fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { - // Justifications can only be requested via `ChainSync`. - if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.request_justification(hash, number); - } - } - - fn clear_justification_requests(&mut self) { - // Justification requests can only be cleared by `ChainSync`. - if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.clear_justification_requests(); - } - } - - fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { - // Only `ChainSync` is interested in justification import. - if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.on_justification_import(hash, number, success); - } - } - - fn on_block_response( - &mut self, - peer_id: PeerId, - key: StrategyKey, - request: BlockRequest, - blocks: Vec>, - ) { - if let (StrategyKey::Warp, Some(ref mut warp)) = (key, &mut self.warp) { - warp.on_block_response(peer_id, request, blocks); - } else if let (StrategyKey::ChainSync, Some(ref mut chain_sync)) = - (key, &mut self.chain_sync) - { - chain_sync.on_block_response(peer_id, key, request, blocks); - } else { - error!( - target: LOG_TARGET, - "`on_block_response()` called with unexpected key {key:?} \ - or corresponding strategy is not active.", - ); - debug_assert!(false); - } - } - - fn on_state_response( - &mut self, - peer_id: PeerId, - key: StrategyKey, - response: OpaqueStateResponse, - ) { - if let (StrategyKey::State, Some(ref mut state)) = (key, &mut self.state) { - state.on_state_response(peer_id, response); - } else if let (StrategyKey::ChainSync, Some(ref mut chain_sync)) = - (key, &mut self.chain_sync) - { - chain_sync.on_state_response(peer_id, key, response); - } else { - error!( - target: LOG_TARGET, - "`on_state_response()` called with unexpected key {key:?} \ - or corresponding strategy is not active.", - ); - debug_assert!(false); - } - } - - fn on_warp_proof_response( - &mut self, - peer_id: &PeerId, - key: StrategyKey, - response: EncodedProof, - ) { - if let (StrategyKey::Warp, Some(ref mut warp)) = (key, &mut self.warp) { - warp.on_warp_proof_response(peer_id, response); - } else { - error!( - target: LOG_TARGET, - "`on_warp_proof_response()` called with unexpected key {key:?} \ - or warp strategy is not active", - ); - debug_assert!(false); - } - } - - fn on_blocks_processed( - &mut self, - imported: usize, - count: usize, - results: Vec<(Result>, BlockImportError>, B::Hash)>, - ) { - // Only `StateStrategy` and `ChainSync` are interested in block processing notifications. - if let Some(ref mut state) = self.state { - state.on_blocks_processed(imported, count, results); - } else if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.on_blocks_processed(imported, count, results); - } - } - - fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { - // Only `ChainSync` is interested in block finalization notifications. - if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.on_block_finalized(hash, number); - } - } - - fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { - // This is relevant to `ChainSync` only. - if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.update_chain_info(best_hash, best_number); - } - } - - fn is_major_syncing(&self) -> bool { - self.warp.is_some() || - self.state.is_some() || - match self.chain_sync { - Some(ref s) => s.status().state.is_major_syncing(), - None => unreachable!("At least one syncing strategy is active; qed"), - } - } - - fn num_peers(&self) -> usize { - self.peer_best_blocks.len() - } - - fn status(&self) -> SyncStatus { - // This function presumes that strategies are executed serially and must be refactored - // once we have parallel strategies. - if let Some(ref warp) = self.warp { - warp.status() - } else if let Some(ref state) = self.state { - state.status() - } else if let Some(ref chain_sync) = self.chain_sync { - chain_sync.status() - } else { - unreachable!("At least one syncing strategy is always active; qed") - } - } - - fn num_downloaded_blocks(&self) -> usize { - self.chain_sync - .as_ref() - .map_or(0, |chain_sync| chain_sync.num_downloaded_blocks()) - } - - fn num_sync_requests(&self) -> usize { - self.chain_sync.as_ref().map_or(0, |chain_sync| chain_sync.num_sync_requests()) - } - - fn actions(&mut self) -> Result>, ClientError> { - // This function presumes that strategies are executed serially and must be refactored once - // we have parallel strategies. - let actions: Vec<_> = if let Some(ref mut warp) = self.warp { - warp.actions().map(Into::into).collect() - } else if let Some(ref mut state) = self.state { - state.actions().map(Into::into).collect() - } else if let Some(ref mut chain_sync) = self.chain_sync { - chain_sync.actions()? - } else { - unreachable!("At least one syncing strategy is always active; qed") - }; - - if actions.iter().any(SyncingAction::is_finished) { - self.proceed_to_next()?; - } - - Ok(actions) - } -} - -impl PolkadotSyncingStrategy -where - B: BlockT, - Client: HeaderBackend - + BlockBackend - + HeaderMetadata - + ProofProvider - + Send - + Sync - + 'static, -{ - /// Initialize a new syncing strategy. - pub fn new( - mut config: SyncingConfig, - client: Arc, - warp_sync_config: Option>, - warp_sync_protocol_name: Option, - ) -> Result { - if config.max_blocks_per_request > MAX_BLOCKS_IN_RESPONSE as u32 { - info!( - target: LOG_TARGET, - "clamping maximum blocks per request to {MAX_BLOCKS_IN_RESPONSE}", - ); - config.max_blocks_per_request = MAX_BLOCKS_IN_RESPONSE as u32; - } - - if let SyncMode::Warp = config.mode { - let warp_sync_config = warp_sync_config - .expect("Warp sync configuration must be supplied in warp sync mode."); - let warp_sync = - WarpSync::new(client.clone(), warp_sync_config, warp_sync_protocol_name); - Ok(Self { - config, - client, - warp: Some(warp_sync), - state: None, - chain_sync: None, - peer_best_blocks: Default::default(), - }) - } else { - let chain_sync = ChainSync::new( - chain_sync_mode(config.mode), - client.clone(), - config.max_parallel_downloads, - config.max_blocks_per_request, - config.state_request_protocol_name.clone(), - config.metrics_registry.as_ref(), - std::iter::empty(), - )?; - Ok(Self { - config, - client, - warp: None, - state: None, - chain_sync: Some(chain_sync), - peer_best_blocks: Default::default(), - }) - } - } - - /// Proceed with the next strategy if the active one finished. - pub fn proceed_to_next(&mut self) -> Result<(), ClientError> { - // The strategies are switched as `WarpSync` -> `StateStrategy` -> `ChainSync`. - if let Some(ref mut warp) = self.warp { - match warp.take_result() { - Some(res) => { - info!( - target: LOG_TARGET, - "Warp sync is complete, continuing with state sync." - ); - let state_sync = StateStrategy::new( - self.client.clone(), - res.target_header, - res.target_body, - res.target_justifications, - false, - self.peer_best_blocks - .iter() - .map(|(peer_id, (_, best_number))| (*peer_id, *best_number)), - self.config.state_request_protocol_name.clone(), - ); - - self.warp = None; - self.state = Some(state_sync); - Ok(()) - }, - None => { - error!( - target: LOG_TARGET, - "Warp sync failed. Continuing with full sync." - ); - let chain_sync = match ChainSync::new( - chain_sync_mode(self.config.mode), - self.client.clone(), - self.config.max_parallel_downloads, - self.config.max_blocks_per_request, - self.config.state_request_protocol_name.clone(), - self.config.metrics_registry.as_ref(), - self.peer_best_blocks.iter().map(|(peer_id, (best_hash, best_number))| { - (*peer_id, *best_hash, *best_number) - }), - ) { - Ok(chain_sync) => chain_sync, - Err(e) => { - error!(target: LOG_TARGET, "Failed to start `ChainSync`."); - return Err(e) - }, - }; - - self.warp = None; - self.chain_sync = Some(chain_sync); - Ok(()) - }, - } - } else if let Some(state) = &self.state { - if state.is_succeeded() { - info!(target: LOG_TARGET, "State sync is complete, continuing with block sync."); - } else { - error!(target: LOG_TARGET, "State sync failed. Falling back to full sync."); - } - let chain_sync = match ChainSync::new( - chain_sync_mode(self.config.mode), - self.client.clone(), - self.config.max_parallel_downloads, - self.config.max_blocks_per_request, - self.config.state_request_protocol_name.clone(), - self.config.metrics_registry.as_ref(), - self.peer_best_blocks.iter().map(|(peer_id, (best_hash, best_number))| { - (*peer_id, *best_hash, *best_number) - }), - ) { - Ok(chain_sync) => chain_sync, - Err(e) => { - error!(target: LOG_TARGET, "Failed to start `ChainSync`."); - return Err(e); - }, - }; - self.state = None; - self.chain_sync = Some(chain_sync); - Ok(()) - } else { - unreachable!("Only warp & state strategies can finish; qed") + #[cfg(test)] + pub(crate) fn name(&self) -> &'static str { + match self { + Self::StartRequest { .. } => "StartRequest", + Self::CancelRequest { .. } => "CancelRequest", + Self::DropPeer(_) => "DropPeer", + Self::ImportBlocks { .. } => "ImportBlocks", + Self::ImportJustifications { .. } => "ImportJustifications", + Self::Finished => "Finished", } } } diff --git a/substrate/client/network/sync/src/strategy/chain_sync.rs b/substrate/client/network/sync/src/strategy/chain_sync.rs index 202033e8e00a..18170b77881e 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync.rs @@ -29,24 +29,28 @@ //! order to update it. use crate::{ + block_relay_protocol::{BlockDownloader, BlockResponseError}, blocks::BlockCollection, justification_requests::ExtraRequests, - schema::v1::StateResponse, + schema::v1::{StateRequest, StateResponse}, + service::network::NetworkServiceHandle, strategy::{ disconnected_peers::DisconnectedPeers, state_sync::{ImportResult, StateSync, StateSyncProvider}, - warp::{EncodedProof, WarpSyncPhase, WarpSyncProgress}, + warp::{WarpSyncPhase, WarpSyncProgress}, StrategyKey, SyncingAction, SyncingStrategy, }, - types::{BadPeer, OpaqueStateRequest, OpaqueStateResponse, SyncState, SyncStatus}, + types::{BadPeer, SyncState, SyncStatus}, LOG_TARGET, }; +use futures::{channel::oneshot, FutureExt}; use log::{debug, error, info, trace, warn}; use prometheus_endpoint::{register, Gauge, PrometheusError, Registry, U64}; +use prost::Message; use sc_client_api::{blockchain::BlockGap, BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; -use sc_network::ProtocolName; +use sc_network::{IfDisconnected, ProtocolName}; use sc_network_common::sync::message::{ BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock, }; @@ -62,6 +66,7 @@ use sp_runtime::{ }; use std::{ + any::Any, collections::{HashMap, HashSet}, ops::Range, sync::Arc, @@ -123,6 +128,9 @@ mod rep { /// Peer response data does not have requested bits. pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response"); + + /// We received a message that failed to decode. + pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); } struct Metrics { @@ -324,9 +332,11 @@ pub struct ChainSync { downloaded_blocks: usize, /// State sync in progress, if any. state_sync: Option>, - /// Enable importing existing blocks. This is used used after the state download to + /// Enable importing existing blocks. This is used after the state download to /// catch up to the latest state while re-importing blocks. import_existing: bool, + /// Block downloader + block_downloader: Arc>, /// Gap download process. gap_sync: Option>, /// Pending actions. @@ -348,11 +358,10 @@ where { fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { match self.add_peer_inner(peer_id, best_hash, best_number) { - Ok(Some(request)) => self.actions.push(SyncingAction::SendBlockRequest { - peer_id, - key: StrategyKey::ChainSync, - request, - }), + Ok(Some(request)) => { + let action = self.create_block_request_action(peer_id, request); + self.actions.push(action); + }, Ok(None) => {}, Err(bad_peer) => self.actions.push(SyncingAction::DropPeer(bad_peer)), } @@ -564,82 +573,77 @@ where self.allowed_requests.set_all(); } - fn on_block_response( + fn on_generic_response( &mut self, - peer_id: PeerId, + peer_id: &PeerId, key: StrategyKey, - request: BlockRequest, - blocks: Vec>, + protocol_name: ProtocolName, + response: Box, ) { - if key != StrategyKey::ChainSync { - error!( + if Self::STRATEGY_KEY != key { + warn!( target: LOG_TARGET, - "`on_block_response()` called with unexpected key {key:?} for chain sync", + "Unexpected generic response strategy key {key:?}, protocol {protocol_name}", ); debug_assert!(false); + return; } - let block_response = BlockResponse:: { id: request.id, blocks }; - let blocks_range = || match ( - block_response - .blocks - .first() - .and_then(|b| b.header.as_ref().map(|h| h.number())), - block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), - ) { - (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), - (Some(first), Some(_)) => format!(" ({})", first), - _ => Default::default(), - }; - trace!( - target: LOG_TARGET, - "BlockResponse {} from {} with {} blocks {}", - block_response.id, - peer_id, - block_response.blocks.len(), - blocks_range(), - ); + if protocol_name == self.state_request_protocol_name { + let Ok(response) = response.downcast::>() else { + warn!(target: LOG_TARGET, "Failed to downcast state response"); + debug_assert!(false); + return; + }; - let res = if request.fields == BlockAttributes::JUSTIFICATION { - self.on_block_justification(peer_id, block_response) - } else { - self.on_block_data(&peer_id, Some(request), block_response) - }; + if let Err(bad_peer) = self.on_state_data(&peer_id, &response) { + self.actions.push(SyncingAction::DropPeer(bad_peer)); + } + } else if &protocol_name == self.block_downloader.protocol_name() { + let Ok(response) = response + .downcast::<(BlockRequest, Result>, BlockResponseError>)>() + else { + warn!(target: LOG_TARGET, "Failed to downcast block response"); + debug_assert!(false); + return; + }; - if let Err(bad_peer) = res { - self.actions.push(SyncingAction::DropPeer(bad_peer)); - } - } + let (request, response) = *response; + let blocks = match response { + Ok(blocks) => blocks, + Err(BlockResponseError::DecodeFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to decode block response from peer {:?}: {:?}.", + peer_id, + e + ); + self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE))); + return; + }, + Err(BlockResponseError::ExtractionFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to extract blocks from peer response {:?}: {:?}.", + peer_id, + e + ); + self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE))); + return; + }, + }; - fn on_state_response( - &mut self, - peer_id: PeerId, - key: StrategyKey, - response: OpaqueStateResponse, - ) { - if key != StrategyKey::ChainSync { - error!( + if let Err(bad_peer) = self.on_block_response(peer_id, key, request, blocks) { + self.actions.push(SyncingAction::DropPeer(bad_peer)); + } + } else { + warn!( target: LOG_TARGET, - "`on_state_response()` called with unexpected key {key:?} for chain sync", + "Unexpected generic response protocol {protocol_name}, strategy key \ + {key:?}", ); debug_assert!(false); } - if let Err(bad_peer) = self.on_state_data(&peer_id, response) { - self.actions.push(SyncingAction::DropPeer(bad_peer)); - } - } - - fn on_warp_proof_response( - &mut self, - _peer_id: &PeerId, - _key: StrategyKey, - _response: EncodedProof, - ) { - error!( - target: LOG_TARGET, - "`on_warp_proof_response()` called for chain sync strategy", - ); - debug_assert!(false); } fn on_blocks_processed( @@ -863,30 +867,56 @@ where .count() } - fn actions(&mut self) -> Result>, ClientError> { + fn actions( + &mut self, + network_service: &NetworkServiceHandle, + ) -> Result>, ClientError> { if !self.peers.is_empty() && self.queue_blocks.is_empty() { if let Some((hash, number, skip_proofs)) = self.pending_state_sync_attempt.take() { self.attempt_state_sync(hash, number, skip_proofs); } } - let block_requests = self.block_requests().into_iter().map(|(peer_id, request)| { - SyncingAction::SendBlockRequest { peer_id, key: StrategyKey::ChainSync, request } - }); + let block_requests = self + .block_requests() + .into_iter() + .map(|(peer_id, request)| self.create_block_request_action(peer_id, request)) + .collect::>(); self.actions.extend(block_requests); - let justification_requests = - self.justification_requests().into_iter().map(|(peer_id, request)| { - SyncingAction::SendBlockRequest { peer_id, key: StrategyKey::ChainSync, request } - }); + let justification_requests = self + .justification_requests() + .into_iter() + .map(|(peer_id, request)| self.create_block_request_action(peer_id, request)) + .collect::>(); self.actions.extend(justification_requests); let state_request = self.state_request().into_iter().map(|(peer_id, request)| { - SyncingAction::SendStateRequest { + trace!( + target: LOG_TARGET, + "Created `StrategyRequest` to {peer_id}.", + ); + + let (tx, rx) = oneshot::channel(); + + network_service.start_request( peer_id, - key: StrategyKey::ChainSync, - protocol_name: self.state_request_protocol_name.clone(), - request, + self.state_request_protocol_name.clone(), + request.encode_to_vec(), + tx, + IfDisconnected::ImmediateError, + ); + + SyncingAction::StartRequest { + peer_id, + key: Self::STRATEGY_KEY, + request: async move { + Ok(rx.await?.and_then(|(response, protocol_name)| { + Ok((Box::new(response) as Box, protocol_name)) + })) + } + .boxed(), + remove_obsolete: false, } }); self.actions.extend(state_request); @@ -906,6 +936,9 @@ where + Sync + 'static, { + /// Strategy key used by chain sync. + pub const STRATEGY_KEY: StrategyKey = StrategyKey::new("ChainSync"); + /// Create a new instance. pub fn new( mode: ChainSyncMode, @@ -913,6 +946,7 @@ where max_parallel_downloads: u32, max_blocks_per_request: u32, state_request_protocol_name: ProtocolName, + block_downloader: Arc>, metrics_registry: Option<&Registry>, initial_peers: impl Iterator)>, ) -> Result { @@ -935,6 +969,7 @@ where downloaded_blocks: 0, state_sync: None, import_existing: false, + block_downloader, gap_sync: None, actions: Vec::new(), metrics: metrics_registry.and_then(|r| match Metrics::register(r) { @@ -1075,6 +1110,33 @@ where } } + fn create_block_request_action( + &mut self, + peer_id: PeerId, + request: BlockRequest, + ) -> SyncingAction { + let downloader = self.block_downloader.clone(); + + SyncingAction::StartRequest { + peer_id, + key: Self::STRATEGY_KEY, + request: async move { + Ok(downloader.download_blocks(peer_id, request.clone()).await?.and_then( + |(response, protocol_name)| { + let decoded_response = + downloader.block_response_into_blocks(&request, response); + let result = Box::new((request, decoded_response)) as Box; + Ok((result, protocol_name)) + }, + )) + } + .boxed(), + // Sending block request implies dropping obsolete pending response as we are not + // interested in it anymore. + remove_obsolete: true, + } + } + /// Submit a block response for processing. #[must_use] fn on_block_data( @@ -1248,11 +1310,8 @@ where state: next_state, }; let request = ancestry_request::(next_num); - self.actions.push(SyncingAction::SendBlockRequest { - peer_id: *peer_id, - key: StrategyKey::ChainSync, - request, - }); + let action = self.create_block_request_action(*peer_id, request); + self.actions.push(action); return Ok(()); } else { // Ancestry search is complete. Check if peer is on a stale fork unknown @@ -1334,6 +1393,49 @@ where Ok(()) } + fn on_block_response( + &mut self, + peer_id: &PeerId, + key: StrategyKey, + request: BlockRequest, + blocks: Vec>, + ) -> Result<(), BadPeer> { + if key != Self::STRATEGY_KEY { + error!( + target: LOG_TARGET, + "`on_block_response()` called with unexpected key {key:?} for chain sync", + ); + debug_assert!(false); + } + let block_response = BlockResponse:: { id: request.id, blocks }; + + let blocks_range = || match ( + block_response + .blocks + .first() + .and_then(|b| b.header.as_ref().map(|h| h.number())), + block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())), + ) { + (Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last), + (Some(first), Some(_)) => format!(" ({})", first), + _ => Default::default(), + }; + trace!( + target: LOG_TARGET, + "BlockResponse {} from {} with {} blocks {}", + block_response.id, + peer_id, + block_response.blocks.len(), + blocks_range(), + ); + + if request.fields == BlockAttributes::JUSTIFICATION { + self.on_block_justification(*peer_id, block_response) + } else { + self.on_block_data(peer_id, Some(request), block_response) + } + } + /// Submit a justification response for processing. #[must_use] fn on_block_justification( @@ -1548,10 +1650,8 @@ where PeerSyncState::DownloadingGap(_) | PeerSyncState::DownloadingState => { // Cancel a request first, as `add_peer` may generate a new request. - self.actions.push(SyncingAction::CancelRequest { - peer_id, - key: StrategyKey::ChainSync, - }); + self.actions + .push(SyncingAction::CancelRequest { peer_id, key: Self::STRATEGY_KEY }); self.add_peer(peer_id, peer_sync.best_hash, peer_sync.best_number); }, PeerSyncState::DownloadingJustification(_) => { @@ -1831,7 +1931,7 @@ where } /// Get a state request scheduled by sync to be sent out (if any). - fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { + fn state_request(&mut self) -> Option<(PeerId, StateRequest)> { if self.allowed_requests.is_empty() { return None; } @@ -1855,7 +1955,7 @@ where let request = sync.next_request(); trace!(target: LOG_TARGET, "New StateRequest for {}: {:?}", id, request); self.allowed_requests.clear(); - return Some((*id, OpaqueStateRequest(Box::new(request)))); + return Some((*id, request)); } } } @@ -1863,19 +1963,18 @@ where } #[must_use] - fn on_state_data( - &mut self, - peer_id: &PeerId, - response: OpaqueStateResponse, - ) -> Result<(), BadPeer> { - let response: Box = response.0.downcast().map_err(|_error| { - error!( - target: LOG_TARGET, - "Failed to downcast opaque state response, this is an implementation bug." - ); + fn on_state_data(&mut self, peer_id: &PeerId, response: &[u8]) -> Result<(), BadPeer> { + let response = match StateResponse::decode(response) { + Ok(response) => response, + Err(error) => { + debug!( + target: LOG_TARGET, + "Failed to decode state response from peer {peer_id:?}: {error:?}.", + ); - BadPeer(*peer_id, rep::BAD_RESPONSE) - })?; + return Err(BadPeer(*peer_id, rep::BAD_RESPONSE)); + }, + }; if let Some(peer) = self.peers.get_mut(peer_id) { if let PeerSyncState::DownloadingState = peer.state { @@ -1891,7 +1990,7 @@ where response.entries.len(), response.proof.len(), ); - sync.import(*response) + sync.import(response) } else { debug!(target: LOG_TARGET, "Ignored obsolete state response from {peer_id}"); return Err(BadPeer(*peer_id, rep::NOT_REQUESTED)); diff --git a/substrate/client/network/sync/src/strategy/chain_sync/test.rs b/substrate/client/network/sync/src/strategy/chain_sync/test.rs index d13f034e2e8d..4a5682722389 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync/test.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync/test.rs @@ -19,16 +19,64 @@ //! Tests of [`ChainSync`]. use super::*; -use futures::executor::block_on; +use crate::{ + block_relay_protocol::BlockResponseError, mock::MockBlockDownloader, + service::network::NetworkServiceProvider, +}; +use futures::{channel::oneshot::Canceled, executor::block_on}; use sc_block_builder::BlockBuilderBuilder; +use sc_network::RequestFailure; use sc_network_common::sync::message::{BlockAnnounce, BlockData, BlockState, FromBlock}; use sp_blockchain::HeaderBackend; +use std::sync::Mutex; use substrate_test_runtime_client::{ runtime::{Block, Hash, Header}, BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClient, TestClientBuilder, TestClientBuilderExt, }; +#[derive(Debug)] +struct ProxyBlockDownloader { + protocol_name: ProtocolName, + sender: std::sync::mpsc::Sender>, + request: Mutex>>, +} + +#[async_trait::async_trait] +impl BlockDownloader for ProxyBlockDownloader { + fn protocol_name(&self) -> &ProtocolName { + &self.protocol_name + } + + async fn download_blocks( + &self, + _who: PeerId, + request: BlockRequest, + ) -> Result, ProtocolName), RequestFailure>, Canceled> { + self.sender.send(request).unwrap(); + Ok(Ok((Vec::new(), self.protocol_name.clone()))) + } + + fn block_response_into_blocks( + &self, + _request: &BlockRequest, + _response: Vec, + ) -> Result>, BlockResponseError> { + Ok(Vec::new()) + } +} + +impl ProxyBlockDownloader { + fn new(protocol_name: ProtocolName) -> Self { + let (sender, receiver) = std::sync::mpsc::channel(); + Self { protocol_name, sender, request: Mutex::new(receiver) } + } + + fn next_request(&self) -> BlockRequest { + self.request.lock().unwrap().recv().unwrap() + } +} + #[test] fn processes_empty_response_on_justification_request_for_unknown_block() { // if we ask for a justification for a given block to a peer that doesn't know that block @@ -44,6 +92,7 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { 1, 64, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) @@ -108,6 +157,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { 1, 8, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) @@ -140,13 +190,15 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { sync.add_peer(peer_id1, Hash::random(), 42); sync.add_peer(peer_id2, Hash::random(), 10); + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); + // we wil send block requests to these peers // for these blocks we don't know about - let actions = sync.actions().unwrap(); + let actions = sync.actions(&network_handle).unwrap(); assert_eq!(actions.len(), 2); assert!(actions.iter().all(|action| match action { - SyncingAction::SendBlockRequest { peer_id, .. } => - peer_id == &peer_id1 || peer_id == &peer_id2, + SyncingAction::StartRequest { peer_id, .. } => peer_id == &peer_id1 || peer_id == &peer_id2, _ => false, })); @@ -176,7 +228,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { sync.restart(); // which should make us cancel and send out again block requests to the first two peers - let actions = sync.actions().unwrap(); + let actions = sync.actions(&network_handle).unwrap(); assert_eq!(actions.len(), 4); let mut cancelled_first = HashSet::new(); assert!(actions.iter().all(|action| match action { @@ -184,7 +236,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { cancelled_first.insert(peer_id); peer_id == &peer_id1 || peer_id == &peer_id2 }, - SyncingAction::SendBlockRequest { peer_id, .. } => { + SyncingAction::StartRequest { peer_id, .. } => { assert!(cancelled_first.remove(peer_id)); peer_id == &peer_id1 || peer_id == &peer_id2 }, @@ -311,6 +363,7 @@ fn do_ancestor_search_when_common_block_to_best_queued_gap_is_to_big() { 5, 64, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) @@ -459,12 +512,16 @@ fn can_sync_huge_fork() { let info = client.info(); + let protocol_name = ProtocolName::Static(""); + let proxy_block_downloader = Arc::new(ProxyBlockDownloader::new(protocol_name.clone())); + let mut sync = ChainSync::new( ChainSyncMode::Full, client.clone(), 5, 64, - ProtocolName::Static(""), + protocol_name, + proxy_block_downloader.clone(), None, std::iter::empty(), ) @@ -494,18 +551,21 @@ fn can_sync_huge_fork() { let block = &fork_blocks[unwrap_from_block_number(request.from.clone()) as usize - 1]; let response = create_block_response(vec![block.clone()]); - sync.on_block_data(&peer_id1, Some(request), response).unwrap(); + sync.on_block_data(&peer_id1, Some(request.clone()), response).unwrap(); - let actions = sync.take_actions().collect::>(); + let mut actions = sync.take_actions().collect::>(); request = if actions.is_empty() { // We found the ancestor break } else { assert_eq!(actions.len(), 1); - match &actions[0] { - SyncingAction::SendBlockRequest { peer_id: _, request, key: _ } => request.clone(), - action @ _ => panic!("Unexpected action: {action:?}"), + match actions.pop().unwrap() { + SyncingAction::StartRequest { request, .. } => { + block_on(request).unwrap().unwrap(); + proxy_block_downloader.next_request() + }, + action => panic!("Unexpected action: {}", action.name()), } }; @@ -600,12 +660,16 @@ fn syncs_fork_without_duplicate_requests() { let info = client.info(); + let protocol_name = ProtocolName::Static(""); + let proxy_block_downloader = Arc::new(ProxyBlockDownloader::new(protocol_name.clone())); + let mut sync = ChainSync::new( ChainSyncMode::Full, client.clone(), 5, 64, - ProtocolName::Static(""), + protocol_name, + proxy_block_downloader.clone(), None, std::iter::empty(), ) @@ -637,16 +701,19 @@ fn syncs_fork_without_duplicate_requests() { sync.on_block_data(&peer_id1, Some(request), response).unwrap(); - let actions = sync.take_actions().collect::>(); + let mut actions = sync.take_actions().collect::>(); request = if actions.is_empty() { // We found the ancestor break } else { assert_eq!(actions.len(), 1); - match &actions[0] { - SyncingAction::SendBlockRequest { peer_id: _, request, key: _ } => request.clone(), - action @ _ => panic!("Unexpected action: {action:?}"), + match actions.pop().unwrap() { + SyncingAction::StartRequest { request, .. } => { + block_on(request).unwrap().unwrap(); + proxy_block_downloader.next_request() + }, + action => panic!("Unexpected action: {}", action.name()), } }; @@ -750,6 +817,7 @@ fn removes_target_fork_on_disconnect() { 1, 64, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) @@ -784,6 +852,7 @@ fn can_import_response_with_missing_blocks() { 1, 64, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) @@ -824,6 +893,7 @@ fn sync_restart_removes_block_but_not_justification_requests() { 1, 64, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) @@ -898,17 +968,17 @@ fn sync_restart_removes_block_but_not_justification_requests() { SyncingAction::CancelRequest { peer_id, key: _ } => { pending_responses.remove(&peer_id); }, - SyncingAction::SendBlockRequest { peer_id, .. } => { + SyncingAction::StartRequest { peer_id, .. } => { // we drop obsolete response, but don't register a new request, it's checked in // the `assert!` below pending_responses.remove(&peer_id); }, - action @ _ => panic!("Unexpected action: {action:?}"), + action @ _ => panic!("Unexpected action: {}", action.name()), } } assert!(actions.iter().any(|action| { match action { - SyncingAction::SendBlockRequest { peer_id, .. } => peer_id == &peers[0], + SyncingAction::StartRequest { peer_id, .. } => peer_id == &peers[0], _ => false, } })); @@ -975,6 +1045,7 @@ fn request_across_forks() { 5, 64, ProtocolName::Static(""), + Arc::new(MockBlockDownloader::new()), None, std::iter::empty(), ) diff --git a/substrate/client/network/sync/src/strategy/polkadot.rs b/substrate/client/network/sync/src/strategy/polkadot.rs new file mode 100644 index 000000000000..44b05966af06 --- /dev/null +++ b/substrate/client/network/sync/src/strategy/polkadot.rs @@ -0,0 +1,481 @@ +// 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 . + +//! [`PolkadotSyncingStrategy`] is a proxy between [`crate::engine::SyncingEngine`] +//! and specific syncing algorithms. + +use crate::{ + block_relay_protocol::BlockDownloader, + block_request_handler::MAX_BLOCKS_IN_RESPONSE, + service::network::NetworkServiceHandle, + strategy::{ + chain_sync::{ChainSync, ChainSyncMode}, + state::StateStrategy, + warp::{WarpSync, WarpSyncConfig}, + StrategyKey, SyncingAction, SyncingStrategy, + }, + types::SyncStatus, + LOG_TARGET, +}; +use log::{debug, error, info, warn}; +use prometheus_endpoint::Registry; +use sc_client_api::{BlockBackend, ProofProvider}; +use sc_consensus::{BlockImportError, BlockImportStatus}; +use sc_network::ProtocolName; +use sc_network_common::sync::{message::BlockAnnounce, SyncMode}; +use sc_network_types::PeerId; +use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; +use std::{any::Any, collections::HashMap, sync::Arc}; + +/// Corresponding `ChainSync` mode. +fn chain_sync_mode(sync_mode: SyncMode) -> ChainSyncMode { + match sync_mode { + SyncMode::Full => ChainSyncMode::Full, + SyncMode::LightState { skip_proofs, storage_chain_mode } => + ChainSyncMode::LightState { skip_proofs, storage_chain_mode }, + SyncMode::Warp => ChainSyncMode::Full, + } +} + +/// Syncing configuration containing data for [`PolkadotSyncingStrategy`]. +#[derive(Clone, Debug)] +pub struct PolkadotSyncingStrategyConfig +where + Block: BlockT, +{ + /// Syncing mode. + pub mode: SyncMode, + /// The number of parallel downloads to guard against slow peers. + pub max_parallel_downloads: u32, + /// Maximum number of blocks to request. + pub max_blocks_per_request: u32, + /// Prometheus metrics registry. + pub metrics_registry: Option, + /// Protocol name used to send out state requests + pub state_request_protocol_name: ProtocolName, + /// Block downloader + pub block_downloader: Arc>, +} + +/// Proxy to specific syncing strategies used in Polkadot. +pub struct PolkadotSyncingStrategy { + /// Initial syncing configuration. + config: PolkadotSyncingStrategyConfig, + /// Client used by syncing strategies. + client: Arc, + /// Warp strategy. + warp: Option>, + /// State strategy. + state: Option>, + /// `ChainSync` strategy.` + chain_sync: Option>, + /// Connected peers and their best blocks used to seed a new strategy when switching to it in + /// `PolkadotSyncingStrategy::proceed_to_next`. + peer_best_blocks: HashMap)>, +} + +impl SyncingStrategy for PolkadotSyncingStrategy +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ + fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { + self.peer_best_blocks.insert(peer_id, (best_hash, best_number)); + + self.warp.as_mut().map(|s| s.add_peer(peer_id, best_hash, best_number)); + self.state.as_mut().map(|s| s.add_peer(peer_id, best_hash, best_number)); + self.chain_sync.as_mut().map(|s| s.add_peer(peer_id, best_hash, best_number)); + } + + fn remove_peer(&mut self, peer_id: &PeerId) { + self.warp.as_mut().map(|s| s.remove_peer(peer_id)); + self.state.as_mut().map(|s| s.remove_peer(peer_id)); + self.chain_sync.as_mut().map(|s| s.remove_peer(peer_id)); + + self.peer_best_blocks.remove(peer_id); + } + + fn on_validated_block_announce( + &mut self, + is_best: bool, + peer_id: PeerId, + announce: &BlockAnnounce, + ) -> Option<(B::Hash, NumberFor)> { + let new_best = if let Some(ref mut warp) = self.warp { + warp.on_validated_block_announce(is_best, peer_id, announce) + } else if let Some(ref mut state) = self.state { + state.on_validated_block_announce(is_best, peer_id, announce) + } else if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.on_validated_block_announce(is_best, peer_id, announce) + } else { + error!(target: LOG_TARGET, "No syncing strategy is active."); + debug_assert!(false); + Some((announce.header.hash(), *announce.header.number())) + }; + + if let Some(new_best) = new_best { + if let Some(best) = self.peer_best_blocks.get_mut(&peer_id) { + *best = new_best; + } else { + debug!( + target: LOG_TARGET, + "Cannot update `peer_best_blocks` as peer {peer_id} is not known to `Strategy` \ + (already disconnected?)", + ); + } + } + + new_best + } + + fn set_sync_fork_request(&mut self, peers: Vec, hash: &B::Hash, number: NumberFor) { + // Fork requests are only handled by `ChainSync`. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.set_sync_fork_request(peers.clone(), hash, number); + } + } + + fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { + // Justifications can only be requested via `ChainSync`. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.request_justification(hash, number); + } + } + + fn clear_justification_requests(&mut self) { + // Justification requests can only be cleared by `ChainSync`. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.clear_justification_requests(); + } + } + + fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor, success: bool) { + // Only `ChainSync` is interested in justification import. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.on_justification_import(hash, number, success); + } + } + + fn on_generic_response( + &mut self, + peer_id: &PeerId, + key: StrategyKey, + protocol_name: ProtocolName, + response: Box, + ) { + match key { + StateStrategy::::STRATEGY_KEY => + if let Some(state) = &mut self.state { + let Ok(response) = response.downcast::>() else { + warn!(target: LOG_TARGET, "Failed to downcast state response"); + debug_assert!(false); + return; + }; + + state.on_state_response(peer_id, *response); + } else if let Some(chain_sync) = &mut self.chain_sync { + chain_sync.on_generic_response(peer_id, key, protocol_name, response); + } else { + error!( + target: LOG_TARGET, + "`on_generic_response()` called with unexpected key {key:?} \ + or corresponding strategy is not active.", + ); + debug_assert!(false); + }, + WarpSync::::STRATEGY_KEY => + if let Some(warp) = &mut self.warp { + warp.on_generic_response(peer_id, protocol_name, response); + } else { + error!( + target: LOG_TARGET, + "`on_generic_response()` called with unexpected key {key:?} \ + or warp strategy is not active", + ); + debug_assert!(false); + }, + ChainSync::::STRATEGY_KEY => + if let Some(chain_sync) = &mut self.chain_sync { + chain_sync.on_generic_response(peer_id, key, protocol_name, response); + } else { + error!( + target: LOG_TARGET, + "`on_generic_response()` called with unexpected key {key:?} \ + or corresponding strategy is not active.", + ); + debug_assert!(false); + }, + key => { + warn!( + target: LOG_TARGET, + "Unexpected generic response strategy key {key:?}, protocol {protocol_name}", + ); + debug_assert!(false); + }, + } + } + + fn on_blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, B::Hash)>, + ) { + // Only `StateStrategy` and `ChainSync` are interested in block processing notifications. + if let Some(ref mut state) = self.state { + state.on_blocks_processed(imported, count, results); + } else if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.on_blocks_processed(imported, count, results); + } + } + + fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor) { + // Only `ChainSync` is interested in block finalization notifications. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.on_block_finalized(hash, number); + } + } + + fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor) { + // This is relevant to `ChainSync` only. + if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.update_chain_info(best_hash, best_number); + } + } + + fn is_major_syncing(&self) -> bool { + self.warp.is_some() || + self.state.is_some() || + match self.chain_sync { + Some(ref s) => s.status().state.is_major_syncing(), + None => unreachable!("At least one syncing strategy is active; qed"), + } + } + + fn num_peers(&self) -> usize { + self.peer_best_blocks.len() + } + + fn status(&self) -> SyncStatus { + // This function presumes that strategies are executed serially and must be refactored + // once we have parallel strategies. + if let Some(ref warp) = self.warp { + warp.status() + } else if let Some(ref state) = self.state { + state.status() + } else if let Some(ref chain_sync) = self.chain_sync { + chain_sync.status() + } else { + unreachable!("At least one syncing strategy is always active; qed") + } + } + + fn num_downloaded_blocks(&self) -> usize { + self.chain_sync + .as_ref() + .map_or(0, |chain_sync| chain_sync.num_downloaded_blocks()) + } + + fn num_sync_requests(&self) -> usize { + self.chain_sync.as_ref().map_or(0, |chain_sync| chain_sync.num_sync_requests()) + } + + fn actions( + &mut self, + network_service: &NetworkServiceHandle, + ) -> Result>, ClientError> { + // This function presumes that strategies are executed serially and must be refactored once + // we have parallel strategies. + let actions: Vec<_> = if let Some(ref mut warp) = self.warp { + warp.actions(network_service).map(Into::into).collect() + } else if let Some(ref mut state) = self.state { + state.actions(network_service).map(Into::into).collect() + } else if let Some(ref mut chain_sync) = self.chain_sync { + chain_sync.actions(network_service)? + } else { + unreachable!("At least one syncing strategy is always active; qed") + }; + + if actions.iter().any(SyncingAction::is_finished) { + self.proceed_to_next()?; + } + + Ok(actions) + } +} + +impl PolkadotSyncingStrategy +where + B: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, +{ + /// Initialize a new syncing strategy. + pub fn new( + mut config: PolkadotSyncingStrategyConfig, + client: Arc, + warp_sync_config: Option>, + warp_sync_protocol_name: Option, + ) -> Result { + if config.max_blocks_per_request > MAX_BLOCKS_IN_RESPONSE as u32 { + info!( + target: LOG_TARGET, + "clamping maximum blocks per request to {MAX_BLOCKS_IN_RESPONSE}", + ); + config.max_blocks_per_request = MAX_BLOCKS_IN_RESPONSE as u32; + } + + if let SyncMode::Warp = config.mode { + let warp_sync_config = warp_sync_config + .expect("Warp sync configuration must be supplied in warp sync mode."); + let warp_sync = WarpSync::new( + client.clone(), + warp_sync_config, + warp_sync_protocol_name, + config.block_downloader.clone(), + ); + Ok(Self { + config, + client, + warp: Some(warp_sync), + state: None, + chain_sync: None, + peer_best_blocks: Default::default(), + }) + } else { + let chain_sync = ChainSync::new( + chain_sync_mode(config.mode), + client.clone(), + config.max_parallel_downloads, + config.max_blocks_per_request, + config.state_request_protocol_name.clone(), + config.block_downloader.clone(), + config.metrics_registry.as_ref(), + std::iter::empty(), + )?; + Ok(Self { + config, + client, + warp: None, + state: None, + chain_sync: Some(chain_sync), + peer_best_blocks: Default::default(), + }) + } + } + + /// Proceed with the next strategy if the active one finished. + pub fn proceed_to_next(&mut self) -> Result<(), ClientError> { + // The strategies are switched as `WarpSync` -> `StateStrategy` -> `ChainSync`. + if let Some(ref mut warp) = self.warp { + match warp.take_result() { + Some(res) => { + info!( + target: LOG_TARGET, + "Warp sync is complete, continuing with state sync." + ); + let state_sync = StateStrategy::new( + self.client.clone(), + res.target_header, + res.target_body, + res.target_justifications, + false, + self.peer_best_blocks + .iter() + .map(|(peer_id, (_, best_number))| (*peer_id, *best_number)), + self.config.state_request_protocol_name.clone(), + ); + + self.warp = None; + self.state = Some(state_sync); + Ok(()) + }, + None => { + error!( + target: LOG_TARGET, + "Warp sync failed. Continuing with full sync." + ); + let chain_sync = match ChainSync::new( + chain_sync_mode(self.config.mode), + self.client.clone(), + self.config.max_parallel_downloads, + self.config.max_blocks_per_request, + self.config.state_request_protocol_name.clone(), + self.config.block_downloader.clone(), + self.config.metrics_registry.as_ref(), + self.peer_best_blocks.iter().map(|(peer_id, (best_hash, best_number))| { + (*peer_id, *best_hash, *best_number) + }), + ) { + Ok(chain_sync) => chain_sync, + Err(e) => { + error!(target: LOG_TARGET, "Failed to start `ChainSync`."); + return Err(e) + }, + }; + + self.warp = None; + self.chain_sync = Some(chain_sync); + Ok(()) + }, + } + } else if let Some(state) = &self.state { + if state.is_succeeded() { + info!(target: LOG_TARGET, "State sync is complete, continuing with block sync."); + } else { + error!(target: LOG_TARGET, "State sync failed. Falling back to full sync."); + } + let chain_sync = match ChainSync::new( + chain_sync_mode(self.config.mode), + self.client.clone(), + self.config.max_parallel_downloads, + self.config.max_blocks_per_request, + self.config.state_request_protocol_name.clone(), + self.config.block_downloader.clone(), + self.config.metrics_registry.as_ref(), + self.peer_best_blocks.iter().map(|(peer_id, (best_hash, best_number))| { + (*peer_id, *best_hash, *best_number) + }), + ) { + Ok(chain_sync) => chain_sync, + Err(e) => { + error!(target: LOG_TARGET, "Failed to start `ChainSync`."); + return Err(e); + }, + }; + + self.state = None; + self.chain_sync = Some(chain_sync); + Ok(()) + } else { + unreachable!("Only warp & state strategies can finish; qed") + } + } +} diff --git a/substrate/client/network/sync/src/strategy/state.rs b/substrate/client/network/sync/src/strategy/state.rs index d69ab3e2d535..1abbb96ccd90 100644 --- a/substrate/client/network/sync/src/strategy/state.rs +++ b/substrate/client/network/sync/src/strategy/state.rs @@ -19,18 +19,22 @@ //! State sync strategy. use crate::{ - schema::v1::StateResponse, + schema::v1::{StateRequest, StateResponse}, + service::network::NetworkServiceHandle, strategy::{ disconnected_peers::DisconnectedPeers, state_sync::{ImportResult, StateSync, StateSyncProvider}, + StrategyKey, SyncingAction, }, - types::{BadPeer, OpaqueStateRequest, OpaqueStateResponse, SyncState, SyncStatus}, + types::{BadPeer, SyncState, SyncStatus}, LOG_TARGET, }; +use futures::{channel::oneshot, FutureExt}; use log::{debug, error, trace}; +use prost::Message; use sc_client_api::ProofProvider; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; -use sc_network::ProtocolName; +use sc_network::{IfDisconnected, ProtocolName}; use sc_network_common::sync::message::BlockAnnounce; use sc_network_types::PeerId; use sp_consensus::BlockOrigin; @@ -38,7 +42,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header, NumberFor}, Justifications, SaturatedConversion, }; -use std::{collections::HashMap, sync::Arc}; +use std::{any::Any, collections::HashMap, sync::Arc}; mod rep { use sc_network::ReputationChange as Rep; @@ -50,18 +54,6 @@ mod rep { pub const BAD_STATE: Rep = Rep::new(-(1 << 29), "Bad state"); } -/// Action that should be performed on [`StateStrategy`]'s behalf. -pub enum StateStrategyAction { - /// Send state request to peer. - SendStateRequest { peer_id: PeerId, protocol_name: ProtocolName, request: OpaqueStateRequest }, - /// Disconnect and report peer. - DropPeer(BadPeer), - /// Import blocks. - ImportBlocks { origin: BlockOrigin, blocks: Vec> }, - /// State sync has finished. - Finished, -} - enum PeerState { Available, DownloadingState, @@ -83,12 +75,15 @@ pub struct StateStrategy { state_sync: Box>, peers: HashMap>, disconnected_peers: DisconnectedPeers, - actions: Vec>, + actions: Vec>, protocol_name: ProtocolName, succeeded: bool, } impl StateStrategy { + /// Strategy key used by state sync. + pub const STRATEGY_KEY: StrategyKey = StrategyKey::new("State"); + /// Create a new instance. pub fn new( client: Arc, @@ -123,10 +118,11 @@ impl StateStrategy { } } - // Create a new instance with a custom state sync provider. - // Used in tests. - #[cfg(test)] - fn new_with_provider( + /// Create a new instance with a custom state sync provider. + /// + /// Note: In most cases, users should use [`StateStrategy::new`]. + /// This method is intended for custom sync strategies and advanced use cases. + pub fn new_with_provider( state_sync_provider: Box>, initial_peers: impl Iterator)>, protocol_name: ProtocolName, @@ -157,7 +153,7 @@ impl StateStrategy { if let Some(bad_peer) = self.disconnected_peers.on_disconnect_during_request(*peer_id) { - self.actions.push(StateStrategyAction::DropPeer(bad_peer)); + self.actions.push(SyncingAction::DropPeer(bad_peer)); } } } @@ -185,30 +181,32 @@ impl StateStrategy { } /// Process state response. - pub fn on_state_response(&mut self, peer_id: PeerId, response: OpaqueStateResponse) { - if let Err(bad_peer) = self.on_state_response_inner(peer_id, response) { - self.actions.push(StateStrategyAction::DropPeer(bad_peer)); + pub fn on_state_response(&mut self, peer_id: &PeerId, response: Vec) { + if let Err(bad_peer) = self.on_state_response_inner(peer_id, &response) { + self.actions.push(SyncingAction::DropPeer(bad_peer)); } } fn on_state_response_inner( &mut self, - peer_id: PeerId, - response: OpaqueStateResponse, + peer_id: &PeerId, + response: &[u8], ) -> Result<(), BadPeer> { if let Some(peer) = self.peers.get_mut(&peer_id) { peer.state = PeerState::Available; } - let response: Box = response.0.downcast().map_err(|_error| { - error!( - target: LOG_TARGET, - "Failed to downcast opaque state response, this is an implementation bug." - ); - debug_assert!(false); + let response = match StateResponse::decode(response) { + Ok(response) => response, + Err(error) => { + debug!( + target: LOG_TARGET, + "Failed to decode state response from peer {peer_id:?}: {error:?}.", + ); - BadPeer(peer_id, rep::BAD_RESPONSE) - })?; + return Err(BadPeer(*peer_id, rep::BAD_RESPONSE)); + }, + }; debug!( target: LOG_TARGET, @@ -218,7 +216,7 @@ impl StateStrategy { response.proof.len(), ); - match self.state_sync.import(*response) { + match self.state_sync.import(response) { ImportResult::Import(hash, header, state, body, justifications) => { let origin = BlockOrigin::NetworkInitialSync; let block = IncomingBlock { @@ -234,14 +232,13 @@ impl StateStrategy { state: Some(state), }; debug!(target: LOG_TARGET, "State download is complete. Import is queued"); - self.actions - .push(StateStrategyAction::ImportBlocks { origin, blocks: vec![block] }); + self.actions.push(SyncingAction::ImportBlocks { origin, blocks: vec![block] }); Ok(()) }, ImportResult::Continue => Ok(()), ImportResult::BadResponse => { debug!(target: LOG_TARGET, "Bad state data received from {peer_id}"); - Err(BadPeer(peer_id, rep::BAD_STATE)) + Err(BadPeer(*peer_id, rep::BAD_STATE)) }, } } @@ -281,12 +278,12 @@ impl StateStrategy { ); }); self.succeeded |= results.into_iter().any(|result| result.is_ok()); - self.actions.push(StateStrategyAction::Finished); + self.actions.push(SyncingAction::Finished); } } /// Produce state request. - fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)> { + fn state_request(&mut self) -> Option<(PeerId, StateRequest)> { if self.state_sync.is_complete() { return None } @@ -307,7 +304,7 @@ impl StateStrategy { target: LOG_TARGET, "New state request to {peer_id}: {request:?}.", ); - Some((peer_id, OpaqueStateRequest(Box::new(request)))) + Some((peer_id, request)) } fn schedule_next_peer( @@ -352,14 +349,33 @@ impl StateStrategy { } } - /// Get actions that should be performed by the owner on [`WarpSync`]'s behalf + /// Get actions that should be performed. #[must_use] - pub fn actions(&mut self) -> impl Iterator> { + pub fn actions( + &mut self, + network_service: &NetworkServiceHandle, + ) -> impl Iterator> { let state_request = self.state_request().into_iter().map(|(peer_id, request)| { - StateStrategyAction::SendStateRequest { + let (tx, rx) = oneshot::channel(); + + network_service.start_request( + peer_id, + self.protocol_name.clone(), + request.encode_to_vec(), + tx, + IfDisconnected::ImmediateError, + ); + + SyncingAction::StartRequest { peer_id, - protocol_name: self.protocol_name.clone(), - request, + key: Self::STRATEGY_KEY, + request: async move { + Ok(rx.await?.and_then(|(response, protocol_name)| { + Ok((Box::new(response) as Box, protocol_name)) + })) + } + .boxed(), + remove_obsolete: false, } }); self.actions.extend(state_request); @@ -379,6 +395,7 @@ mod test { use super::*; use crate::{ schema::v1::{StateRequest, StateResponse}, + service::network::NetworkServiceProvider, strategy::state_sync::{ImportResult, StateSyncProgress, StateSyncProvider}, }; use codec::Decode; @@ -579,8 +596,7 @@ mod test { ProtocolName::Static(""), ); - let (_peer_id, mut opaque_request) = state_strategy.state_request().unwrap(); - let request: &mut StateRequest = opaque_request.0.downcast_mut().unwrap(); + let (_peer_id, request) = state_strategy.state_request().unwrap(); let hash = Hash::decode(&mut &*request.block).unwrap(); assert_eq!(hash, target_block.header().hash()); @@ -631,8 +647,8 @@ mod test { // Manually set the peer's state. state_strategy.peers.get_mut(&peer_id).unwrap().state = PeerState::DownloadingState; - let dummy_response = OpaqueStateResponse(Box::new(StateResponse::default())); - state_strategy.on_state_response(peer_id, dummy_response); + let dummy_response = StateResponse::default().encode_to_vec(); + state_strategy.on_state_response(&peer_id, dummy_response); assert!(state_strategy.peers.get(&peer_id).unwrap().state.is_available()); } @@ -651,10 +667,10 @@ mod test { ); // Manually set the peer's state. state_strategy.peers.get_mut(&peer_id).unwrap().state = PeerState::DownloadingState; - let dummy_response = OpaqueStateResponse(Box::new(StateResponse::default())); + let dummy_response = StateResponse::default().encode_to_vec(); // Receiving response drops the peer. assert!(matches!( - state_strategy.on_state_response_inner(peer_id, dummy_response), + state_strategy.on_state_response_inner(&peer_id, &dummy_response), Err(BadPeer(id, _rep)) if id == peer_id, )); } @@ -674,8 +690,8 @@ mod test { // Manually set the peer's state . state_strategy.peers.get_mut(&peer_id).unwrap().state = PeerState::DownloadingState; - let dummy_response = OpaqueStateResponse(Box::new(StateResponse::default())); - state_strategy.on_state_response(peer_id, dummy_response); + let dummy_response = StateResponse::default().encode_to_vec(); + state_strategy.on_state_response(&peer_id, dummy_response); // No actions generated. assert_eq!(state_strategy.actions.len(), 0) @@ -737,13 +753,13 @@ mod test { state_strategy.peers.get_mut(&peer_id).unwrap().state = PeerState::DownloadingState; // Receive response. - let dummy_response = OpaqueStateResponse(Box::new(StateResponse::default())); - state_strategy.on_state_response(peer_id, dummy_response); + let dummy_response = StateResponse::default().encode_to_vec(); + state_strategy.on_state_response(&peer_id, dummy_response); assert_eq!(state_strategy.actions.len(), 1); assert!(matches!( &state_strategy.actions[0], - StateStrategyAction::ImportBlocks { origin, blocks } + SyncingAction::ImportBlocks { origin, blocks } if *origin == expected_origin && *blocks == expected_blocks, )); } @@ -799,7 +815,7 @@ mod test { // Strategy finishes. assert_eq!(state_strategy.actions.len(), 1); - assert!(matches!(&state_strategy.actions[0], StateStrategyAction::Finished)); + assert!(matches!(&state_strategy.actions[0], SyncingAction::Finished)); } #[test] @@ -826,7 +842,7 @@ mod test { // Strategy finishes. assert_eq!(state_strategy.actions.len(), 1); - assert!(matches!(&state_strategy.actions[0], StateStrategyAction::Finished)); + assert!(matches!(&state_strategy.actions[0], SyncingAction::Finished)); } #[test] @@ -854,12 +870,15 @@ mod test { )], ); + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); + // Strategy finishes. - let actions = state_strategy.actions().collect::>(); + let actions = state_strategy.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - assert!(matches!(&actions[0], StateStrategyAction::Finished)); + assert!(matches!(&actions[0], SyncingAction::Finished)); // No more actions generated. - assert_eq!(state_strategy.actions().count(), 0); + assert_eq!(state_strategy.actions(&network_handle).count(), 0); } } diff --git a/substrate/client/network/sync/src/strategy/state_sync.rs b/substrate/client/network/sync/src/strategy/state_sync.rs index 1ed1de7c8efa..47d859a1b7c6 100644 --- a/substrate/client/network/sync/src/strategy/state_sync.rs +++ b/substrate/client/network/sync/src/strategy/state_sync.rs @@ -19,12 +19,12 @@ //! State sync support. use crate::{ - schema::v1::{StateEntry, StateRequest, StateResponse}, + schema::v1::{KeyValueStateEntry, StateEntry, StateRequest, StateResponse}, LOG_TARGET, }; use codec::{Decode, Encode}; use log::debug; -use sc_client_api::{CompactProof, ProofProvider}; +use sc_client_api::{CompactProof, KeyValueStates, ProofProvider}; use sc_consensus::ImportedState; use smallvec::SmallVec; use sp_core::storage::well_known_keys; @@ -89,22 +89,62 @@ pub enum ImportResult { BadResponse, } -/// State sync state machine. Accumulates partial state data until it -/// is ready to be imported. -pub struct StateSync { - target_block: B::Hash, +struct StateSyncMetadata { + last_key: SmallVec<[Vec; 2]>, target_header: B::Header, - target_root: B::Hash, target_body: Option>, target_justifications: Option, - last_key: SmallVec<[Vec; 2]>, - state: HashMap, (Vec<(Vec, Vec)>, Vec>)>, complete: bool, - client: Arc, imported_bytes: u64, skip_proof: bool, } +impl StateSyncMetadata { + fn target_hash(&self) -> B::Hash { + self.target_header.hash() + } + + /// Returns target block number. + fn target_number(&self) -> NumberFor { + *self.target_header.number() + } + + fn target_root(&self) -> B::Hash { + *self.target_header.state_root() + } + + fn next_request(&self) -> StateRequest { + StateRequest { + block: self.target_hash().encode(), + start: self.last_key.clone().into_vec(), + no_proof: self.skip_proof, + } + } + + fn progress(&self) -> StateSyncProgress { + let cursor = *self.last_key.get(0).and_then(|last| last.get(0)).unwrap_or(&0u8); + let percent_done = cursor as u32 * 100 / 256; + StateSyncProgress { + percentage: percent_done, + size: self.imported_bytes, + phase: if self.complete { + StateSyncPhase::ImportingState + } else { + StateSyncPhase::DownloadingState + }, + } + } +} + +/// State sync state machine. +/// +/// Accumulates partial state data until it is ready to be imported. +pub struct StateSync { + metadata: StateSyncMetadata, + state: HashMap, (Vec<(Vec, Vec)>, Vec>)>, + client: Arc, +} + impl StateSync where B: BlockT, @@ -120,18 +160,92 @@ where ) -> Self { Self { client, - target_block: target_header.hash(), - target_root: *target_header.state_root(), - target_header, - target_body, - target_justifications, - last_key: SmallVec::default(), + metadata: StateSyncMetadata { + last_key: SmallVec::default(), + target_header, + target_body, + target_justifications, + complete: false, + imported_bytes: 0, + skip_proof, + }, state: HashMap::default(), - complete: false, - imported_bytes: 0, - skip_proof, } } + + fn process_state_key_values( + &mut self, + state_root: Vec, + key_values: impl IntoIterator, Vec)>, + ) { + let is_top = state_root.is_empty(); + + let entry = self.state.entry(state_root).or_default(); + + if entry.0.len() > 0 && entry.1.len() > 1 { + // Already imported child_trie with same root. + // Warning this will not work with parallel download. + return; + } + + let mut child_storage_roots = Vec::new(); + + for (key, value) in key_values { + // Skip all child key root (will be recalculated on import) + if is_top && well_known_keys::is_child_storage_key(key.as_slice()) { + child_storage_roots.push((value, key)); + } else { + self.metadata.imported_bytes += key.len() as u64; + entry.0.push((key, value)); + } + } + + for (root, storage_key) in child_storage_roots { + self.state.entry(root).or_default().1.push(storage_key); + } + } + + fn process_state_verified(&mut self, values: KeyValueStates) { + for values in values.0 { + self.process_state_key_values(values.state_root, values.key_values); + } + } + + fn process_state_unverified(&mut self, response: StateResponse) -> bool { + let mut complete = true; + // if the trie is a child trie and one of its parent trie is empty, + // the parent cursor stays valid. + // Empty parent trie content only happens when all the response content + // is part of a single child trie. + if self.metadata.last_key.len() == 2 && response.entries[0].entries.is_empty() { + // Do not remove the parent trie position. + self.metadata.last_key.pop(); + } else { + self.metadata.last_key.clear(); + } + for state in response.entries { + debug!( + target: LOG_TARGET, + "Importing state from {:?} to {:?}", + state.entries.last().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), + state.entries.first().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), + ); + + if !state.complete { + if let Some(e) = state.entries.last() { + self.metadata.last_key.push(e.key.clone()); + } + complete = false; + } + + let KeyValueStateEntry { state_root, entries, complete: _ } = state; + self.process_state_key_values( + state_root, + entries.into_iter().map(|StateEntry { key, value }| (key, value)), + ); + } + complete + } } impl StateSyncProvider for StateSync @@ -145,11 +259,11 @@ where debug!(target: LOG_TARGET, "Bad state response"); return ImportResult::BadResponse } - if !self.skip_proof && response.proof.is_empty() { + if !self.metadata.skip_proof && response.proof.is_empty() { debug!(target: LOG_TARGET, "Missing proof"); return ImportResult::BadResponse } - let complete = if !self.skip_proof { + let complete = if !self.metadata.skip_proof { debug!(target: LOG_TARGET, "Importing state from {} trie nodes", response.proof.len()); let proof_size = response.proof.len() as u64; let proof = match CompactProof::decode(&mut response.proof.as_ref()) { @@ -160,9 +274,9 @@ where }, }; let (values, completed) = match self.client.verify_range_proof( - self.target_root, + self.metadata.target_root(), proof, - self.last_key.as_slice(), + self.metadata.last_key.as_slice(), ) { Err(e) => { debug!( @@ -177,110 +291,25 @@ where debug!(target: LOG_TARGET, "Imported with {} keys", values.len()); let complete = completed == 0; - if !complete && !values.update_last_key(completed, &mut self.last_key) { + if !complete && !values.update_last_key(completed, &mut self.metadata.last_key) { debug!(target: LOG_TARGET, "Error updating key cursor, depth: {}", completed); }; - for values in values.0 { - let key_values = if values.state_root.is_empty() { - // Read child trie roots. - values - .key_values - .into_iter() - .filter(|key_value| { - if well_known_keys::is_child_storage_key(key_value.0.as_slice()) { - self.state - .entry(key_value.1.clone()) - .or_default() - .1 - .push(key_value.0.clone()); - false - } else { - true - } - }) - .collect() - } else { - values.key_values - }; - let entry = self.state.entry(values.state_root).or_default(); - if entry.0.len() > 0 && entry.1.len() > 1 { - // Already imported child_trie with same root. - // Warning this will not work with parallel download. - } else if entry.0.is_empty() { - for (key, _value) in key_values.iter() { - self.imported_bytes += key.len() as u64; - } - - entry.0 = key_values; - } else { - for (key, value) in key_values { - self.imported_bytes += key.len() as u64; - entry.0.push((key, value)) - } - } - } - self.imported_bytes += proof_size; + self.process_state_verified(values); + self.metadata.imported_bytes += proof_size; complete } else { - let mut complete = true; - // if the trie is a child trie and one of its parent trie is empty, - // the parent cursor stays valid. - // Empty parent trie content only happens when all the response content - // is part of a single child trie. - if self.last_key.len() == 2 && response.entries[0].entries.is_empty() { - // Do not remove the parent trie position. - self.last_key.pop(); - } else { - self.last_key.clear(); - } - for state in response.entries { - debug!( - target: LOG_TARGET, - "Importing state from {:?} to {:?}", - state.entries.last().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), - state.entries.first().map(|e| sp_core::hexdisplay::HexDisplay::from(&e.key)), - ); - - if !state.complete { - if let Some(e) = state.entries.last() { - self.last_key.push(e.key.clone()); - } - complete = false; - } - let is_top = state.state_root.is_empty(); - let entry = self.state.entry(state.state_root).or_default(); - if entry.0.len() > 0 && entry.1.len() > 1 { - // Already imported child trie with same root. - } else { - let mut child_roots = Vec::new(); - for StateEntry { key, value } in state.entries { - // Skip all child key root (will be recalculated on import). - if is_top && well_known_keys::is_child_storage_key(key.as_slice()) { - child_roots.push((value, key)); - } else { - self.imported_bytes += key.len() as u64; - entry.0.push((key, value)) - } - } - for (root, storage_key) in child_roots { - self.state.entry(root).or_default().1.push(storage_key); - } - } - } - complete + self.process_state_unverified(response) }; if complete { - self.complete = true; + self.metadata.complete = true; + let target_hash = self.metadata.target_hash(); ImportResult::Import( - self.target_block, - self.target_header.clone(), - ImportedState { - block: self.target_block, - state: std::mem::take(&mut self.state).into(), - }, - self.target_body.clone(), - self.target_justifications.clone(), + target_hash, + self.metadata.target_header.clone(), + ImportedState { block: target_hash, state: std::mem::take(&mut self.state).into() }, + self.metadata.target_body.clone(), + self.metadata.target_justifications.clone(), ) } else { ImportResult::Continue @@ -289,40 +318,26 @@ where /// Produce next state request. fn next_request(&self) -> StateRequest { - StateRequest { - block: self.target_block.encode(), - start: self.last_key.clone().into_vec(), - no_proof: self.skip_proof, - } + self.metadata.next_request() } /// Check if the state is complete. fn is_complete(&self) -> bool { - self.complete + self.metadata.complete } /// Returns target block number. fn target_number(&self) -> NumberFor { - *self.target_header.number() + self.metadata.target_number() } /// Returns target block hash. fn target_hash(&self) -> B::Hash { - self.target_block + self.metadata.target_hash() } /// Returns state sync estimated progress. fn progress(&self) -> StateSyncProgress { - let cursor = *self.last_key.get(0).and_then(|last| last.get(0)).unwrap_or(&0u8); - let percent_done = cursor as u32 * 100 / 256; - StateSyncProgress { - percentage: percent_done, - size: self.imported_bytes, - phase: if self.complete { - StateSyncPhase::ImportingState - } else { - StateSyncPhase::DownloadingState - }, - } + self.metadata.progress() } } diff --git a/substrate/client/network/sync/src/strategy/warp.rs b/substrate/client/network/sync/src/strategy/warp.rs index 0c71dd3c6aee..673bc1688ecc 100644 --- a/substrate/client/network/sync/src/strategy/warp.rs +++ b/substrate/client/network/sync/src/strategy/warp.rs @@ -21,13 +21,19 @@ pub use sp_consensus_grandpa::{AuthorityList, SetId}; use crate::{ - strategy::{chain_sync::validate_blocks, disconnected_peers::DisconnectedPeers}, + block_relay_protocol::{BlockDownloader, BlockResponseError}, + service::network::NetworkServiceHandle, + strategy::{ + chain_sync::validate_blocks, disconnected_peers::DisconnectedPeers, StrategyKey, + SyncingAction, + }, types::{BadPeer, SyncState, SyncStatus}, LOG_TARGET, }; use codec::{Decode, Encode}; +use futures::{channel::oneshot, FutureExt}; use log::{debug, error, trace, warn}; -use sc_network::ProtocolName; +use sc_network::{IfDisconnected, ProtocolName}; use sc_network_common::sync::message::{ BlockAnnounce, BlockAttributes, BlockData, BlockRequest, Direction, FromBlock, }; @@ -37,7 +43,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header, NumberFor, Zero}, Justifications, SaturatedConversion, }; -use std::{collections::HashMap, fmt, sync::Arc}; +use std::{any::Any, collections::HashMap, fmt, sync::Arc}; /// Number of peers that need to be connected before warp sync is started. const MIN_PEERS_TO_START_WARP_SYNC: usize = 3; @@ -97,6 +103,9 @@ mod rep { /// Reputation change for peers which send us a block which we fail to verify. pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 29), "Block verification failed"); + + /// We received a message that failed to decode. + pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); } /// Reported warp sync phase. @@ -186,22 +195,6 @@ struct Peer { state: PeerState, } -/// Action that should be performed on [`WarpSync`]'s behalf. -pub enum WarpSyncAction { - /// Send warp proof request to peer. - SendWarpProofRequest { - peer_id: PeerId, - protocol_name: ProtocolName, - request: WarpProofRequest, - }, - /// Send block request to peer. Always implies dropping a stale block request to the same peer. - SendBlockRequest { peer_id: PeerId, request: BlockRequest }, - /// Disconnect and report peer. - DropPeer(BadPeer), - /// Warp sync has finished. - Finished, -} - pub struct WarpSyncResult { pub target_header: B::Header, pub target_body: Option>, @@ -217,7 +210,8 @@ pub struct WarpSync { peers: HashMap>, disconnected_peers: DisconnectedPeers, protocol_name: Option, - actions: Vec>, + block_downloader: Arc>, + actions: Vec>, result: Option>, } @@ -226,6 +220,9 @@ where B: BlockT, Client: HeaderBackend + 'static, { + /// Strategy key used by warp sync. + pub const STRATEGY_KEY: StrategyKey = StrategyKey::new("Warp"); + /// Create a new instance. When passing a warp sync provider we will be checking for proof and /// authorities. Alternatively we can pass a target block when we want to skip downloading /// proofs, in this case we will continue polling until the target block is known. @@ -233,6 +230,7 @@ where client: Arc, warp_sync_config: WarpSyncConfig, protocol_name: Option, + block_downloader: Arc>, ) -> Self { if client.info().finalized_state.is_some() { error!( @@ -247,7 +245,8 @@ where peers: HashMap::new(), disconnected_peers: DisconnectedPeers::new(), protocol_name, - actions: vec![WarpSyncAction::Finished], + block_downloader, + actions: vec![SyncingAction::Finished], result: None, } } @@ -266,6 +265,7 @@ where peers: HashMap::new(), disconnected_peers: DisconnectedPeers::new(), protocol_name, + block_downloader, actions: Vec::new(), result: None, } @@ -285,7 +285,7 @@ where if let Some(bad_peer) = self.disconnected_peers.on_disconnect_during_request(*peer_id) { - self.actions.push(WarpSyncAction::DropPeer(bad_peer)); + self.actions.push(SyncingAction::DropPeer(bad_peer)); } } } @@ -329,6 +329,58 @@ where trace!(target: LOG_TARGET, "Started warp sync with {} peers.", self.peers.len()); } + pub fn on_generic_response( + &mut self, + peer_id: &PeerId, + protocol_name: ProtocolName, + response: Box, + ) { + if &protocol_name == self.block_downloader.protocol_name() { + let Ok(response) = response + .downcast::<(BlockRequest, Result>, BlockResponseError>)>() + else { + warn!(target: LOG_TARGET, "Failed to downcast block response"); + debug_assert!(false); + return; + }; + + let (request, response) = *response; + let blocks = match response { + Ok(blocks) => blocks, + Err(BlockResponseError::DecodeFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to decode block response from peer {:?}: {:?}.", + peer_id, + e + ); + self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE))); + return; + }, + Err(BlockResponseError::ExtractionFailed(e)) => { + debug!( + target: LOG_TARGET, + "Failed to extract blocks from peer response {:?}: {:?}.", + peer_id, + e + ); + self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE))); + return; + }, + }; + + self.on_block_response(*peer_id, request, blocks); + } else { + let Ok(response) = response.downcast::>() else { + warn!(target: LOG_TARGET, "Failed to downcast warp sync response"); + debug_assert!(false); + return; + }; + + self.on_warp_proof_response(peer_id, EncodedProof(*response)); + } + } + /// Process warp proof response. pub fn on_warp_proof_response(&mut self, peer_id: &PeerId, response: EncodedProof) { if let Some(peer) = self.peers.get_mut(peer_id) { @@ -340,7 +392,7 @@ where else { debug!(target: LOG_TARGET, "Unexpected warp proof response"); self.actions - .push(WarpSyncAction::DropPeer(BadPeer(*peer_id, rep::UNEXPECTED_RESPONSE))); + .push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::UNEXPECTED_RESPONSE))); return }; @@ -348,7 +400,7 @@ where Err(e) => { debug!(target: LOG_TARGET, "Bad warp proof response: {}", e); self.actions - .push(WarpSyncAction::DropPeer(BadPeer(*peer_id, rep::BAD_WARP_PROOF))) + .push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_WARP_PROOF))) }, Ok(VerificationResult::Partial(new_set_id, new_authorities, new_last_hash)) => { log::debug!(target: LOG_TARGET, "Verified partial proof, set_id={:?}", new_set_id); @@ -379,7 +431,7 @@ where blocks: Vec>, ) { if let Err(bad_peer) = self.on_block_response_inner(peer_id, request, blocks) { - self.actions.push(WarpSyncAction::DropPeer(bad_peer)); + self.actions.push(SyncingAction::DropPeer(bad_peer)); } } @@ -449,7 +501,7 @@ where target_justifications: block.justifications, }); self.phase = Phase::Complete; - self.actions.push(WarpSyncAction::Finished); + self.actions.push(SyncingAction::Finished); Ok(()) } @@ -606,17 +658,67 @@ where /// Get actions that should be performed by the owner on [`WarpSync`]'s behalf #[must_use] - pub fn actions(&mut self) -> impl Iterator> { + pub fn actions( + &mut self, + network_service: &NetworkServiceHandle, + ) -> impl Iterator> { let warp_proof_request = self.warp_proof_request().into_iter().map(|(peer_id, protocol_name, request)| { - WarpSyncAction::SendWarpProofRequest { peer_id, protocol_name, request } + trace!( + target: LOG_TARGET, + "Created `WarpProofRequest` to {}, request: {:?}.", + peer_id, + request, + ); + + let (tx, rx) = oneshot::channel(); + + network_service.start_request( + peer_id, + protocol_name, + request.encode(), + tx, + IfDisconnected::ImmediateError, + ); + + SyncingAction::StartRequest { + peer_id, + key: Self::STRATEGY_KEY, + request: async move { + Ok(rx.await?.and_then(|(response, protocol_name)| { + Ok((Box::new(response) as Box, protocol_name)) + })) + } + .boxed(), + remove_obsolete: false, + } }); self.actions.extend(warp_proof_request); - let target_block_request = self - .target_block_request() - .into_iter() - .map(|(peer_id, request)| WarpSyncAction::SendBlockRequest { peer_id, request }); + let target_block_request = + self.target_block_request().into_iter().map(|(peer_id, request)| { + let downloader = self.block_downloader.clone(); + + SyncingAction::StartRequest { + peer_id, + key: Self::STRATEGY_KEY, + request: async move { + Ok(downloader.download_blocks(peer_id, request.clone()).await?.and_then( + |(response, protocol_name)| { + let decoded_response = + downloader.block_response_into_blocks(&request, response); + let result = + Box::new((request, decoded_response)) as Box; + Ok((result, protocol_name)) + }, + )) + } + .boxed(), + // Sending block request implies dropping obsolete pending response as we are + // not interested in it anymore. + remove_obsolete: true, + } + }); self.actions.extend(target_block_request); std::mem::take(&mut self.actions).into_iter() @@ -632,6 +734,7 @@ where #[cfg(test)] mod test { use super::*; + use crate::{mock::MockBlockDownloader, service::network::NetworkServiceProvider}; use sc_block_builder::BlockBuilderBuilder; use sp_blockchain::{BlockStatus, Error as BlockchainError, HeaderBackend, Info}; use sp_consensus_grandpa::{AuthorityList, SetId}; @@ -716,12 +819,16 @@ mod test { let client = mock_client_with_state(); let provider = MockWarpSyncProvider::::new(); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); + + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); // Warp sync instantly finishes - let actions = warp_sync.actions().collect::>(); + let actions = warp_sync.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - assert!(matches!(actions[0], WarpSyncAction::Finished)); + assert!(matches!(actions[0], SyncingAction::Finished)); // ... with no result. assert!(warp_sync.take_result().is_none()); @@ -737,12 +844,16 @@ mod test { Default::default(), Default::default(), )); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); + + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); // Warp sync instantly finishes - let actions = warp_sync.actions().collect::>(); + let actions = warp_sync.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - assert!(matches!(actions[0], WarpSyncAction::Finished)); + assert!(matches!(actions[0], SyncingAction::Finished)); // ... with no result. assert!(warp_sync.take_result().is_none()); @@ -753,10 +864,14 @@ mod test { let client = mock_client_without_state(); let provider = MockWarpSyncProvider::::new(); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); + + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); // No actions are emitted. - assert_eq!(warp_sync.actions().count(), 0) + assert_eq!(warp_sync.actions(&network_handle).count(), 0) } #[test] @@ -769,10 +884,14 @@ mod test { Default::default(), Default::default(), )); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); + + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); // No actions are emitted. - assert_eq!(warp_sync.actions().count(), 0) + assert_eq!(warp_sync.actions(&network_handle).count(), 0) } #[test] @@ -784,7 +903,8 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); // Warp sync is not started when there is not enough peers. for _ in 0..(MIN_PEERS_TO_START_WARP_SYNC - 1) { @@ -802,7 +922,8 @@ mod test { let client = mock_client_without_state(); let provider = MockWarpSyncProvider::::new(); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); assert!(warp_sync.schedule_next_peer(PeerState::DownloadingProofs, None).is_none()); } @@ -826,7 +947,8 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); for best_number in 1..11 { warp_sync.add_peer(PeerId::random(), Hash::random(), best_number); @@ -847,7 +969,8 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); for best_number in 1..11 { warp_sync.add_peer(PeerId::random(), Hash::random(), best_number); @@ -867,7 +990,8 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); for best_number in 1..11 { warp_sync.add_peer(PeerId::random(), Hash::random(), best_number); @@ -911,7 +1035,12 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static(""))); + let mut warp_sync = WarpSync::new( + Arc::new(client), + config, + Some(ProtocolName::Static("")), + Arc::new(MockBlockDownloader::new()), + ); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -940,7 +1069,12 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static(""))); + let mut warp_sync = WarpSync::new( + Arc::new(client), + config, + Some(ProtocolName::Static("")), + Arc::new(MockBlockDownloader::new()), + ); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -971,7 +1105,12 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static(""))); + let mut warp_sync = WarpSync::new( + Arc::new(client), + config, + Some(ProtocolName::Static("")), + Arc::new(MockBlockDownloader::new()), + ); // Make sure we have enough peers to make requests. for best_number in 1..11 { @@ -998,7 +1137,12 @@ mod test { Err(Box::new(std::io::Error::new(ErrorKind::Other, "test-verification-failure"))) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static(""))); + let mut warp_sync = WarpSync::new( + Arc::new(client), + config, + Some(ProtocolName::Static("")), + Arc::new(MockBlockDownloader::new()), + ); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1006,11 +1150,13 @@ mod test { } assert!(matches!(warp_sync.phase, Phase::WarpProof { .. })); + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); + // Consume `SendWarpProofRequest` action. - let actions = warp_sync.actions().collect::>(); + let actions = warp_sync.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - let WarpSyncAction::SendWarpProofRequest { peer_id: request_peer_id, .. } = actions[0] - else { + let SyncingAction::StartRequest { peer_id: request_peer_id, .. } = actions[0] else { panic!("Invalid action"); }; @@ -1021,7 +1167,7 @@ mod test { assert_eq!(actions.len(), 1); assert!(matches!( actions[0], - WarpSyncAction::DropPeer(BadPeer(peer_id, _rep)) if peer_id == request_peer_id + SyncingAction::DropPeer(BadPeer(peer_id, _rep)) if peer_id == request_peer_id )); assert!(matches!(warp_sync.phase, Phase::WarpProof { .. })); } @@ -1039,7 +1185,12 @@ mod test { Ok(VerificationResult::Partial(set_id, authorities, Hash::random())) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static(""))); + let mut warp_sync = WarpSync::new( + Arc::new(client), + config, + Some(ProtocolName::Static("")), + Arc::new(MockBlockDownloader::new()), + ); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1047,11 +1198,13 @@ mod test { } assert!(matches!(warp_sync.phase, Phase::WarpProof { .. })); + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); + // Consume `SendWarpProofRequest` action. - let actions = warp_sync.actions().collect::>(); + let actions = warp_sync.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - let WarpSyncAction::SendWarpProofRequest { peer_id: request_peer_id, .. } = actions[0] - else { + let SyncingAction::StartRequest { peer_id: request_peer_id, .. } = actions[0] else { panic!("Invalid action"); }; @@ -1083,7 +1236,12 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, Some(ProtocolName::Static(""))); + let mut warp_sync = WarpSync::new( + client, + config, + Some(ProtocolName::Static("")), + Arc::new(MockBlockDownloader::new()), + ); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1091,11 +1249,13 @@ mod test { } assert!(matches!(warp_sync.phase, Phase::WarpProof { .. })); + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); + // Consume `SendWarpProofRequest` action. - let actions = warp_sync.actions().collect::>(); + let actions = warp_sync.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - let WarpSyncAction::SendWarpProofRequest { peer_id: request_peer_id, .. } = actions[0] - else { + let SyncingAction::StartRequest { peer_id: request_peer_id, .. } = actions[0] else { panic!("Invalid action."); }; @@ -1116,7 +1276,8 @@ mod test { .once() .return_const(AuthorityList::default()); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(Arc::new(client), config, None); + let mut warp_sync = + WarpSync::new(Arc::new(client), config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1151,7 +1312,8 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1183,7 +1345,8 @@ mod test { .block; let target_header = target_block.header().clone(); let config = WarpSyncConfig::WithTarget(target_header); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1223,7 +1386,8 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1261,7 +1425,8 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1315,7 +1480,8 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1392,7 +1558,8 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1445,7 +1612,8 @@ mod test { Ok(VerificationResult::Complete(set_id, authorities, target_header)) }); let config = WarpSyncConfig::WithProvider(Arc::new(provider)); - let mut warp_sync = WarpSync::new(client, config, None); + let mut warp_sync = + WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new())); // Make sure we have enough peers to make a request. for best_number in 1..11 { @@ -1473,10 +1641,13 @@ mod test { assert!(warp_sync.on_block_response_inner(peer_id, request, response).is_ok()); + let network_provider = NetworkServiceProvider::new(); + let network_handle = network_provider.handle(); + // Strategy finishes. - let actions = warp_sync.actions().collect::>(); + let actions = warp_sync.actions(&network_handle).collect::>(); assert_eq!(actions.len(), 1); - assert!(matches!(actions[0], WarpSyncAction::Finished)); + assert!(matches!(actions[0], SyncingAction::Finished)); // With correct result. let result = warp_sync.take_result().unwrap(); diff --git a/substrate/client/network/sync/src/types.rs b/substrate/client/network/sync/src/types.rs index c3403fe1e5f7..a72a2f7c1ffe 100644 --- a/substrate/client/network/sync/src/types.rs +++ b/substrate/client/network/sync/src/types.rs @@ -23,11 +23,10 @@ use sc_network_common::{role::Roles, types::ReputationChange}; use crate::strategy::{state_sync::StateSyncProgress, warp::WarpSyncProgress}; -use sc_network_common::sync::message::BlockRequest; use sc_network_types::PeerId; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use std::{any::Any, fmt, fmt::Formatter, pin::Pin, sync::Arc}; +use std::{fmt, pin::Pin, sync::Arc}; /// The sync status of a peer we are trying to sync with #[derive(Debug)] @@ -107,52 +106,6 @@ impl fmt::Display for BadPeer { impl std::error::Error for BadPeer {} -#[derive(Debug)] -pub enum PeerRequest { - Block(BlockRequest), - State, - WarpProof, -} - -#[derive(Debug)] -pub enum PeerRequestType { - Block, - State, - WarpProof, -} - -impl PeerRequest { - pub fn get_type(&self) -> PeerRequestType { - match self { - PeerRequest::Block(_) => PeerRequestType::Block, - PeerRequest::State => PeerRequestType::State, - PeerRequest::WarpProof => PeerRequestType::WarpProof, - } - } -} - -/// Wrapper for implementation-specific state request. -/// -/// NOTE: Implementation must be able to encode and decode it for network purposes. -pub struct OpaqueStateRequest(pub Box); - -impl fmt::Debug for OpaqueStateRequest { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("OpaqueStateRequest").finish() - } -} - -/// Wrapper for implementation-specific state response. -/// -/// NOTE: Implementation must be able to encode and decode it for network purposes. -pub struct OpaqueStateResponse(pub Box); - -impl fmt::Debug for OpaqueStateResponse { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("OpaqueStateResponse").finish() - } -} - /// Provides high-level status of syncing. #[async_trait::async_trait] pub trait SyncStatusProvider: Send + Sync { @@ -174,6 +127,10 @@ where /// Syncing-related events that other protocols can subscribe to. pub enum SyncEvent { + /// All connected peers that the syncing implementation is tracking. + /// Always sent as the first message to the stream. + InitialPeers(Vec), + /// Peer that the syncing implementation is tracking connected. PeerConnected(PeerId), diff --git a/substrate/client/network/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index ebece1762f29..783d47f21fa7 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -16,7 +16,6 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -tokio = { workspace = true, default-features = true } async-trait = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } @@ -29,11 +28,11 @@ sc-client-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } -sc-network-types = { workspace = true, default-features = true } -sc-utils = { workspace = true, default-features = true } sc-network-light = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } -sc-service = { features = ["test-helpers"], workspace = true } +sc-network-types = { workspace = true, default-features = true } +sc-service = { workspace = true } +sc-utils = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } @@ -41,3 +40,4 @@ sp-runtime = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime = { workspace = true } substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 06e243342fb2..3cdf211e07f6 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -67,11 +67,11 @@ use sc_network_sync::{ service::{network::NetworkServiceProvider, syncing_service::SyncingService}, state_request_handler::StateRequestHandler, strategy::{ + polkadot::{PolkadotSyncingStrategy, PolkadotSyncingStrategyConfig}, warp::{ AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncConfig, WarpSyncProvider, }, - PolkadotSyncingStrategy, SyncingConfig, }, warp_request_handler, }; @@ -91,7 +91,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, Justification, Justifications, }; -use substrate_test_runtime_client::AccountKeyring; +use substrate_test_runtime_client::Sr25519Keyring; pub use substrate_test_runtime_client::{ runtime::{Block, ExtrinsicBuilder, Hash, Header, Transfer}, TestClient, TestClientBuilder, TestClientBuilderExt, @@ -475,8 +475,8 @@ where BlockOrigin::File, |mut builder| { let transfer = Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Alice.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Alice.into(), amount: 1, nonce, }; @@ -833,8 +833,8 @@ pub trait TestNetFactory: Default + Sized + Send { let fork_id = Some(String::from("test-fork-id")); - let (chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); + let chain_sync_network_provider = NetworkServiceProvider::new(); + let chain_sync_network_handle = chain_sync_network_provider.handle(); let mut block_relay_params = BlockRequestHandler::new::>( chain_sync_network_handle.clone(), &protocol_id, @@ -908,12 +908,13 @@ pub trait TestNetFactory: Default + Sized + Send { ::Hash, >>::register_notification_metrics(None); - let syncing_config = SyncingConfig { + let syncing_config = PolkadotSyncingStrategyConfig { mode: network_config.sync_mode, max_parallel_downloads: network_config.max_parallel_downloads, max_blocks_per_request: network_config.max_blocks_per_request, metrics_registry: None, state_request_protocol_name: state_request_protocol_config.name.clone(), + block_downloader: block_relay_params.downloader, }; // Initialize syncing strategy. let syncing_strategy = Box::new( @@ -934,16 +935,14 @@ pub trait TestNetFactory: Default + Sized + Send { metrics, &full_net_config, protocol_id.clone(), - &fork_id, + fork_id.as_deref(), block_announce_validator, syncing_strategy, chain_sync_network_handle, import_queue.service(), - block_relay_params.downloader, peer_store_handle.clone(), ) .unwrap(); - let sync_service_import_queue = Box::new(sync_service.clone()); let sync_service = Arc::new(sync_service.clone()); for config in config.request_response_protocols { @@ -987,8 +986,12 @@ pub trait TestNetFactory: Default + Sized + Send { chain_sync_network_provider.run(service).await; }); - tokio::spawn(async move { - import_queue.run(sync_service_import_queue).await; + tokio::spawn({ + let sync_service = sync_service.clone(); + + async move { + import_queue.run(sync_service.as_ref()).await; + } }); tokio::spawn(async move { diff --git a/substrate/client/network/test/src/service.rs b/substrate/client/network/test/src/service.rs index ad2d1d9ec24d..688b569c3222 100644 --- a/substrate/client/network/test/src/service.rs +++ b/substrate/client/network/test/src/service.rs @@ -32,9 +32,9 @@ use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ block_request_handler::BlockRequestHandler, engine::SyncingEngine, - service::network::{NetworkServiceHandle, NetworkServiceProvider}, + service::network::NetworkServiceProvider, state_request_handler::StateRequestHandler, - strategy::{PolkadotSyncingStrategy, SyncingConfig}, + strategy::polkadot::{PolkadotSyncingStrategy, PolkadotSyncingStrategyConfig}, }; use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, Zero}; @@ -78,7 +78,7 @@ struct TestNetworkBuilder { client: Option>, listen_addresses: Vec, set_config: Option, - chain_sync_network: Option<(NetworkServiceProvider, NetworkServiceHandle)>, + chain_sync_network: Option, notification_protocols: Vec, config: Option, } @@ -157,8 +157,9 @@ impl TestNetworkBuilder { let fork_id = Some(String::from("test-fork-id")); let mut full_net_config = FullNetworkConfiguration::new(&network_config, None); - let (chain_sync_network_provider, chain_sync_network_handle) = + let chain_sync_network_provider = self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); + let chain_sync_network_handle = chain_sync_network_provider.handle(); let mut block_relay_params = BlockRequestHandler::new::< NetworkWorker< @@ -203,12 +204,13 @@ impl TestNetworkBuilder { let peer_store_handle: Arc = Arc::new(peer_store.handle()); tokio::spawn(peer_store.run().boxed()); - let syncing_config = SyncingConfig { + let syncing_config = PolkadotSyncingStrategyConfig { mode: network_config.sync_mode, max_parallel_downloads: network_config.max_parallel_downloads, max_blocks_per_request: network_config.max_blocks_per_request, metrics_registry: None, state_request_protocol_name: state_request_protocol_config.name.clone(), + block_downloader: block_relay_params.downloader, }; // Initialize syncing strategy. let syncing_strategy = Box::new( @@ -222,12 +224,11 @@ impl TestNetworkBuilder { NotificationMetrics::new(None), &full_net_config, protocol_id.clone(), - &None, + None, Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator), syncing_strategy, chain_sync_network_handle, import_queue.service(), - block_relay_params.downloader, Arc::clone(&peer_store_handle), ) .unwrap(); diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index 2ffd6f5f4660..ef9ea1c46197 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -26,5 +26,5 @@ sc-network-common = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } diff --git a/substrate/client/network/transactions/src/lib.rs b/substrate/client/network/transactions/src/lib.rs index 2b5297fe0e13..49f429a04ee2 100644 --- a/substrate/client/network/transactions/src/lib.rs +++ b/substrate/client/network/transactions/src/lib.rs @@ -35,7 +35,8 @@ use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::{ config::{NonReservedPeerMode, ProtocolId, SetConfig}, - error, multiaddr, + error, + multiaddr::{Multiaddr, Protocol}, peer_store::PeerStoreProvider, service::{ traits::{NotificationEvent, NotificationService, ValidationResult}, @@ -377,9 +378,19 @@ where fn handle_sync_event(&mut self, event: SyncEvent) { match event { - SyncEvent::PeerConnected(remote) => { - let addr = iter::once(multiaddr::Protocol::P2p(remote.into())) - .collect::(); + SyncEvent::InitialPeers(peer_ids) => { + let addrs = peer_ids + .into_iter() + .map(|peer_id| Multiaddr::empty().with(Protocol::P2p(peer_id.into()))) + .collect(); + let result = + self.network.add_peers_to_reserved_set(self.protocol_name.clone(), addrs); + if let Err(err) = result { + log::error!(target: LOG_TARGET, "Add reserved peers failed: {}", err); + } + }, + SyncEvent::PeerConnected(peer_id) => { + let addr = Multiaddr::empty().with(Protocol::P2p(peer_id.into())); let result = self.network.add_peers_to_reserved_set( self.protocol_name.clone(), iter::once(addr).collect(), @@ -388,10 +399,10 @@ where log::error!(target: LOG_TARGET, "Add reserved peer failed: {}", err); } }, - SyncEvent::PeerDisconnected(remote) => { + SyncEvent::PeerDisconnected(peer_id) => { let result = self.network.remove_peers_from_reserved_set( self.protocol_name.clone(), - iter::once(remote).collect(), + iter::once(peer_id).collect(), ); if let Err(err) = result { log::error!(target: LOG_TARGET, "Remove reserved peer failed: {}", err); @@ -480,7 +491,7 @@ where continue } - let (hashes, to_send): (Vec<_>, Vec<_>) = transactions + let (hashes, to_send): (Vec<_>, Transactions<_>) = transactions .iter() .filter(|(hash, _)| peer.known_transactions.insert(hash.clone())) .cloned() diff --git a/substrate/client/network/types/Cargo.toml b/substrate/client/network/types/Cargo.toml index 655f104111e4..67814f135d39 100644 --- a/substrate/client/network/types/Cargo.toml +++ b/substrate/client/network/types/Cargo.toml @@ -11,8 +11,10 @@ documentation = "https://docs.rs/sc-network-types" [dependencies] bs58 = { workspace = true, default-features = true } +bytes = { version = "1.4.0", default-features = false } ed25519-dalek = { workspace = true, default-features = true } libp2p-identity = { features = ["ed25519", "peerid", "rand"], workspace = true } +libp2p-kad = { version = "0.46.2", default-features = false } litep2p = { workspace = true } log = { workspace = true, default-features = true } multiaddr = { workspace = true } diff --git a/substrate/client/network/types/src/kad.rs b/substrate/client/network/types/src/kad.rs new file mode 100644 index 000000000000..72028d356dc7 --- /dev/null +++ b/substrate/client/network/types/src/kad.rs @@ -0,0 +1,185 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{multihash::Multihash, PeerId}; +use bytes::Bytes; +use libp2p_kad::RecordKey as Libp2pKey; +use litep2p::protocol::libp2p::kademlia::{Record as Litep2pRecord, RecordKey as Litep2pKey}; +use std::{error::Error, fmt, time::Instant}; + +/// The (opaque) key of a record. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Key(Bytes); + +impl Key { + /// Creates a new key from the bytes of the input. + pub fn new>(key: &K) -> Self { + Key(Bytes::copy_from_slice(key.as_ref())) + } + + /// Copies the bytes of the key into a new vector. + pub fn to_vec(&self) -> Vec { + self.0.to_vec() + } +} + +impl AsRef<[u8]> for Key { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl From> for Key { + fn from(v: Vec) -> Key { + Key(Bytes::from(v)) + } +} + +impl From for Key { + fn from(m: Multihash) -> Key { + Key::from(m.to_bytes()) + } +} + +impl From for Key { + fn from(key: Litep2pKey) -> Self { + Self::from(key.to_vec()) + } +} + +impl From for Litep2pKey { + fn from(key: Key) -> Self { + Self::from(key.to_vec()) + } +} + +impl From for Key { + fn from(key: Libp2pKey) -> Self { + Self::from(key.to_vec()) + } +} + +impl From for Libp2pKey { + fn from(key: Key) -> Self { + Self::from(key.to_vec()) + } +} + +/// A record stored in the DHT. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Record { + /// Key of the record. + pub key: Key, + /// Value of the record. + pub value: Vec, + /// The (original) publisher of the record. + pub publisher: Option, + /// The expiration time as measured by a local, monotonic clock. + pub expires: Option, +} + +impl Record { + /// Creates a new record for insertion into the DHT. + pub fn new(key: Key, value: Vec) -> Self { + Record { key, value, publisher: None, expires: None } + } + + /// Checks whether the record is expired w.r.t. the given `Instant`. + pub fn is_expired(&self, now: Instant) -> bool { + self.expires.map_or(false, |t| now >= t) + } +} + +impl From for Record { + fn from(out: libp2p_kad::Record) -> Self { + let vec: Vec = out.key.to_vec(); + let key: Key = vec.into(); + let publisher = out.publisher.map(Into::into); + Record { key, value: out.value, publisher, expires: out.expires } + } +} + +impl From for Litep2pRecord { + fn from(val: Record) -> Self { + let vec: Vec = val.key.to_vec(); + let key: Litep2pKey = vec.into(); + let publisher = val.publisher.map(Into::into); + Litep2pRecord { key, value: val.value, publisher, expires: val.expires } + } +} + +impl From for libp2p_kad::Record { + fn from(a: Record) -> libp2p_kad::Record { + let peer = a.publisher.map(Into::into); + libp2p_kad::Record { + key: a.key.to_vec().into(), + value: a.value, + publisher: peer, + expires: a.expires, + } + } +} + +/// A record either received by the given peer or retrieved from the local +/// record store. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PeerRecord { + /// The peer from whom the record was received. `None` if the record was + /// retrieved from local storage. + pub peer: Option, + pub record: Record, +} + +impl From for PeerRecord { + fn from(out: libp2p_kad::PeerRecord) -> Self { + let peer = out.peer.map(Into::into); + let record = out.record.into(); + PeerRecord { peer, record } + } +} + +/// An error during signing of a message. +#[derive(Debug)] +pub struct SigningError { + msg: String, + source: Option>, +} + +/// An error during encoding of key material. +#[allow(dead_code)] +impl SigningError { + pub(crate) fn new(msg: S) -> Self { + Self { msg: msg.to_string(), source: None } + } + + pub(crate) fn source(self, source: impl Error + Send + Sync + 'static) -> Self { + Self { source: Some(Box::new(source)), ..self } + } +} + +impl fmt::Display for SigningError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Key signing error: {}", self.msg) + } +} + +impl Error for SigningError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.source.as_ref().map(|s| &**s as &dyn Error) + } +} diff --git a/substrate/client/network/types/src/lib.rs b/substrate/client/network/types/src/lib.rs index 5684e38ab2e8..093d81533f60 100644 --- a/substrate/client/network/types/src/lib.rs +++ b/substrate/client/network/types/src/lib.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . pub mod ed25519; +pub mod kad; pub mod multiaddr; pub mod multihash; - mod peer_id; pub use peer_id::PeerId; diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index 71b40211e126..bfdb29cc4c35 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -26,13 +26,12 @@ http-body-util = { workspace = true } hyper = { features = ["http1", "http2"], workspace = true, default-features = true } hyper-rustls = { workspace = true } hyper-util = { features = ["client-legacy", "http1", "http2"], workspace = true } +log = { workspace = true, default-features = true } num_cpus = { workspace = true } once_cell = { workspace = true } parking_lot = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } rustls = { workspace = true } -threadpool = { workspace = true } -tracing = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } @@ -41,15 +40,15 @@ sc-transaction-pool-api = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-externalities = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } sp-offchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sp-externalities = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } +threadpool = { workspace = true } +tracing = { workspace = true, default-features = true } [dev-dependencies] async-trait = { workspace = true } -tokio = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-client-db = { default-features = true, workspace = true } sc-transaction-pool = { workspace = true, default-features = true } @@ -57,6 +56,7 @@ sc-transaction-pool-api = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } [features] default = [] diff --git a/substrate/client/proposer-metrics/src/lib.rs b/substrate/client/proposer-metrics/src/lib.rs index 2856300cf802..a62278988f12 100644 --- a/substrate/client/proposer-metrics/src/lib.rs +++ b/substrate/client/proposer-metrics/src/lib.rs @@ -44,7 +44,7 @@ impl MetricsLink { } /// The reason why proposing a block ended. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum EndProposingReason { NoMoreTransactions, HitDeadline, diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 3263285aa2b1..e7bb723d8839 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -17,15 +17,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -thiserror = { workspace = true } +jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } sc-chain-spec = { workspace = true, default-features = true } sc-mixnet = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-rpc = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } -jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } +thiserror = { workspace = true } diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index 31e4042d81f2..4234ff3196ef 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -144,11 +144,56 @@ where local_addrs.push(local_addr); let cfg = cfg.clone(); - let mut id_provider2 = id_provider.clone(); + let RpcSettings { + batch_config, + max_connections, + max_payload_in_mb, + max_payload_out_mb, + max_buffer_capacity_per_connection, + max_subscriptions_per_connection, + rpc_methods, + rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips, + host_filter, + cors, + rate_limit, + } = listener.rpc_settings(); + + let http_middleware = tower::ServiceBuilder::new() + .option_layer(host_filter) + // Proxy `GET /health, /health/readiness` requests to the internal + // `system_health` method. + .layer(NodeHealthProxyLayer::default()) + .layer(cors); + + let mut builder = jsonrpsee::server::Server::builder() + .max_request_body_size(max_payload_in_mb.saturating_mul(MEGABYTE)) + .max_response_body_size(max_payload_out_mb.saturating_mul(MEGABYTE)) + .max_connections(max_connections) + .max_subscriptions_per_connection(max_subscriptions_per_connection) + .enable_ws_ping( + PingConfig::new() + .ping_interval(Duration::from_secs(30)) + .inactive_limit(Duration::from_secs(60)) + .max_failures(3), + ) + .set_http_middleware(http_middleware) + .set_message_buffer_capacity(max_buffer_capacity_per_connection) + .set_batch_request_config(batch_config) + .custom_tokio_runtime(cfg.tokio_handle.clone()); + + if let Some(provider) = id_provider.clone() { + builder = builder.set_id_provider(provider); + } else { + builder = builder.set_id_provider(RandomStringIdProvider::new(16)); + }; + + let service_builder = builder.to_service_builder(); + let deny_unsafe = deny_unsafe(&local_addr, &rpc_methods); tokio_handle.spawn(async move { loop { - let (sock, remote_addr, rpc_cfg) = tokio::select! { + let (sock, remote_addr) = tokio::select! { res = listener.accept() => { match res { Ok(s) => s, @@ -161,57 +206,10 @@ where _ = cfg.stop_handle.clone().shutdown() => break, }; - let RpcSettings { - batch_config, - max_connections, - max_payload_in_mb, - max_payload_out_mb, - max_buffer_capacity_per_connection, - max_subscriptions_per_connection, - rpc_methods, - rate_limit_trust_proxy_headers, - rate_limit_whitelisted_ips, - host_filter, - cors, - rate_limit, - } = rpc_cfg; - - let http_middleware = tower::ServiceBuilder::new() - .option_layer(host_filter) - // Proxy `GET /health, /health/readiness` requests to the internal - // `system_health` method. - .layer(NodeHealthProxyLayer::default()) - .layer(cors); - - let mut builder = jsonrpsee::server::Server::builder() - .max_request_body_size(max_payload_in_mb.saturating_mul(MEGABYTE)) - .max_response_body_size(max_payload_out_mb.saturating_mul(MEGABYTE)) - .max_connections(max_connections) - .max_subscriptions_per_connection(max_subscriptions_per_connection) - .enable_ws_ping( - PingConfig::new() - .ping_interval(Duration::from_secs(30)) - .inactive_limit(Duration::from_secs(60)) - .max_failures(3), - ) - .set_http_middleware(http_middleware) - .set_message_buffer_capacity(max_buffer_capacity_per_connection) - .set_batch_request_config(batch_config) - .custom_tokio_runtime(cfg.tokio_handle.clone()) - .set_id_provider(RandomStringIdProvider::new(16)); - - if let Some(provider) = id_provider2.take() { - builder = builder.set_id_provider(provider); - } else { - builder = builder.set_id_provider(RandomStringIdProvider::new(16)); - }; - - let service_builder = builder.to_service_builder(); - let deny_unsafe = deny_unsafe(&local_addr, &rpc_methods); - let ip = remote_addr.ip(); let cfg2 = cfg.clone(); let service_builder2 = service_builder.clone(); + let rate_limit_whitelisted_ips2 = rate_limit_whitelisted_ips.clone(); let svc = tower::service_fn(move |mut req: http::Request| { @@ -224,14 +222,14 @@ where let proxy_ip = if rate_limit_trust_proxy_headers { get_proxy_ip(&req) } else { None }; - let rate_limit_cfg = if rate_limit_whitelisted_ips + let rate_limit_cfg = if rate_limit_whitelisted_ips2 .iter() .any(|ips| ips.contains(proxy_ip.unwrap_or(ip))) { log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is trusted, disabling rate-limit", proxy_ip); None } else { - if !rate_limit_whitelisted_ips.is_empty() { + if !rate_limit_whitelisted_ips2.is_empty() { log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is not trusted, rate-limit enabled", proxy_ip); } rate_limit diff --git a/substrate/client/rpc-servers/src/utils.rs b/substrate/client/rpc-servers/src/utils.rs index d9b2db7af133..b76cfced3401 100644 --- a/substrate/client/rpc-servers/src/utils.rs +++ b/substrate/client/rpc-servers/src/utils.rs @@ -176,31 +176,30 @@ pub(crate) struct Listener { impl Listener { /// Accepts a new connection. - pub(crate) async fn accept( - &mut self, - ) -> std::io::Result<(tokio::net::TcpStream, SocketAddr, RpcSettings)> { + pub(crate) async fn accept(&mut self) -> std::io::Result<(tokio::net::TcpStream, SocketAddr)> { let (sock, remote_addr) = self.listener.accept().await?; - Ok((sock, remote_addr, self.cfg.clone())) + Ok((sock, remote_addr)) } /// Returns the local address the listener is bound to. pub fn local_addr(&self) -> SocketAddr { self.local_addr } + + pub fn rpc_settings(&self) -> RpcSettings { + self.cfg.clone() + } } pub(crate) fn host_filtering(enabled: bool, addr: SocketAddr) -> Option { if enabled { // NOTE: The listening addresses are whitelisted by default. - let mut hosts = Vec::new(); - - if addr.is_ipv4() { - hosts.push(format!("localhost:{}", addr.port())); - hosts.push(format!("127.0.0.1:{}", addr.port())); - } else { - hosts.push(format!("[::1]:{}", addr.port())); - } + let hosts = [ + format!("localhost:{}", addr.port()), + format!("127.0.0.1:{}", addr.port()), + format!("[::1]:{}", addr.port()), + ]; Some(HostFilterLayer::new(hosts).expect("Valid hosts; qed")) } else { diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 58dd8b830beb..ebe7e7eca7b4 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -20,43 +20,45 @@ jsonrpsee = { workspace = true, features = ["client-core", "macros", "server-cor # Internal chain structures for "chain_spec". sc-chain-spec = { workspace = true, default-features = true } # Pool for submitting extrinsics required by "transaction" +array-bytes = { workspace = true, default-features = true } +codec = { workspace = true, default-features = true } +futures = { workspace = true } +futures-util = { workspace = true } +hex = { workspace = true, default-features = true } +itertools = { workspace = true } +log = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } +schnellru = { workspace = true } +serde = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-rpc = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-rpc = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sc-rpc = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } thiserror = { workspace = true } -serde = { workspace = true, default-features = true } -hex = { workspace = true, default-features = true } -futures = { workspace = true } -parking_lot = { workspace = true, default-features = true } -tokio-stream = { features = ["sync"], workspace = true } tokio = { features = ["sync"], workspace = true, default-features = true } -array-bytes = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } -futures-util = { workspace = true } -rand = { workspace = true, default-features = true } -schnellru = { workspace = true } +tokio-stream = { features = ["sync"], workspace = true } [dev-dependencies] +assert_matches = { workspace = true } +async-trait = { workspace = true } jsonrpsee = { workspace = true, features = ["server", "ws-client"] } -serde_json = { workspace = true, default-features = true } -tokio = { features = ["macros"], workspace = true, default-features = true } -substrate-test-runtime-client = { workspace = true } -substrate-test-runtime = { workspace = true } -substrate-test-runtime-transaction-pool = { workspace = true } -sp-consensus = { workspace = true, default-features = true } -sp-externalities = { workspace = true, default-features = true } -sp-maybe-compressed-blob = { workspace = true, default-features = true } +pretty_assertions = { workspace = true } sc-block-builder = { workspace = true, default-features = true } -sc-service = { features = ["test-helpers"], workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true, features = ["test-helpers"] } -assert_matches = { workspace = true } -pretty_assertions = { workspace = true } +sc-service = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-externalities = { workspace = true, default-features = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } +substrate-test-runtime = { workspace = true } +substrate-test-runtime-client = { workspace = true } +substrate-test-runtime-transaction-pool = { workspace = true } +tokio = { features = ["macros"], workspace = true, default-features = true } diff --git a/substrate/client/rpc-spec-v2/src/archive/api.rs b/substrate/client/rpc-spec-v2/src/archive/api.rs index b19738304000..a205d0502c93 100644 --- a/substrate/client/rpc-spec-v2/src/archive/api.rs +++ b/substrate/client/rpc-spec-v2/src/archive/api.rs @@ -19,7 +19,9 @@ //! API trait of the archive methods. use crate::{ - common::events::{ArchiveStorageResult, PaginatedStorageQuery}, + common::events::{ + ArchiveStorageDiffEvent, ArchiveStorageDiffItem, ArchiveStorageEvent, StorageQuery, + }, MethodResult, }; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; @@ -97,11 +99,32 @@ pub trait ArchiveApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "archive_unstable_storage", blocking)] + #[subscription( + name = "archive_unstable_storage" => "archive_unstable_storageEvent", + unsubscribe = "archive_unstable_stopStorage", + item = ArchiveStorageEvent, + )] fn archive_unstable_storage( &self, hash: Hash, - items: Vec>, + items: Vec>, child_trie: Option, - ) -> RpcResult; + ); + + /// Returns the storage difference between two blocks. + /// + /// # Unstable + /// + /// This method is unstable and can change in minor or patch releases. + #[subscription( + name = "archive_unstable_storageDiff" => "archive_unstable_storageDiffEvent", + unsubscribe = "archive_unstable_storageDiff_stopStorageDiff", + item = ArchiveStorageDiffEvent, + )] + fn archive_unstable_storage_diff( + &self, + hash: Hash, + items: Vec>, + previous_hash: Option, + ); } diff --git a/substrate/client/rpc-spec-v2/src/archive/archive.rs b/substrate/client/rpc-spec-v2/src/archive/archive.rs index dd6c566a76ed..62e44a016241 100644 --- a/substrate/client/rpc-spec-v2/src/archive/archive.rs +++ b/substrate/client/rpc-spec-v2/src/archive/archive.rs @@ -19,17 +19,29 @@ //! API implementation for `archive`. use crate::{ - archive::{error::Error as ArchiveError, ArchiveApiServer}, - common::events::{ArchiveStorageResult, PaginatedStorageQuery}, - hex_string, MethodResult, + archive::{ + archive_storage::ArchiveStorageDiff, error::Error as ArchiveError, ArchiveApiServer, + }, + common::{ + events::{ + ArchiveStorageDiffEvent, ArchiveStorageDiffItem, ArchiveStorageEvent, StorageQuery, + }, + storage::{QueryResult, StorageSubscriptionClient}, + }, + hex_string, MethodResult, SubscriptionTaskExecutor, }; use codec::Encode; -use jsonrpsee::core::{async_trait, RpcResult}; +use futures::FutureExt; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + PendingSubscriptionSink, +}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ChildInfo, ExecutorProvider, StorageKey, StorageProvider, }; +use sc_rpc::utils::Subscription; use sp_api::{CallApiAt, CallContext}; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, @@ -41,37 +53,15 @@ use sp_runtime::{ }; use std::{collections::HashSet, marker::PhantomData, sync::Arc}; -use super::archive_storage::ArchiveStorage; - -/// The configuration of [`Archive`]. -pub struct ArchiveConfig { - /// The maximum number of items the `archive_storage` can return for a descendant query before - /// pagination is required. - pub max_descendant_responses: usize, - /// The maximum number of queried items allowed for the `archive_storage` at a time. - pub max_queried_items: usize, -} +use tokio::sync::mpsc; -/// The maximum number of items the `archive_storage` can return for a descendant query before -/// pagination is required. -/// -/// Note: this is identical to the `chainHead` value. -const MAX_DESCENDANT_RESPONSES: usize = 5; +pub(crate) const LOG_TARGET: &str = "rpc-spec-v2::archive"; -/// The maximum number of queried items allowed for the `archive_storage` at a time. +/// The buffer capacity for each storage query. /// -/// Note: A queried item can also be a descendant query which can return up to -/// `MAX_DESCENDANT_RESPONSES`. -const MAX_QUERIED_ITEMS: usize = 8; - -impl Default for ArchiveConfig { - fn default() -> Self { - Self { - max_descendant_responses: MAX_DESCENDANT_RESPONSES, - max_queried_items: MAX_QUERIED_ITEMS, - } - } -} +/// This is small because the underlying JSON-RPC server has +/// its down buffer capacity per connection as well. +const STORAGE_QUERY_BUF: usize = 16; /// An API for archive RPC calls. pub struct Archive, Block: BlockT, Client> { @@ -79,13 +69,10 @@ pub struct Archive, Block: BlockT, Client> { client: Arc, /// Backend of the chain. backend: Arc, + /// Executor to spawn subscriptions. + executor: SubscriptionTaskExecutor, /// The hexadecimal encoded hash of the genesis block. genesis_hash: String, - /// The maximum number of items the `archive_storage` can return for a descendant query before - /// pagination is required. - storage_max_descendant_responses: usize, - /// The maximum number of queried items allowed for the `archive_storage` at a time. - storage_max_queried_items: usize, /// Phantom member to pin the block type. _phantom: PhantomData, } @@ -96,17 +83,10 @@ impl, Block: BlockT, Client> Archive { client: Arc, backend: Arc, genesis_hash: GenesisHash, - config: ArchiveConfig, + executor: SubscriptionTaskExecutor, ) -> Self { let genesis_hash = hex_string(&genesis_hash.as_ref()); - Self { - client, - backend, - genesis_hash, - storage_max_descendant_responses: config.max_descendant_responses, - storage_max_queried_items: config.max_queried_items, - _phantom: PhantomData, - } + Self { client, backend, executor, genesis_hash, _phantom: PhantomData } } } @@ -236,46 +216,157 @@ where fn archive_unstable_storage( &self, + pending: PendingSubscriptionSink, hash: Block::Hash, - items: Vec>, + items: Vec>, child_trie: Option, - ) -> RpcResult { - let items = items - .into_iter() - .map(|query| { - let key = StorageKey(parse_hex_param(query.key)?); - let pagination_start_key = query - .pagination_start_key - .map(|key| parse_hex_param(key).map(|key| StorageKey(key))) - .transpose()?; - - // Paginated start key is only supported - if pagination_start_key.is_some() && !query.query_type.is_descendant_query() { - return Err(ArchiveError::InvalidParam( - "Pagination start key is only supported for descendants queries" - .to_string(), - )) + ) { + let mut storage_client = + StorageSubscriptionClient::::new(self.client.clone()); + + let fut = async move { + let Ok(mut sink) = pending.accept().await.map(Subscription::from) else { return }; + + let items = match items + .into_iter() + .map(|query| { + let key = StorageKey(parse_hex_param(query.key)?); + Ok(StorageQuery { key, query_type: query.query_type }) + }) + .collect::, ArchiveError>>() + { + Ok(items) => items, + Err(error) => { + let _ = sink.send(&ArchiveStorageEvent::err(error.to_string())); + return + }, + }; + + let child_trie = child_trie.map(|child_trie| parse_hex_param(child_trie)).transpose(); + let child_trie = match child_trie { + Ok(child_trie) => child_trie.map(ChildInfo::new_default_from_vec), + Err(error) => { + let _ = sink.send(&ArchiveStorageEvent::err(error.to_string())); + return + }, + }; + + let (tx, mut rx) = tokio::sync::mpsc::channel(STORAGE_QUERY_BUF); + let storage_fut = storage_client.generate_events(hash, items, child_trie, tx); + + // We don't care about the return value of this join: + // - process_events might encounter an error (if the client disconnected) + // - storage_fut might encounter an error while processing a trie queries and + // the error is propagated via the sink. + let _ = futures::future::join(storage_fut, process_storage_events(&mut rx, &mut sink)) + .await; + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + } + + fn archive_unstable_storage_diff( + &self, + pending: PendingSubscriptionSink, + hash: Block::Hash, + items: Vec>, + previous_hash: Option, + ) { + let storage_client = ArchiveStorageDiff::new(self.client.clone()); + let client = self.client.clone(); + + log::trace!(target: LOG_TARGET, "Storage diff subscription started"); + + let fut = async move { + let Ok(mut sink) = pending.accept().await.map(Subscription::from) else { return }; + + let previous_hash = if let Some(previous_hash) = previous_hash { + previous_hash + } else { + let Ok(Some(current_header)) = client.header(hash) else { + let message = format!("Block header is not present: {hash}"); + let _ = sink.send(&ArchiveStorageDiffEvent::err(message)).await; + return + }; + *current_header.parent_hash() + }; + + let (tx, mut rx) = tokio::sync::mpsc::channel(STORAGE_QUERY_BUF); + let storage_fut = + storage_client.handle_trie_queries(hash, items, previous_hash, tx.clone()); + + // We don't care about the return value of this join: + // - process_events might encounter an error (if the client disconnected) + // - storage_fut might encounter an error while processing a trie queries and + // the error is propagated via the sink. + let _ = + futures::future::join(storage_fut, process_storage_diff_events(&mut rx, &mut sink)) + .await; + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + } +} + +/// Sends all the events of the storage_diff method to the sink. +async fn process_storage_diff_events( + rx: &mut mpsc::Receiver, + sink: &mut Subscription, +) { + loop { + tokio::select! { + _ = sink.closed() => { + return + }, + + maybe_event = rx.recv() => { + let Some(event) = maybe_event else { + break; + }; + + if event.is_done() { + log::debug!(target: LOG_TARGET, "Finished processing partial trie query"); + } else if event.is_err() { + log::debug!(target: LOG_TARGET, "Error encountered while processing partial trie query"); } - Ok(PaginatedStorageQuery { - key, - query_type: query.query_type, - pagination_start_key, - }) - }) - .collect::, ArchiveError>>()?; + if sink.send(&event).await.is_err() { + return + } + } + } + } +} - let child_trie = child_trie - .map(|child_trie| parse_hex_param(child_trie)) - .transpose()? - .map(ChildInfo::new_default_from_vec); +/// Sends all the events of the storage method to the sink. +async fn process_storage_events(rx: &mut mpsc::Receiver, sink: &mut Subscription) { + loop { + tokio::select! { + _ = sink.closed() => { + break + } + + maybe_storage = rx.recv() => { + let Some(event) = maybe_storage else { + break; + }; - let storage_client = ArchiveStorage::new( - self.client.clone(), - self.storage_max_descendant_responses, - self.storage_max_queried_items, - ); + match event { + Ok(None) => continue, - Ok(storage_client.handle_query(hash, items, child_trie)) + Ok(Some(event)) => + if sink.send(&ArchiveStorageEvent::result(event)).await.is_err() { + return + }, + + Err(error) => { + let _ = sink.send(&ArchiveStorageEvent::err(error)).await; + return + } + } + } + } } + + let _ = sink.send(&ArchiveStorageEvent::StorageDone).await; } diff --git a/substrate/client/rpc-spec-v2/src/archive/archive_storage.rs b/substrate/client/rpc-spec-v2/src/archive/archive_storage.rs index 26e7c299de41..390db765a48f 100644 --- a/substrate/client/rpc-spec-v2/src/archive/archive_storage.rs +++ b/substrate/client/rpc-spec-v2/src/archive/archive_storage.rs @@ -18,112 +18,832 @@ //! Implementation of the `archive_storage` method. -use std::sync::Arc; +use std::{ + collections::{hash_map::Entry, HashMap}, + sync::Arc, +}; +use itertools::Itertools; use sc_client_api::{Backend, ChildInfo, StorageKey, StorageProvider}; use sp_runtime::traits::Block as BlockT; -use crate::common::{ - events::{ArchiveStorageResult, PaginatedStorageQuery, StorageQueryType}, - storage::{IterQueryType, QueryIter, Storage}, +use super::error::Error as ArchiveError; +use crate::{ + archive::archive::LOG_TARGET, + common::{ + events::{ + ArchiveStorageDiffEvent, ArchiveStorageDiffItem, ArchiveStorageDiffOperationType, + ArchiveStorageDiffResult, ArchiveStorageDiffType, StorageResult, + }, + storage::Storage, + }, }; +use tokio::sync::mpsc; + +/// Parse hex-encoded string parameter as raw bytes. +/// +/// If the parsing fails, returns an error propagated to the RPC method. +pub fn parse_hex_param(param: String) -> Result, ArchiveError> { + // Methods can accept empty parameters. + if param.is_empty() { + return Ok(Default::default()) + } + + array_bytes::hex2bytes(¶m).map_err(|_| ArchiveError::InvalidParam(param)) +} + +#[derive(Debug, PartialEq, Clone)] +pub struct DiffDetails { + key: StorageKey, + return_type: ArchiveStorageDiffType, + child_trie_key: Option, + child_trie_key_string: Option, +} + +/// The type of storage query. +#[derive(Debug, PartialEq, Clone, Copy)] +enum FetchStorageType { + /// Only fetch the value. + Value, + /// Only fetch the hash. + Hash, + /// Fetch both the value and the hash. + Both, +} -/// Generates the events of the `archive_storage` method. -pub struct ArchiveStorage { - /// Storage client. +/// The return value of the `fetch_storage` method. +#[derive(Debug, PartialEq, Clone)] +enum FetchedStorage { + /// Storage value under a key. + Value(StorageResult), + /// Storage hash under a key. + Hash(StorageResult), + /// Both storage value and hash under a key. + Both { value: StorageResult, hash: StorageResult }, +} + +pub struct ArchiveStorageDiff { client: Storage, - /// The maximum number of responses the API can return for a descendant query at a time. - storage_max_descendant_responses: usize, - /// The maximum number of queried items allowed for the `archive_storage` at a time. - storage_max_queried_items: usize, } -impl ArchiveStorage { - /// Constructs a new [`ArchiveStorage`]. - pub fn new( - client: Arc, - storage_max_descendant_responses: usize, - storage_max_queried_items: usize, - ) -> Self { - Self { - client: Storage::new(client), - storage_max_descendant_responses, - storage_max_queried_items, - } +impl ArchiveStorageDiff { + pub fn new(client: Arc) -> Self { + Self { client: Storage::new(client) } } } -impl ArchiveStorage +impl ArchiveStorageDiff where Block: BlockT + 'static, BE: Backend + 'static, - Client: StorageProvider + 'static, + Client: StorageProvider + Send + Sync + 'static, { - /// Generate the response of the `archive_storage` method. - pub fn handle_query( + /// Fetch the storage from the given key. + fn fetch_storage( &self, hash: Block::Hash, - mut items: Vec>, - child_key: Option, - ) -> ArchiveStorageResult { - let discarded_items = items.len().saturating_sub(self.storage_max_queried_items); - items.truncate(self.storage_max_queried_items); + key: StorageKey, + maybe_child_trie: Option, + ty: FetchStorageType, + ) -> Result, String> { + match ty { + FetchStorageType::Value => { + let result = self.client.query_value(hash, &key, maybe_child_trie.as_ref())?; + + Ok(result.map(FetchedStorage::Value)) + }, + + FetchStorageType::Hash => { + let result = self.client.query_hash(hash, &key, maybe_child_trie.as_ref())?; + + Ok(result.map(FetchedStorage::Hash)) + }, + + FetchStorageType::Both => { + let Some(value) = self.client.query_value(hash, &key, maybe_child_trie.as_ref())? + else { + return Ok(None); + }; + + let Some(hash) = self.client.query_hash(hash, &key, maybe_child_trie.as_ref())? + else { + return Ok(None); + }; + + Ok(Some(FetchedStorage::Both { value, hash })) + }, + } + } + + /// Check if the key belongs to the provided query items. + /// + /// A key belongs to the query items when: + /// - the provided key is a prefix of the key in the query items. + /// - the query items are empty. + /// + /// Returns an optional `FetchStorageType` based on the query items. + /// If the key does not belong to the query items, returns `None`. + fn belongs_to_query(key: &StorageKey, items: &[DiffDetails]) -> Option { + // User has requested all keys, by default this fallbacks to fetching the value. + if items.is_empty() { + return Some(FetchStorageType::Value) + } + + let mut value = false; + let mut hash = false; - let mut storage_results = Vec::with_capacity(items.len()); for item in items { - match item.query_type { - StorageQueryType::Value => { - match self.client.query_value(hash, &item.key, child_key.as_ref()) { - Ok(Some(value)) => storage_results.push(value), - Ok(None) => continue, - Err(error) => return ArchiveStorageResult::err(error), - } - }, - StorageQueryType::Hash => - match self.client.query_hash(hash, &item.key, child_key.as_ref()) { - Ok(Some(value)) => storage_results.push(value), - Ok(None) => continue, - Err(error) => return ArchiveStorageResult::err(error), - }, - StorageQueryType::ClosestDescendantMerkleValue => - match self.client.query_merkle_value(hash, &item.key, child_key.as_ref()) { - Ok(Some(value)) => storage_results.push(value), - Ok(None) => continue, - Err(error) => return ArchiveStorageResult::err(error), - }, - StorageQueryType::DescendantsValues => { - match self.client.query_iter_pagination( - QueryIter { - query_key: item.key, - ty: IterQueryType::Value, - pagination_start_key: item.pagination_start_key, - }, + if key.as_ref().starts_with(&item.key.as_ref()) { + match item.return_type { + ArchiveStorageDiffType::Value => value = true, + ArchiveStorageDiffType::Hash => hash = true, + } + } + } + + match (value, hash) { + (true, true) => Some(FetchStorageType::Both), + (true, false) => Some(FetchStorageType::Value), + (false, true) => Some(FetchStorageType::Hash), + (false, false) => None, + } + } + + /// Send the provided result to the `tx` sender. + /// + /// Returns `false` if the sender has been closed. + fn send_result( + tx: &mpsc::Sender, + result: FetchedStorage, + operation_type: ArchiveStorageDiffOperationType, + child_trie_key: Option, + ) -> bool { + let items = match result { + FetchedStorage::Value(storage_result) | FetchedStorage::Hash(storage_result) => + vec![storage_result], + FetchedStorage::Both { value, hash } => vec![value, hash], + }; + + for item in items { + let res = ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: item.key, + result: item.result, + operation_type, + child_trie_key: child_trie_key.clone(), + }); + if tx.blocking_send(res).is_err() { + return false + } + } + + true + } + + fn handle_trie_queries_inner( + &self, + hash: Block::Hash, + previous_hash: Block::Hash, + items: Vec, + tx: &mpsc::Sender, + ) -> Result<(), String> { + // Parse the child trie key as `ChildInfo` and `String`. + let maybe_child_trie = items.first().and_then(|item| item.child_trie_key.clone()); + let maybe_child_trie_str = + items.first().and_then(|item| item.child_trie_key_string.clone()); + + // Iterator over the current block and previous block + // at the same time to compare the keys. This approach effectively + // leverages backpressure to avoid memory consumption. + let keys_iter = self.client.raw_keys_iter(hash, maybe_child_trie.clone())?; + let previous_keys_iter = + self.client.raw_keys_iter(previous_hash, maybe_child_trie.clone())?; + + let mut diff_iter = lexicographic_diff(keys_iter, previous_keys_iter); + + while let Some(item) = diff_iter.next() { + let (operation_type, key) = match item { + Diff::Added(key) => (ArchiveStorageDiffOperationType::Added, key), + Diff::Deleted(key) => (ArchiveStorageDiffOperationType::Deleted, key), + Diff::Equal(key) => (ArchiveStorageDiffOperationType::Modified, key), + }; + + let Some(fetch_type) = Self::belongs_to_query(&key, &items) else { + // The key does not belong the the query items. + continue; + }; + + let maybe_result = match operation_type { + ArchiveStorageDiffOperationType::Added => + self.fetch_storage(hash, key.clone(), maybe_child_trie.clone(), fetch_type)?, + ArchiveStorageDiffOperationType::Deleted => self.fetch_storage( + previous_hash, + key.clone(), + maybe_child_trie.clone(), + fetch_type, + )?, + ArchiveStorageDiffOperationType::Modified => { + let Some(storage_result) = self.fetch_storage( hash, - child_key.as_ref(), - self.storage_max_descendant_responses, - ) { - Ok((results, _)) => storage_results.extend(results), - Err(error) => return ArchiveStorageResult::err(error), + key.clone(), + maybe_child_trie.clone(), + fetch_type, + )? + else { + continue + }; + + let Some(previous_storage_result) = self.fetch_storage( + previous_hash, + key.clone(), + maybe_child_trie.clone(), + fetch_type, + )? + else { + continue + }; + + // For modified records we need to check the actual storage values. + if storage_result == previous_storage_result { + continue } + + Some(storage_result) }, - StorageQueryType::DescendantsHashes => { - match self.client.query_iter_pagination( - QueryIter { - query_key: item.key, - ty: IterQueryType::Hash, - pagination_start_key: item.pagination_start_key, - }, - hash, - child_key.as_ref(), - self.storage_max_descendant_responses, - ) { - Ok((results, _)) => storage_results.extend(results), - Err(error) => return ArchiveStorageResult::err(error), - } + }; + + if let Some(storage_result) = maybe_result { + if !Self::send_result( + &tx, + storage_result, + operation_type, + maybe_child_trie_str.clone(), + ) { + return Ok(()) + } + } + } + + Ok(()) + } + + /// This method will iterate over the keys of the main trie or a child trie and fetch the + /// given keys. The fetched keys will be sent to the provided `tx` sender to leverage + /// the backpressure mechanism. + pub async fn handle_trie_queries( + &self, + hash: Block::Hash, + items: Vec>, + previous_hash: Block::Hash, + tx: mpsc::Sender, + ) -> Result<(), tokio::task::JoinError> { + let this = ArchiveStorageDiff { client: self.client.clone() }; + + tokio::task::spawn_blocking(move || { + // Deduplicate the items. + let mut trie_items = match deduplicate_storage_diff_items(items) { + Ok(items) => items, + Err(error) => { + let _ = tx.blocking_send(ArchiveStorageDiffEvent::err(error.to_string())); + return }, }; + // Default to using the main storage trie if no items are provided. + if trie_items.is_empty() { + trie_items.push(Vec::new()); + } + log::trace!(target: LOG_TARGET, "Storage diff deduplicated items: {:?}", trie_items); + + for items in trie_items { + log::trace!( + target: LOG_TARGET, + "handle_trie_queries: hash={:?}, previous_hash={:?}, items={:?}", + hash, + previous_hash, + items + ); + + let result = this.handle_trie_queries_inner(hash, previous_hash, items, &tx); + + if let Err(error) = result { + log::trace!( + target: LOG_TARGET, + "handle_trie_queries: sending error={:?}", + error, + ); + + let _ = tx.blocking_send(ArchiveStorageDiffEvent::err(error)); + + return + } else { + log::trace!( + target: LOG_TARGET, + "handle_trie_queries: sending storage diff done", + ); + } + } + + let _ = tx.blocking_send(ArchiveStorageDiffEvent::StorageDiffDone); + }) + .await?; + + Ok(()) + } +} + +/// The result of the `lexicographic_diff` method. +#[derive(Debug, PartialEq)] +enum Diff { + Added(T), + Deleted(T), + Equal(T), +} + +/// Compare two iterators lexicographically and return the differences. +fn lexicographic_diff( + mut left: LeftIter, + mut right: RightIter, +) -> impl Iterator> +where + T: Ord, + LeftIter: Iterator, + RightIter: Iterator, +{ + let mut a = left.next(); + let mut b = right.next(); + + core::iter::from_fn(move || match (a.take(), b.take()) { + (Some(a_value), Some(b_value)) => + if a_value < b_value { + b = Some(b_value); + a = left.next(); + + Some(Diff::Added(a_value)) + } else if a_value > b_value { + a = Some(a_value); + b = right.next(); + + Some(Diff::Deleted(b_value)) + } else { + a = left.next(); + b = right.next(); + + Some(Diff::Equal(a_value)) + }, + (Some(a_value), None) => { + a = left.next(); + Some(Diff::Added(a_value)) + }, + (None, Some(b_value)) => { + b = right.next(); + Some(Diff::Deleted(b_value)) + }, + (None, None) => None, + }) +} + +/// Deduplicate the provided items and return a list of `DiffDetails`. +/// +/// Each list corresponds to a single child trie or the main trie. +fn deduplicate_storage_diff_items( + items: Vec>, +) -> Result>, ArchiveError> { + let mut deduplicated: HashMap, Vec> = HashMap::new(); + + for diff_item in items { + // Ensure the provided hex keys are valid before deduplication. + let key = StorageKey(parse_hex_param(diff_item.key)?); + let child_trie_key_string = diff_item.child_trie_key.clone(); + let child_trie_key = diff_item + .child_trie_key + .map(|child_trie_key| parse_hex_param(child_trie_key)) + .transpose()? + .map(ChildInfo::new_default_from_vec); + + let diff_item = DiffDetails { + key, + return_type: diff_item.return_type, + child_trie_key: child_trie_key.clone(), + child_trie_key_string, + }; + + match deduplicated.entry(child_trie_key.clone()) { + Entry::Occupied(mut entry) => { + let mut should_insert = true; + + for existing in entry.get() { + // This points to a different return type. + if existing.return_type != diff_item.return_type { + continue + } + // Keys and return types are identical. + if existing.key == diff_item.key { + should_insert = false; + break + } + + // The following two conditions ensure that we keep the shortest key. + + // The current key is a longer prefix of the existing key. + if diff_item.key.as_ref().starts_with(&existing.key.as_ref()) { + should_insert = false; + break + } + + // The existing key is a longer prefix of the current key. + // We need to keep the current key and remove the existing one. + if existing.key.as_ref().starts_with(&diff_item.key.as_ref()) { + let to_remove = existing.clone(); + entry.get_mut().retain(|item| item != &to_remove); + break; + } + } + + if should_insert { + entry.get_mut().push(diff_item); + } + }, + Entry::Vacant(entry) => { + entry.insert(vec![diff_item]); + }, } + } + + Ok(deduplicated + .into_iter() + .sorted_by_key(|(child_trie_key, _)| child_trie_key.clone()) + .map(|(_, values)| values) + .collect()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn dedup_empty() { + let items = vec![]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert!(result.is_empty()); + } + + #[test] + fn dedup_single() { + let items = vec![ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 1); + + let expected = DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }; + assert_eq!(result[0][0], expected); + } + + #[test] + fn dedup_with_different_keys() { + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem { + key: "0x02".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 2); + + let expected = vec![ + DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }, + DiffDetails { + key: StorageKey(vec![2]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }, + ]; + assert_eq!(result[0], expected); + } + + #[test] + fn dedup_with_same_keys() { + // Identical keys. + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 1); + + let expected = vec![DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }]; + assert_eq!(result[0], expected); + } + + #[test] + fn dedup_with_same_prefix() { + // Identical keys. + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem { + key: "0x01ff".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 1); + + let expected = vec![DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }]; + assert_eq!(result[0], expected); + } + + #[test] + fn dedup_with_different_return_types() { + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: None, + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 2); + + let expected = vec![ + DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }, + DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: None, + child_trie_key_string: None, + }, + ]; + assert_eq!(result[0], expected); + } + + #[test] + fn dedup_with_different_child_tries() { + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x01".into()), + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x02".into()), + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 2); + assert_eq!(result[0].len(), 1); + assert_eq!(result[1].len(), 1); + + let expected = vec![ + vec![DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![1])), + child_trie_key_string: Some("0x01".into()), + }], + vec![DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![2])), + child_trie_key_string: Some("0x02".into()), + }], + ]; + assert_eq!(result, expected); + } + + #[test] + fn dedup_with_same_child_tries() { + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x01".into()), + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x01".into()), + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 1); + + let expected = vec![DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![1])), + child_trie_key_string: Some("0x01".into()), + }]; + assert_eq!(result[0], expected); + } + + #[test] + fn dedup_with_shorter_key_reverse_order() { + let items = vec![ + ArchiveStorageDiffItem { + key: "0x01ff".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ]; + let result = deduplicate_storage_diff_items(items).unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].len(), 1); + + let expected = vec![DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }]; + assert_eq!(result[0], expected); + } + + #[test] + fn dedup_multiple_child_tries() { + let items = vec![ + ArchiveStorageDiffItem { + key: "0x02".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x01".into()), + }, + ArchiveStorageDiffItem { + key: "0x02".into(), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: Some("0x01".into()), + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x02".into()), + }, + ArchiveStorageDiffItem { + key: "0x01".into(), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: Some("0x02".into()), + }, + ArchiveStorageDiffItem { + key: "0x01ff".into(), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x02".into()), + }, + ]; + + let result = deduplicate_storage_diff_items(items).unwrap(); + + let expected = vec![ + vec![DiffDetails { + key: StorageKey(vec![2]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + child_trie_key_string: None, + }], + vec![ + DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![1])), + child_trie_key_string: Some("0x01".into()), + }, + DiffDetails { + key: StorageKey(vec![2]), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![1])), + child_trie_key_string: Some("0x01".into()), + }, + ], + vec![ + DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![2])), + child_trie_key_string: Some("0x02".into()), + }, + DiffDetails { + key: StorageKey(vec![1]), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: Some(ChildInfo::new_default_from_vec(vec![2])), + child_trie_key_string: Some("0x02".into()), + }, + ], + ]; + + assert_eq!(result, expected); + } + + #[test] + fn test_lexicographic_diff() { + let left = vec![1, 2, 3, 4, 5]; + let right = vec![2, 3, 4, 5, 6]; + + let diff = lexicographic_diff(left.into_iter(), right.into_iter()).collect::>(); + let expected = vec![ + Diff::Added(1), + Diff::Equal(2), + Diff::Equal(3), + Diff::Equal(4), + Diff::Equal(5), + Diff::Deleted(6), + ]; + assert_eq!(diff, expected); + } + + #[test] + fn test_lexicographic_diff_one_side_empty() { + let left = vec![]; + let right = vec![1, 2, 3, 4, 5, 6]; + + let diff = lexicographic_diff(left.into_iter(), right.into_iter()).collect::>(); + let expected = vec![ + Diff::Deleted(1), + Diff::Deleted(2), + Diff::Deleted(3), + Diff::Deleted(4), + Diff::Deleted(5), + Diff::Deleted(6), + ]; + assert_eq!(diff, expected); + + let left = vec![1, 2, 3, 4, 5, 6]; + let right = vec![]; - ArchiveStorageResult::ok(storage_results, discarded_items) + let diff = lexicographic_diff(left.into_iter(), right.into_iter()).collect::>(); + let expected = vec![ + Diff::Added(1), + Diff::Added(2), + Diff::Added(3), + Diff::Added(4), + Diff::Added(5), + Diff::Added(6), + ]; + assert_eq!(diff, expected); } } diff --git a/substrate/client/rpc-spec-v2/src/archive/mod.rs b/substrate/client/rpc-spec-v2/src/archive/mod.rs index 5f020c203eab..14fa104c113a 100644 --- a/substrate/client/rpc-spec-v2/src/archive/mod.rs +++ b/substrate/client/rpc-spec-v2/src/archive/mod.rs @@ -32,4 +32,4 @@ pub mod archive; pub mod error; pub use api::ArchiveApiServer; -pub use archive::{Archive, ArchiveConfig}; +pub use archive::Archive; diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs index 078016f5b3e2..48cbbaa4934a 100644 --- a/substrate/client/rpc-spec-v2/src/archive/tests.rs +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -18,24 +18,25 @@ use crate::{ common::events::{ - ArchiveStorageMethodOk, ArchiveStorageResult, PaginatedStorageQuery, StorageQueryType, - StorageResultType, + ArchiveStorageDiffEvent, ArchiveStorageDiffItem, ArchiveStorageDiffOperationType, + ArchiveStorageDiffResult, ArchiveStorageDiffType, ArchiveStorageEvent, StorageQuery, + StorageQueryType, StorageResult, StorageResultType, }, hex_string, MethodResult, }; -use super::{ - archive::{Archive, ArchiveConfig}, - *, -}; +use super::{archive::Archive, *}; use assert_matches::assert_matches; use codec::{Decode, Encode}; use jsonrpsee::{ - core::EmptyServerParams as EmptyParams, rpc_params, MethodsError as Error, RpcModule, + core::{server::Subscription as RpcSubscription, EmptyServerParams as EmptyParams}, + rpc_params, MethodsError as Error, RpcModule, }; + use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; +use sc_rpc::testing::TokioTestExecutor; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_core::{Blake2Hasher, Hasher}; @@ -51,8 +52,6 @@ use substrate_test_runtime_client::{ const CHAIN_GENESIS: [u8; 32] = [0; 32]; const INVALID_HASH: [u8; 32] = [1; 32]; -const MAX_PAGINATION_LIMIT: usize = 5; -const MAX_QUERIED_LIMIT: usize = 5; const KEY: &[u8] = b":mock"; const VALUE: &[u8] = b"hello world"; const CHILD_STORAGE_KEY: &[u8] = b"child"; @@ -61,10 +60,7 @@ const CHILD_VALUE: &[u8] = b"child value"; type Header = substrate_test_runtime_client::runtime::Header; type Block = substrate_test_runtime_client::runtime::Block; -fn setup_api( - max_descendant_responses: usize, - max_queried_items: usize, -) -> (Arc>, RpcModule>>) { +fn setup_api() -> (Arc>, RpcModule>>) { let child_info = ChildInfo::new_default(CHILD_STORAGE_KEY); let builder = TestClientBuilder::new().add_extra_child_storage( &child_info, @@ -78,16 +74,25 @@ fn setup_api( client.clone(), backend, CHAIN_GENESIS, - ArchiveConfig { max_descendant_responses, max_queried_items }, + Arc::new(TokioTestExecutor::default()), ) .into_rpc(); (client, api) } +async fn get_next_event(sub: &mut RpcSubscription) -> T { + let (event, _sub_id) = tokio::time::timeout(std::time::Duration::from_secs(60), sub.next()) + .await + .unwrap() + .unwrap() + .unwrap(); + event +} + #[tokio::test] async fn archive_genesis() { - let (_client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (_client, api) = setup_api(); let genesis: String = api.call("archive_unstable_genesisHash", EmptyParams::new()).await.unwrap(); @@ -96,7 +101,7 @@ async fn archive_genesis() { #[tokio::test] async fn archive_body() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); // Invalid block hash. let invalid_hash = hex_string(&INVALID_HASH); @@ -112,8 +117,8 @@ async fn archive_body() { builder .push_transfer(runtime::Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42, nonce: 0, }) @@ -130,7 +135,7 @@ async fn archive_body() { #[tokio::test] async fn archive_header() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); // Invalid block hash. let invalid_hash = hex_string(&INVALID_HASH); @@ -146,8 +151,8 @@ async fn archive_header() { builder .push_transfer(runtime::Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42, nonce: 0, }) @@ -164,7 +169,7 @@ async fn archive_header() { #[tokio::test] async fn archive_finalized_height() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); let client_height: u32 = client.info().finalized_number.saturated_into(); @@ -176,7 +181,7 @@ async fn archive_finalized_height() { #[tokio::test] async fn archive_hash_by_height() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); // Genesis height. let hashes: Vec = api.call("archive_unstable_hashByHeight", [0]).await.unwrap(); @@ -244,8 +249,8 @@ async fn archive_hash_by_height() { // imported block_builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -282,7 +287,7 @@ async fn archive_hash_by_height() { #[tokio::test] async fn archive_call() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); let invalid_hash = hex_string(&INVALID_HASH); // Invalid parameter (non-hex). @@ -325,7 +330,7 @@ async fn archive_call() { client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); // Valid call. - let alice_id = AccountKeyring::Alice.to_account_id(); + let alice_id = Sr25519Keyring::Alice.to_account_id(); // Hex encoded scale encoded bytes representing the call parameters. let call_parameters = hex_string(&alice_id.encode()); let result: MethodResult = api @@ -341,7 +346,7 @@ async fn archive_call() { #[tokio::test] async fn archive_storage_hashes_values() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); let block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().genesis_hash) @@ -355,42 +360,23 @@ async fn archive_storage_hashes_values() { let block_hash = format!("{:?}", block.header.hash()); let key = hex_string(&KEY); - let items: Vec> = vec![ - PaginatedStorageQuery { - key: key.clone(), - query_type: StorageQueryType::DescendantsHashes, - pagination_start_key: None, - }, - PaginatedStorageQuery { - key: key.clone(), - query_type: StorageQueryType::DescendantsValues, - pagination_start_key: None, - }, - PaginatedStorageQuery { - key: key.clone(), - query_type: StorageQueryType::Hash, - pagination_start_key: None, - }, - PaginatedStorageQuery { - key: key.clone(), - query_type: StorageQueryType::Value, - pagination_start_key: None, - }, + let items: Vec> = vec![ + StorageQuery { key: key.clone(), query_type: StorageQueryType::DescendantsHashes }, + StorageQuery { key: key.clone(), query_type: StorageQueryType::DescendantsValues }, + StorageQuery { key: key.clone(), query_type: StorageQueryType::Hash }, + StorageQuery { key: key.clone(), query_type: StorageQueryType::Value }, ]; - let result: ArchiveStorageResult = api - .call("archive_unstable_storage", rpc_params![&block_hash, items.clone()]) + let mut sub = api + .subscribe_unbounded("archive_unstable_storage", rpc_params![&block_hash, items.clone()]) .await .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - // Key has not been imported yet. - assert_eq!(result.len(), 0); - assert_eq!(discarded_items, 0); - }, - _ => panic!("Unexpected result"), - }; + // Key has not been imported yet. + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::StorageDone, + ); // Import a block with the given key value pair. let mut builder = BlockBuilderBuilder::new(&*client) @@ -406,32 +392,103 @@ async fn archive_storage_hashes_values() { let expected_hash = format!("{:?}", Blake2Hasher::hash(&VALUE)); let expected_value = hex_string(&VALUE); - let result: ArchiveStorageResult = api - .call("archive_unstable_storage", rpc_params![&block_hash, items]) + let mut sub = api + .subscribe_unbounded("archive_unstable_storage", rpc_params![&block_hash, items]) .await .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 4); - assert_eq!(discarded_items, 0); - - assert_eq!(result[0].key, key); - assert_eq!(result[0].result, StorageResultType::Hash(expected_hash.clone())); - assert_eq!(result[1].key, key); - assert_eq!(result[1].result, StorageResultType::Value(expected_value.clone())); - assert_eq!(result[2].key, key); - assert_eq!(result[2].result, StorageResultType::Hash(expected_hash)); - assert_eq!(result[3].key, key); - assert_eq!(result[3].result, StorageResultType::Value(expected_value)); - }, - _ => panic!("Unexpected result"), - }; + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: key.clone(), + result: StorageResultType::Hash(expected_hash.clone()), + child_trie_key: None, + }), + ); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: key.clone(), + result: StorageResultType::Value(expected_value.clone()), + child_trie_key: None, + }), + ); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: key.clone(), + result: StorageResultType::Hash(expected_hash), + child_trie_key: None, + }), + ); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: key.clone(), + result: StorageResultType::Value(expected_value), + child_trie_key: None, + }), + ); + + assert_matches!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::StorageDone + ); +} + +#[tokio::test] +async fn archive_storage_hashes_values_child_trie() { + let (client, api) = setup_api(); + + // Get child storage values set in `setup_api`. + let child_info = hex_string(&CHILD_STORAGE_KEY); + let key = hex_string(&KEY); + let genesis_hash = format!("{:?}", client.genesis_hash()); + let expected_hash = format!("{:?}", Blake2Hasher::hash(&CHILD_VALUE)); + let expected_value = hex_string(&CHILD_VALUE); + + let items: Vec> = vec![ + StorageQuery { key: key.clone(), query_type: StorageQueryType::DescendantsHashes }, + StorageQuery { key: key.clone(), query_type: StorageQueryType::DescendantsValues }, + ]; + let mut sub = api + .subscribe_unbounded( + "archive_unstable_storage", + rpc_params![&genesis_hash, items, &child_info], + ) + .await + .unwrap(); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: key.clone(), + result: StorageResultType::Hash(expected_hash.clone()), + child_trie_key: Some(child_info.clone()), + }) + ); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: key.clone(), + result: StorageResultType::Value(expected_value.clone()), + child_trie_key: Some(child_info.clone()), + }) + ); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::StorageDone, + ); } #[tokio::test] async fn archive_storage_closest_merkle_value() { - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); /// The core of this test. /// @@ -443,55 +500,47 @@ async fn archive_storage_closest_merkle_value() { api: &RpcModule>>, block_hash: String, ) -> HashMap { - let result: ArchiveStorageResult = api - .call( + let mut sub = api + .subscribe_unbounded( "archive_unstable_storage", rpc_params![ &block_hash, vec![ - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AAAA"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AAAB"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, // Key with descendant. - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":A"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AA"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, // Keys below this comment do not produce a result. // Key that exceed the keyspace of the trie. - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AAAAX"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AAABX"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, // Key that are not part of the trie. - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AAX"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, - PaginatedStorageQuery { + StorageQuery { key: hex_string(b":AAAX"), query_type: StorageQueryType::ClosestDescendantMerkleValue, - pagination_start_key: None, }, ] ], @@ -499,19 +548,21 @@ async fn archive_storage_closest_merkle_value() { .await .unwrap(); - let merkle_values: HashMap<_, _> = match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, .. }) => result - .into_iter() - .map(|res| { - let value = match res.result { + let mut merkle_values = HashMap::new(); + loop { + let event = get_next_event::(&mut sub).await; + match event { + ArchiveStorageEvent::Storage(result) => { + let str_result = match result.result { StorageResultType::ClosestDescendantMerkleValue(value) => value, - _ => panic!("Unexpected StorageResultType"), + _ => panic!("Unexpected result type"), }; - (res.key, value) - }) - .collect(), - _ => panic!("Unexpected result"), - }; + merkle_values.insert(result.key, str_result); + }, + ArchiveStorageEvent::StorageError(err) => panic!("Unexpected error {err:?}"), + ArchiveStorageEvent::StorageDone => break, + } + } // Response for AAAA, AAAB, A and AA. assert_eq!(merkle_values.len(), 4); @@ -590,9 +641,9 @@ async fn archive_storage_closest_merkle_value() { } #[tokio::test] -async fn archive_storage_paginate_iterations() { +async fn archive_storage_iterations() { // 1 iteration allowed before pagination kicks in. - let (client, api) = setup_api(1, MAX_QUERIED_LIMIT); + let (client, api) = setup_api(); // Import a new block with storage changes. let mut builder = BlockBuilderBuilder::new(&*client) @@ -611,230 +662,344 @@ async fn archive_storage_paginate_iterations() { // Calling with an invalid hash. let invalid_hash = hex_string(&INVALID_HASH); - let result: ArchiveStorageResult = api - .call( + let mut sub = api + .subscribe_unbounded( "archive_unstable_storage", rpc_params![ &invalid_hash, - vec![PaginatedStorageQuery { + vec![StorageQuery { key: hex_string(b":m"), query_type: StorageQueryType::DescendantsValues, - pagination_start_key: None, }] ], ) .await .unwrap(); - match result { - ArchiveStorageResult::Err(_) => (), - _ => panic!("Unexpected result"), - }; + + assert_matches!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::StorageError(_) + ); // Valid call with storage at the key. - let result: ArchiveStorageResult = api - .call( + let mut sub = api + .subscribe_unbounded( "archive_unstable_storage", rpc_params![ &block_hash, - vec![PaginatedStorageQuery { + vec![StorageQuery { key: hex_string(b":m"), query_type: StorageQueryType::DescendantsValues, - pagination_start_key: None, }] ], ) .await .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 1); - assert_eq!(discarded_items, 0); - assert_eq!(result[0].key, hex_string(b":m")); - assert_eq!(result[0].result, StorageResultType::Value(hex_string(b"a"))); - }, - _ => panic!("Unexpected result"), - }; + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: hex_string(b":m"), + result: StorageResultType::Value(hex_string(b"a")), + child_trie_key: None, + }) + ); - // Continue with pagination. - let result: ArchiveStorageResult = api - .call( - "archive_unstable_storage", - rpc_params![ - &block_hash, - vec![PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::DescendantsValues, - pagination_start_key: Some(hex_string(b":m")), - }] - ], - ) - .await - .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 1); - assert_eq!(discarded_items, 0); + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: hex_string(b":mo"), + result: StorageResultType::Value(hex_string(b"ab")), + child_trie_key: None, + }) + ); - assert_eq!(result[0].key, hex_string(b":mo")); - assert_eq!(result[0].result, StorageResultType::Value(hex_string(b"ab"))); - }, - _ => panic!("Unexpected result"), - }; + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: hex_string(b":moD"), + result: StorageResultType::Value(hex_string(b"abcmoD")), + child_trie_key: None, + }) + ); - // Continue with pagination. - let result: ArchiveStorageResult = api - .call( - "archive_unstable_storage", - rpc_params![ - &block_hash, - vec![PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::DescendantsValues, - pagination_start_key: Some(hex_string(b":mo")), - }] - ], - ) - .await + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: hex_string(b":moc"), + result: StorageResultType::Value(hex_string(b"abc")), + child_trie_key: None, + }) + ); + + assert_eq!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::Storage(StorageResult { + key: hex_string(b":mock"), + result: StorageResultType::Value(hex_string(b"abcd")), + child_trie_key: None, + }) + ); + + assert_matches!( + get_next_event::(&mut sub).await, + ArchiveStorageEvent::StorageDone + ); +} + +#[tokio::test] +async fn archive_storage_diff_main_trie() { + let (client, api) = setup_api(); + + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 1); - assert_eq!(discarded_items, 0); + builder.push_storage_change(b":A".to_vec(), Some(b"B".to_vec())).unwrap(); + builder.push_storage_change(b":AA".to_vec(), Some(b"BB".to_vec())).unwrap(); + let prev_block = builder.build().unwrap().block; + let prev_hash = format!("{:?}", prev_block.header.hash()); + client.import(BlockOrigin::Own, prev_block.clone()).await.unwrap(); - assert_eq!(result[0].key, hex_string(b":moD")); - assert_eq!(result[0].result, StorageResultType::Value(hex_string(b"abcmoD"))); - }, - _ => panic!("Unexpected result"), - }; + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(prev_block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); + builder.push_storage_change(b":A".to_vec(), Some(b"11".to_vec())).unwrap(); + builder.push_storage_change(b":AA".to_vec(), Some(b"22".to_vec())).unwrap(); + builder.push_storage_change(b":AAA".to_vec(), Some(b"222".to_vec())).unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); - // Continue with pagination. - let result: ArchiveStorageResult = api - .call( - "archive_unstable_storage", - rpc_params![ - &block_hash, - vec![PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::DescendantsValues, - pagination_start_key: Some(hex_string(b":moD")), - }] - ], + // Search for items in the main trie: + // - values of keys under ":A" + // - hashes of keys under ":AA" + let items = vec![ + ArchiveStorageDiffItem:: { + key: hex_string(b":A"), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }, + ArchiveStorageDiffItem:: { + key: hex_string(b":AA"), + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: None, + }, + ]; + let mut sub = api + .subscribe_unbounded( + "archive_unstable_storageDiff", + rpc_params![&block_hash, items.clone(), &prev_hash], ) .await .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 1); - assert_eq!(discarded_items, 0); - assert_eq!(result[0].key, hex_string(b":moc")); - assert_eq!(result[0].result, StorageResultType::Value(hex_string(b"abc"))); - }, - _ => panic!("Unexpected result"), - }; + let event = get_next_event::(&mut sub).await; + assert_eq!( + ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: hex_string(b":A"), + result: StorageResultType::Value(hex_string(b"11")), + operation_type: ArchiveStorageDiffOperationType::Modified, + child_trie_key: None, + }), + event, + ); - // Continue with pagination. - let result: ArchiveStorageResult = api - .call( - "archive_unstable_storage", - rpc_params![ - &block_hash, - vec![PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::DescendantsValues, - pagination_start_key: Some(hex_string(b":moc")), - }] - ], - ) - .await + let event = get_next_event::(&mut sub).await; + assert_eq!( + ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: hex_string(b":AA"), + result: StorageResultType::Value(hex_string(b"22")), + operation_type: ArchiveStorageDiffOperationType::Modified, + child_trie_key: None, + }), + event, + ); + + let event = get_next_event::(&mut sub).await; + assert_eq!( + ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: hex_string(b":AA"), + result: StorageResultType::Hash(format!("{:?}", Blake2Hasher::hash(b"22"))), + operation_type: ArchiveStorageDiffOperationType::Modified, + child_trie_key: None, + }), + event, + ); + + // Added key. + let event = get_next_event::(&mut sub).await; + assert_eq!( + ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: hex_string(b":AAA"), + result: StorageResultType::Value(hex_string(b"222")), + operation_type: ArchiveStorageDiffOperationType::Added, + child_trie_key: None, + }), + event, + ); + + let event = get_next_event::(&mut sub).await; + assert_eq!( + ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: hex_string(b":AAA"), + result: StorageResultType::Hash(format!("{:?}", Blake2Hasher::hash(b"222"))), + operation_type: ArchiveStorageDiffOperationType::Added, + child_trie_key: None, + }), + event, + ); + + let event = get_next_event::(&mut sub).await; + assert_eq!(ArchiveStorageDiffEvent::StorageDiffDone, event); +} + +#[tokio::test] +async fn archive_storage_diff_no_changes() { + let (client, api) = setup_api(); + + // Build 2 identical blocks. + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 1); - assert_eq!(discarded_items, 0); + builder.push_storage_change(b":A".to_vec(), Some(b"B".to_vec())).unwrap(); + builder.push_storage_change(b":AA".to_vec(), Some(b"BB".to_vec())).unwrap(); + builder.push_storage_change(b":B".to_vec(), Some(b"CC".to_vec())).unwrap(); + builder.push_storage_change(b":BA".to_vec(), Some(b"CC".to_vec())).unwrap(); + let prev_block = builder.build().unwrap().block; + let prev_hash = format!("{:?}", prev_block.header.hash()); + client.import(BlockOrigin::Own, prev_block.clone()).await.unwrap(); - assert_eq!(result[0].key, hex_string(b":mock")); - assert_eq!(result[0].result, StorageResultType::Value(hex_string(b"abcd"))); - }, - _ => panic!("Unexpected result"), - }; + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(prev_block.hash()) + .with_parent_block_number(1) + .build() + .unwrap(); + builder.push_storage_change(b":A".to_vec(), Some(b"B".to_vec())).unwrap(); + builder.push_storage_change(b":AA".to_vec(), Some(b"BB".to_vec())).unwrap(); + let block = builder.build().unwrap().block; + let block_hash = format!("{:?}", block.header.hash()); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); - // Continue with pagination until no keys are returned. - let result: ArchiveStorageResult = api - .call( - "archive_unstable_storage", - rpc_params![ - &block_hash, - vec![PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::DescendantsValues, - pagination_start_key: Some(hex_string(b":mock")), - }] - ], + // Search for items in the main trie with keys prefixed with ":A". + let items = vec![ArchiveStorageDiffItem:: { + key: hex_string(b":A"), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }]; + let mut sub = api + .subscribe_unbounded( + "archive_unstable_storageDiff", + rpc_params![&block_hash, items.clone(), &prev_hash], ) .await .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 0); - assert_eq!(discarded_items, 0); - }, - _ => panic!("Unexpected result"), - }; + + let event = get_next_event::(&mut sub).await; + assert_eq!(ArchiveStorageDiffEvent::StorageDiffDone, event); } #[tokio::test] -async fn archive_storage_discarded_items() { - // One query at a time - let (client, api) = setup_api(MAX_PAGINATION_LIMIT, 1); +async fn archive_storage_diff_deleted_changes() { + let (client, api) = setup_api(); - // Import a new block with storage changes. + // Blocks are imported as forks. let mut builder = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().genesis_hash) .with_parent_block_number(0) .build() .unwrap(); - builder.push_storage_change(b":m".to_vec(), Some(b"a".to_vec())).unwrap(); + builder.push_storage_change(b":A".to_vec(), Some(b"B".to_vec())).unwrap(); + builder.push_storage_change(b":AA".to_vec(), Some(b"BB".to_vec())).unwrap(); + builder.push_storage_change(b":B".to_vec(), Some(b"CC".to_vec())).unwrap(); + builder.push_storage_change(b":BA".to_vec(), Some(b"CC".to_vec())).unwrap(); + let prev_block = builder.build().unwrap().block; + let prev_hash = format!("{:?}", prev_block.header.hash()); + client.import(BlockOrigin::Own, prev_block.clone()).await.unwrap(); + + let mut builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap(); + builder + .push_transfer(Transfer { + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + builder.push_storage_change(b":A".to_vec(), Some(b"B".to_vec())).unwrap(); let block = builder.build().unwrap().block; let block_hash = format!("{:?}", block.header.hash()); client.import(BlockOrigin::Own, block.clone()).await.unwrap(); - // Valid call with storage at the key. - let result: ArchiveStorageResult = api - .call( - "archive_unstable_storage", - rpc_params![ - &block_hash, - vec![ - PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::Value, - pagination_start_key: None, - }, - PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::Hash, - pagination_start_key: None, - }, - PaginatedStorageQuery { - key: hex_string(b":m"), - query_type: StorageQueryType::Hash, - pagination_start_key: None, - } - ] - ], + // Search for items in the main trie with keys prefixed with ":A". + let items = vec![ArchiveStorageDiffItem:: { + key: hex_string(b":A"), + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }]; + + let mut sub = api + .subscribe_unbounded( + "archive_unstable_storageDiff", + rpc_params![&block_hash, items.clone(), &prev_hash], ) .await .unwrap(); - match result { - ArchiveStorageResult::Ok(ArchiveStorageMethodOk { result, discarded_items }) => { - assert_eq!(result.len(), 1); - assert_eq!(discarded_items, 2); - assert_eq!(result[0].key, hex_string(b":m")); - assert_eq!(result[0].result, StorageResultType::Value(hex_string(b"a"))); - }, - _ => panic!("Unexpected result"), - }; + let event = get_next_event::(&mut sub).await; + assert_eq!( + ArchiveStorageDiffEvent::StorageDiff(ArchiveStorageDiffResult { + key: hex_string(b":AA"), + result: StorageResultType::Value(hex_string(b"BB")), + operation_type: ArchiveStorageDiffOperationType::Deleted, + child_trie_key: None, + }), + event, + ); + + let event = get_next_event::(&mut sub).await; + assert_eq!(ArchiveStorageDiffEvent::StorageDiffDone, event); +} + +#[tokio::test] +async fn archive_storage_diff_invalid_params() { + let invalid_hash = hex_string(&INVALID_HASH); + let (_, api) = setup_api(); + + // Invalid shape for parameters. + let items: Vec> = Vec::new(); + let err = api + .subscribe_unbounded( + "archive_unstable_storageDiff", + rpc_params!["123", items.clone(), &invalid_hash], + ) + .await + .unwrap_err(); + assert_matches!(err, + Error::JsonRpc(ref err) if err.code() == crate::chain_head::error::json_rpc_spec::INVALID_PARAM_ERROR && err.message() == "Invalid params" + ); + + // The shape is right, but the block hash is invalid. + let items: Vec> = Vec::new(); + let mut sub = api + .subscribe_unbounded( + "archive_unstable_storageDiff", + rpc_params![&invalid_hash, items.clone(), &invalid_hash], + ) + .await + .unwrap(); + + let event = get_next_event::(&mut sub).await; + assert_matches!(event, + ArchiveStorageDiffEvent::StorageDiffError(ref err) if err.error.contains("Header was not found") + ); } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 61eb47d1b9ab..b949fb25402b 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -318,7 +318,7 @@ where }), }; - let (rp, rp_fut) = method_started_response(operation_id); + let (rp, rp_fut) = method_started_response(operation_id, None); let fut = async move { // Wait for the server to send out the response and if it produces an error no event // should be generated. @@ -432,7 +432,8 @@ where let mut storage_client = ChainHeadStorage::::new(self.client.clone()); - let (rp, rp_fut) = method_started_response(block_guard.operation().operation_id()); + // Storage items are never discarded. + let (rp, rp_fut) = method_started_response(block_guard.operation().operation_id(), Some(0)); let fut = async move { // Wait for the server to send out the response and if it produces an error no event @@ -507,7 +508,7 @@ where let operation_id = block_guard.operation().operation_id(); let client = self.client.clone(); - let (rp, rp_fut) = method_started_response(operation_id.clone()); + let (rp, rp_fut) = method_started_response(operation_id.clone(), None); let fut = async move { // Wait for the server to send out the response and if it produces an error no event // should be generated. @@ -630,8 +631,9 @@ where fn method_started_response( operation_id: String, + discarded_items: Option, ) -> (ResponsePayload<'static, MethodResponse>, MethodResponseFuture) { - let rp = MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items: None }); + let rp = MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items }); ResponsePayload::success(rp).notify_on_completion() } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/event.rs b/substrate/client/rpc-spec-v2/src/chain_head/event.rs index bd9863060910..de74145a3f08 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/event.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/event.rs @@ -235,7 +235,7 @@ pub struct OperationCallDone { pub output: String, } -/// The response of the `chainHead_call` method. +/// The response of the `chainHead_storage` method. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct OperationStorageItems { @@ -536,6 +536,7 @@ mod tests { items: vec![StorageResult { key: "0x1".into(), result: StorageResultType::Value("0x123".to_string()), + child_trie_key: None, }], }); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index 95a7c7fe1832..3e1bd23776d3 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -784,7 +784,7 @@ mod tests { use super::*; use jsonrpsee::ConnectionId; use sc_block_builder::BlockBuilderBuilder; - use sc_service::client::new_in_mem; + use sc_service::client::new_with_backend; use sp_consensus::BlockOrigin; use sp_core::{testing::TaskExecutor, H256}; use substrate_test_runtime_client::{ @@ -811,13 +811,13 @@ mod tests { ) .unwrap(); let client = Arc::new( - new_in_mem::<_, Block, _, RuntimeApi>( + new_with_backend::<_, _, Block, _, RuntimeApi>( backend.clone(), executor, genesis_block_builder, + Box::new(TaskExecutor::new()), None, None, - Box::new(TaskExecutor::new()), client_config, ) .unwrap(), diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index c505566d887d..3ec5e805ecd5 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -34,7 +34,7 @@ use jsonrpsee::{ use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; use sc_rpc::testing::TokioTestExecutor; -use sc_service::client::new_in_mem; +use sc_service::client::new_with_backend; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_core::{ @@ -506,8 +506,8 @@ async fn get_body() { .unwrap(); builder .push_transfer(runtime::Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42, nonce: 0, }) @@ -580,7 +580,7 @@ async fn call_runtime() { ); // Valid call. - let alice_id = AccountKeyring::Alice.to_account_id(); + let alice_id = Sr25519Keyring::Alice.to_account_id(); // Hex encoded scale encoded bytes representing the call parameters. let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = api @@ -670,7 +670,7 @@ async fn call_runtime_without_flag() { ); // Valid runtime call on a subscription started with `with_runtime` false. - let alice_id = AccountKeyring::Alice.to_account_id(); + let alice_id = Sr25519Keyring::Alice.to_account_id(); let call_parameters = hex_string(&alice_id.encode()); let err = api .call::<_, serde_json::Value>( @@ -1256,7 +1256,7 @@ async fn unique_operation_ids() { assert!(op_ids.insert(operation_id)); // Valid `chainHead_v1_call` call. - let alice_id = AccountKeyring::Alice.to_account_id(); + let alice_id = Sr25519Keyring::Alice.to_account_id(); let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = api .call( @@ -1423,8 +1423,8 @@ async fn follow_generates_initial_blocks() { // imported block_builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -2046,8 +2046,8 @@ async fn follow_prune_best_block() { // imported block_builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -2217,8 +2217,8 @@ async fn follow_forks_pruned_block() { // imported block_builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -2233,8 +2233,8 @@ async fn follow_forks_pruned_block() { .unwrap(); block_builder .push_transfer(Transfer { - from: AccountKeyring::Bob.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Bob.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -2379,8 +2379,8 @@ async fn follow_report_multiple_pruned_block() { // imported block_builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -2397,8 +2397,8 @@ async fn follow_report_multiple_pruned_block() { block_builder .push_transfer(Transfer { - from: AccountKeyring::Bob.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Bob.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -2547,13 +2547,13 @@ async fn pin_block_references() { .unwrap(); let client = Arc::new( - new_in_mem::<_, Block, _, RuntimeApi>( + new_with_backend::<_, _, Block, _, RuntimeApi>( backend.clone(), executor, genesis_block_builder, + Box::new(TokioTestExecutor::default()), None, None, - Box::new(TokioTestExecutor::default()), client_config, ) .unwrap(), @@ -2871,7 +2871,7 @@ async fn ensure_operation_limits_works() { let operation_id = match response { MethodResponse::Started(started) => { // Check discarded items. - assert!(started.discarded_items.is_none()); + assert_eq!(started.discarded_items, Some(0)); started.operation_id }, MethodResponse::LimitReached => panic!("Expected started response"), @@ -2883,7 +2883,7 @@ async fn ensure_operation_limits_works() { ); // The storage is finished and capacity must be released. - let alice_id = AccountKeyring::Alice.to_account_id(); + let alice_id = Sr25519Keyring::Alice.to_account_id(); // Hex encoded scale encoded bytes representing the call parameters. let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = api @@ -3228,7 +3228,10 @@ async fn storage_closest_merkle_value() { .await .unwrap(); let operation_id = match response { - MethodResponse::Started(started) => started.operation_id, + MethodResponse::Started(started) => { + assert_eq!(started.discarded_items, Some(0)); + started.operation_id + }, MethodResponse::LimitReached => panic!("Expected started response"), }; @@ -3534,7 +3537,7 @@ async fn chain_head_single_connection_context() { .unwrap(); assert_matches!(response, MethodResponse::LimitReached); - let alice_id = AccountKeyring::Alice.to_account_id(); + let alice_id = Sr25519Keyring::Alice.to_account_id(); // Hex encoded scale encoded bytes representing the call parameters. let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_call( @@ -3660,8 +3663,8 @@ async fn follow_unique_pruned_blocks() { let block_6_hash = import_block(client.clone(), block_2_f_hash, 2).await.hash(); // Import block 2 as best on the fork. let mut tx_alice_ferdie = Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }; @@ -3843,8 +3846,8 @@ async fn follow_report_best_block_of_a_known_block() { // imported block_builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) diff --git a/substrate/client/rpc-spec-v2/src/common/events.rs b/substrate/client/rpc-spec-v2/src/common/events.rs index b1627d74c844..44f722c0c61b 100644 --- a/substrate/client/rpc-spec-v2/src/common/events.rs +++ b/substrate/client/rpc-spec-v2/src/common/events.rs @@ -78,10 +78,14 @@ pub struct StorageResult { /// The result of the query. #[serde(flatten)] pub result: StorageResultType, + /// The child trie key if provided. + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub child_trie_key: Option, } /// The type of the storage query. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum StorageResultType { /// Fetch the value of the provided key. @@ -105,23 +109,41 @@ pub struct StorageResultErr { /// The result of a storage call. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ArchiveStorageResult { +#[serde(rename_all = "camelCase")] +#[serde(tag = "event")] +pub enum ArchiveStorageEvent { /// Query generated a result. - Ok(ArchiveStorageMethodOk), + Storage(StorageResult), /// Query encountered an error. - Err(ArchiveStorageMethodErr), + StorageError(ArchiveStorageMethodErr), + /// Operation storage is done. + StorageDone, } -impl ArchiveStorageResult { - /// Create a new `ArchiveStorageResult::Ok` result. - pub fn ok(result: Vec, discarded_items: usize) -> Self { - Self::Ok(ArchiveStorageMethodOk { result, discarded_items }) +impl ArchiveStorageEvent { + /// Create a new `ArchiveStorageEvent::StorageErr` event. + pub fn err(error: String) -> Self { + Self::StorageError(ArchiveStorageMethodErr { error }) } - /// Create a new `ArchiveStorageResult::Err` result. - pub fn err(error: String) -> Self { - Self::Err(ArchiveStorageMethodErr { error }) + /// Create a new `ArchiveStorageEvent::StorageResult` event. + pub fn result(result: StorageResult) -> Self { + Self::Storage(result) + } + + /// Checks if the event is a `StorageDone` event. + pub fn is_done(&self) -> bool { + matches!(self, Self::StorageDone) + } + + /// Checks if the event is a `StorageErr` event. + pub fn is_err(&self) -> bool { + matches!(self, Self::StorageError(_)) + } + + /// Checks if the event is a `StorageResult` event. + pub fn is_result(&self) -> bool { + matches!(self, Self::Storage(_)) } } @@ -136,22 +158,229 @@ pub struct ArchiveStorageMethodOk { } /// The error of a storage call. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ArchiveStorageMethodErr { /// Reported error. pub error: String, } +/// The type of the archive storage difference query. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum ArchiveStorageDiffType { + /// The result is provided as value of the key. + Value, + /// The result the hash of the value of the key. + Hash, +} + +/// The storage item to query. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ArchiveStorageDiffItem { + /// The provided key. + pub key: Key, + /// The type of the storage query. + pub return_type: ArchiveStorageDiffType, + /// The child trie key if provided. + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub child_trie_key: Option, +} + +/// The result of a storage difference call. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ArchiveStorageDiffMethodResult { + /// Reported results. + pub result: Vec, +} + +/// The result of a storage difference call operation type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum ArchiveStorageDiffOperationType { + /// The key is added. + Added, + /// The key is modified. + Modified, + /// The key is removed. + Deleted, +} + +/// The result of an individual storage difference key. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ArchiveStorageDiffResult { + /// The hex-encoded key of the result. + pub key: String, + /// The result of the query. + #[serde(flatten)] + pub result: StorageResultType, + /// The operation type. + #[serde(rename = "type")] + pub operation_type: ArchiveStorageDiffOperationType, + /// The child trie key if provided. + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub child_trie_key: Option, +} + +/// The event generated by the `archive_storageDiff` method. +/// +/// The `archive_storageDiff` can generate the following events: +/// - `storageDiff` event - generated when a `ArchiveStorageDiffResult` is produced. +/// - `storageDiffError` event - generated when an error is produced. +/// - `storageDiffDone` event - generated when the `archive_storageDiff` method completed. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event")] +pub enum ArchiveStorageDiffEvent { + /// The `storageDiff` event. + StorageDiff(ArchiveStorageDiffResult), + /// The `storageDiffError` event. + StorageDiffError(ArchiveStorageMethodErr), + /// The `storageDiffDone` event. + StorageDiffDone, +} + +impl ArchiveStorageDiffEvent { + /// Create a new `ArchiveStorageDiffEvent::StorageDiffError` event. + pub fn err(error: String) -> Self { + Self::StorageDiffError(ArchiveStorageMethodErr { error }) + } + + /// Checks if the event is a `StorageDiffDone` event. + pub fn is_done(&self) -> bool { + matches!(self, Self::StorageDiffDone) + } + + /// Checks if the event is a `StorageDiffError` event. + pub fn is_err(&self) -> bool { + matches!(self, Self::StorageDiffError(_)) + } +} + #[cfg(test)] mod tests { use super::*; + #[test] + fn archive_diff_input() { + // Item with Value. + let item = ArchiveStorageDiffItem { + key: "0x1", + return_type: ArchiveStorageDiffType::Value, + child_trie_key: None, + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","returnType":"value"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffItem<&str> = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + + // Item with Hash. + let item = ArchiveStorageDiffItem { + key: "0x1", + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: None, + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","returnType":"hash"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffItem<&str> = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + + // Item with Value and child trie key. + let item = ArchiveStorageDiffItem { + key: "0x1", + return_type: ArchiveStorageDiffType::Value, + child_trie_key: Some("0x2"), + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","returnType":"value","childTrieKey":"0x2"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffItem<&str> = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + + // Item with Hash and child trie key. + let item = ArchiveStorageDiffItem { + key: "0x1", + return_type: ArchiveStorageDiffType::Hash, + child_trie_key: Some("0x2"), + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","returnType":"hash","childTrieKey":"0x2"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffItem<&str> = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + } + + #[test] + fn archive_diff_output() { + // Item with Value. + let item = ArchiveStorageDiffResult { + key: "0x1".into(), + result: StorageResultType::Value("res".into()), + operation_type: ArchiveStorageDiffOperationType::Added, + child_trie_key: None, + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","value":"res","type":"added"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffResult = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + + // Item with Hash. + let item = ArchiveStorageDiffResult { + key: "0x1".into(), + result: StorageResultType::Hash("res".into()), + operation_type: ArchiveStorageDiffOperationType::Modified, + child_trie_key: None, + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","hash":"res","type":"modified"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffResult = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + + // Item with Hash, child trie key and removed. + let item = ArchiveStorageDiffResult { + key: "0x1".into(), + result: StorageResultType::Hash("res".into()), + operation_type: ArchiveStorageDiffOperationType::Deleted, + child_trie_key: Some("0x2".into()), + }; + // Encode + let ser = serde_json::to_string(&item).unwrap(); + let exp = r#"{"key":"0x1","hash":"res","type":"deleted","childTrieKey":"0x2"}"#; + assert_eq!(ser, exp); + // Decode + let dec: ArchiveStorageDiffResult = serde_json::from_str(exp).unwrap(); + assert_eq!(dec, item); + } + #[test] fn storage_result() { // Item with Value. - let item = - StorageResult { key: "0x1".into(), result: StorageResultType::Value("res".into()) }; + let item = StorageResult { + key: "0x1".into(), + result: StorageResultType::Value("res".into()), + child_trie_key: None, + }; // Encode let ser = serde_json::to_string(&item).unwrap(); let exp = r#"{"key":"0x1","value":"res"}"#; @@ -161,8 +390,11 @@ mod tests { assert_eq!(dec, item); // Item with Hash. - let item = - StorageResult { key: "0x1".into(), result: StorageResultType::Hash("res".into()) }; + let item = StorageResult { + key: "0x1".into(), + result: StorageResultType::Hash("res".into()), + child_trie_key: None, + }; // Encode let ser = serde_json::to_string(&item).unwrap(); let exp = r#"{"key":"0x1","hash":"res"}"#; @@ -175,6 +407,7 @@ mod tests { let item = StorageResult { key: "0x1".into(), result: StorageResultType::ClosestDescendantMerkleValue("res".into()), + child_trie_key: None, }; // Encode let ser = serde_json::to_string(&item).unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/common/storage.rs b/substrate/client/rpc-spec-v2/src/common/storage.rs index 2e24a8da8ca8..a1e34d51530e 100644 --- a/substrate/client/rpc-spec-v2/src/common/storage.rs +++ b/substrate/client/rpc-spec-v2/src/common/storage.rs @@ -24,7 +24,7 @@ use sc_client_api::{Backend, ChildInfo, StorageKey, StorageProvider}; use sp_runtime::traits::Block as BlockT; use tokio::sync::mpsc; -use super::events::{StorageResult, StorageResultType}; +use super::events::{StorageQuery, StorageQueryType, StorageResult, StorageResultType}; use crate::hex_string; /// Call into the storage of blocks. @@ -70,9 +70,6 @@ pub enum IterQueryType { /// The result of making a query call. pub type QueryResult = Result, String>; -/// The result of iterating over keys. -pub type QueryIterResult = Result<(Vec, Option), String>; - impl Storage where Block: BlockT + 'static, @@ -97,6 +94,7 @@ where QueryResult::Ok(opt.map(|storage_data| StorageResult { key: hex_string(&key.0), result: StorageResultType::Value(hex_string(&storage_data.0)), + child_trie_key: child_key.map(|c| hex_string(&c.storage_key())), })) }) .unwrap_or_else(|error| QueryResult::Err(error.to_string())) @@ -120,6 +118,7 @@ where QueryResult::Ok(opt.map(|storage_data| StorageResult { key: hex_string(&key.0), result: StorageResultType::Hash(hex_string(&storage_data.as_ref())), + child_trie_key: child_key.map(|c| hex_string(&c.storage_key())), })) }) .unwrap_or_else(|error| QueryResult::Err(error.to_string())) @@ -149,6 +148,7 @@ where StorageResult { key: hex_string(&key.0), result: StorageResultType::ClosestDescendantMerkleValue(result), + child_trie_key: child_key.map(|c| hex_string(&c.storage_key())), } })) }) @@ -199,53 +199,111 @@ where } } - /// Iterate over at most the provided number of keys. - /// - /// Returns the storage result with a potential next key to resume iteration. - pub fn query_iter_pagination( + /// Raw iterator over the keys. + pub fn raw_keys_iter( &self, - query: QueryIter, hash: Block::Hash, - child_key: Option<&ChildInfo>, - count: usize, - ) -> QueryIterResult { - let QueryIter { ty, query_key, pagination_start_key } = query; - - let mut keys_iter = if let Some(child_key) = child_key { - self.client.child_storage_keys( - hash, - child_key.to_owned(), - Some(&query_key), - pagination_start_key.as_ref(), - ) + child_key: Option, + ) -> Result, String> { + let keys_iter = if let Some(child_key) = child_key { + self.client.child_storage_keys(hash, child_key, None, None) } else { - self.client.storage_keys(hash, Some(&query_key), pagination_start_key.as_ref()) - } - .map_err(|err| err.to_string())?; + self.client.storage_keys(hash, None, None) + }; + + keys_iter.map_err(|err| err.to_string()) + } +} - let mut ret = Vec::with_capacity(count); - let mut next_pagination_key = None; - for _ in 0..count { - let Some(key) = keys_iter.next() else { break }; +/// Generates storage events for `chainHead_storage` and `archive_storage` subscriptions. +pub struct StorageSubscriptionClient { + /// Storage client. + client: Storage, + _phandom: PhantomData<(BE, Block)>, +} - next_pagination_key = Some(key.clone()); +impl Clone for StorageSubscriptionClient { + fn clone(&self) -> Self { + Self { client: self.client.clone(), _phandom: PhantomData } + } +} - let result = match ty { - IterQueryType::Value => self.query_value(hash, &key, child_key), - IterQueryType::Hash => self.query_hash(hash, &key, child_key), - }?; +impl StorageSubscriptionClient { + /// Constructs a new [`StorageSubscriptionClient`]. + pub fn new(client: Arc) -> Self { + Self { client: Storage::new(client), _phandom: PhantomData } + } +} - if let Some(value) = result { - ret.push(value); +impl StorageSubscriptionClient +where + Block: BlockT + 'static, + BE: Backend + 'static, + Client: StorageProvider + Send + Sync + 'static, +{ + /// Generate storage events to the provided sender. + pub async fn generate_events( + &mut self, + hash: Block::Hash, + items: Vec>, + child_key: Option, + tx: mpsc::Sender, + ) -> Result<(), tokio::task::JoinError> { + let this = self.clone(); + + tokio::task::spawn_blocking(move || { + for item in items { + match item.query_type { + StorageQueryType::Value => { + let rp = this.client.query_value(hash, &item.key, child_key.as_ref()); + if tx.blocking_send(rp).is_err() { + break; + } + }, + StorageQueryType::Hash => { + let rp = this.client.query_hash(hash, &item.key, child_key.as_ref()); + if tx.blocking_send(rp).is_err() { + break; + } + }, + StorageQueryType::ClosestDescendantMerkleValue => { + let rp = + this.client.query_merkle_value(hash, &item.key, child_key.as_ref()); + if tx.blocking_send(rp).is_err() { + break; + } + }, + StorageQueryType::DescendantsValues => { + let query = QueryIter { + query_key: item.key, + ty: IterQueryType::Value, + pagination_start_key: None, + }; + this.client.query_iter_pagination_with_producer( + query, + hash, + child_key.as_ref(), + &tx, + ) + }, + StorageQueryType::DescendantsHashes => { + let query = QueryIter { + query_key: item.key, + ty: IterQueryType::Hash, + pagination_start_key: None, + }; + this.client.query_iter_pagination_with_producer( + query, + hash, + child_key.as_ref(), + &tx, + ) + }, + } } - } + }) + .await?; - // Save the next key if any to continue the iteration. - let maybe_next_query = keys_iter.next().map(|_| QueryIter { - ty, - query_key, - pagination_start_key: next_pagination_key, - }); - Ok((ret, maybe_next_query)) + Ok(()) } } diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/middleware_pool.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/middleware_pool.rs index adcc987f9c39..a543969a89b8 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/middleware_pool.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/middleware_pool.rs @@ -16,16 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use async_trait::async_trait; use codec::Encode; -use futures::Future; use sc_transaction_pool::BasicPool; use sc_transaction_pool_api::{ - ImportNotificationStream, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, - TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, + ImportNotificationStream, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, + TransactionSource, TransactionStatusStreamFor, TxHash, }; use crate::hex_string; -use futures::{FutureExt, StreamExt}; +use futures::StreamExt; use sp_runtime::traits::Block as BlockT; use std::{collections::HashMap, pin::Pin, sync::Arc}; @@ -77,67 +77,64 @@ impl MiddlewarePool { } } +#[async_trait] impl TransactionPool for MiddlewarePool { type Block = as TransactionPool>::Block; type Hash = as TransactionPool>::Hash; type InPoolTransaction = as TransactionPool>::InPoolTransaction; type Error = as TransactionPool>::Error; - fn submit_at( + async fn submit_at( &self, at: ::Hash, source: TransactionSource, xts: Vec>, - ) -> PoolFuture, Self::Error>>, Self::Error> { - self.inner_pool.submit_at(at, source, xts) + ) -> Result, Self::Error>>, Self::Error> { + self.inner_pool.submit_at(at, source, xts).await } - fn submit_one( + async fn submit_one( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture, Self::Error> { - self.inner_pool.submit_one(at, source, xt) + ) -> Result, Self::Error> { + self.inner_pool.submit_one(at, source, xt).await } - fn submit_and_watch( + async fn submit_and_watch( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture>>, Self::Error> { - let pool = self.inner_pool.clone(); - let sender = self.sender.clone(); + ) -> Result>>, Self::Error> { let transaction = hex_string(&xt.encode()); + let sender = self.sender.clone(); - async move { - let watcher = match pool.submit_and_watch(at, source, xt).await { - Ok(watcher) => watcher, - Err(err) => { - let _ = sender.send(MiddlewarePoolEvent::PoolError { - transaction: transaction.clone(), - err: err.to_string(), - }); - return Err(err); - }, - }; - - let watcher = watcher.map(move |status| { - let sender = sender.clone(); - let transaction = transaction.clone(); - - let _ = sender.send(MiddlewarePoolEvent::TransactionStatus { - transaction, - status: status.clone(), + let watcher = match self.inner_pool.submit_and_watch(at, source, xt).await { + Ok(watcher) => watcher, + Err(err) => { + let _ = sender.send(MiddlewarePoolEvent::PoolError { + transaction: transaction.clone(), + err: err.to_string(), }); + return Err(err); + }, + }; + + let watcher = watcher.map(move |status| { + let sender = sender.clone(); + let transaction = transaction.clone(); - status + let _ = sender.send(MiddlewarePoolEvent::TransactionStatus { + transaction, + status: status.clone(), }); - Ok(watcher.boxed()) - } - .boxed() + status + }); + + Ok(watcher.boxed()) } fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { @@ -164,17 +161,11 @@ impl TransactionPool for MiddlewarePool { self.inner_pool.ready_transaction(hash) } - fn ready_at( + async fn ready_at( &self, at: ::Hash, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send, - >, - > { - self.inner_pool.ready_at(at) + ) -> Box> + Send> { + self.inner_pool.ready_at(at).await } fn ready(&self) -> Box> + Send> { @@ -185,18 +176,11 @@ impl TransactionPool for MiddlewarePool { self.inner_pool.futures() } - fn ready_at_with_timeout( + async fn ready_at_with_timeout( &self, at: ::Hash, _timeout: std::time::Duration, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send - + '_, - >, - > { - self.inner_pool.ready_at(at) + ) -> Box> + Send> { + self.inner_pool.ready_at(at).await } } diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs index efb3bd94ddbf..c2f11878e8fc 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs @@ -23,7 +23,7 @@ use jsonrpsee::{rpc_params, MethodsError as Error}; use sc_transaction_pool::{Options, PoolLimit}; use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool, TransactionPool}; use std::sync::Arc; -use substrate_test_runtime_client::AccountKeyring::*; +use substrate_test_runtime_client::Sr25519Keyring::*; use substrate_test_runtime_transaction_pool::uxt; const MAX_TX_PER_CONNECTION: usize = 4; diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs index 53c5b8ce3895..879d51eaf5f3 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs @@ -26,7 +26,7 @@ use jsonrpsee::rpc_params; use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool}; use sp_core::H256; use std::{sync::Arc, vec}; -use substrate_test_runtime_client::AccountKeyring::*; +use substrate_test_runtime_client::Sr25519Keyring::*; use substrate_test_runtime_transaction_pool::uxt; // Test helpers. diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index 6fe28a3873e9..8be932f02ed4 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -21,7 +21,6 @@ futures = { workspace = true } jsonrpsee = { features = ["server"], workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } @@ -30,6 +29,7 @@ sc-rpc-api = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } @@ -38,22 +38,22 @@ sp-offchain = { workspace = true, default-features = true } sp-rpc = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-session = { workspace = true, default-features = true } -sp-version = { workspace = true, default-features = true } sp-statement-store = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } tokio = { workspace = true, default-features = true } [dev-dependencies] assert_matches = { workspace = true } +pretty_assertions = { workspace = true } sc-block-builder = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } -tokio = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } -pretty_assertions = { workspace = true } +tokio = { workspace = true, default-features = true } [features] test-helpers = [] diff --git a/substrate/client/rpc/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs index 731f4df2f6f3..6afc871e565a 100644 --- a/substrate/client/rpc/src/author/mod.rs +++ b/substrate/client/rpc/src/author/mod.rs @@ -29,7 +29,6 @@ use crate::{ }; use codec::{Decode, Encode}; -use futures::TryFutureExt; use jsonrpsee::{core::async_trait, types::ErrorObject, Extensions, PendingSubscriptionSink}; use sc_rpc_api::check_if_safe; use sc_transaction_pool_api::{ @@ -191,14 +190,16 @@ where }, }; - let submit = self.pool.submit_and_watch(best_block_hash, TX_SOURCE, dxt).map_err(|e| { - e.into_pool_error() - .map(error::Error::from) - .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) - }); - + let pool = self.pool.clone(); let fut = async move { - let stream = match submit.await { + let submit = + pool.submit_and_watch(best_block_hash, TX_SOURCE, dxt).await.map_err(|e| { + e.into_pool_error() + .map(error::Error::from) + .unwrap_or_else(|e| error::Error::Verification(Box::new(e))) + }); + + let stream = match submit { Ok(stream) => stream, Err(err) => { let _ = pending.reject(ErrorObject::from(err)).await; diff --git a/substrate/client/rpc/src/author/tests.rs b/substrate/client/rpc/src/author/tests.rs index ab0b8bdab699..b1c899667624 100644 --- a/substrate/client/rpc/src/author/tests.rs +++ b/substrate/client/rpc/src/author/tests.rs @@ -39,15 +39,15 @@ use std::sync::Arc; use substrate_test_runtime_client::{ self, runtime::{Block, Extrinsic, ExtrinsicBuilder, SessionKeys, Transfer}, - AccountKeyring, Backend, Client, DefaultTestClientBuilderExt, TestClientBuilderExt, + Backend, Client, DefaultTestClientBuilderExt, Sr25519Keyring, TestClientBuilderExt, }; -fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { +fn uxt(sender: Sr25519Keyring, nonce: u64) -> Extrinsic { let tx = Transfer { amount: Default::default(), nonce, from: sender.into(), - to: AccountKeyring::Bob.into(), + to: Sr25519Keyring::Bob.into(), }; ExtrinsicBuilder::new_transfer(tx).build() } @@ -99,7 +99,7 @@ impl TestSetup { async fn author_submit_transaction_should_not_cause_error() { let api = TestSetup::into_rpc(); - let xt: Bytes = uxt(AccountKeyring::Alice, 1).encode().into(); + let xt: Bytes = uxt(Sr25519Keyring::Alice, 1).encode().into(); let extrinsic_hash: H256 = blake2_256(&xt).into(); let response: H256 = api.call("author_submitExtrinsic", [xt.clone()]).await.unwrap(); @@ -116,7 +116,7 @@ async fn author_should_watch_extrinsic() { let api = TestSetup::into_rpc(); let xt = to_hex( &ExtrinsicBuilder::new_call_with_priority(0) - .signer(AccountKeyring::Alice.into()) + .signer(Sr25519Keyring::Alice.into()) .build() .encode(), true, @@ -135,7 +135,7 @@ async fn author_should_watch_extrinsic() { // Replace the extrinsic and observe the subscription is notified. let (xt_replacement, xt_hash) = { let tx = ExtrinsicBuilder::new_call_with_priority(1) - .signer(AccountKeyring::Alice.into()) + .signer(Sr25519Keyring::Alice.into()) .build() .encode(); let hash = blake2_256(&tx); @@ -172,7 +172,7 @@ async fn author_should_return_watch_validation_error() { async fn author_should_return_pending_extrinsics() { let api = TestSetup::into_rpc(); - let xt_bytes: Bytes = uxt(AccountKeyring::Alice, 0).encode().into(); + let xt_bytes: Bytes = uxt(Sr25519Keyring::Alice, 0).encode().into(); api.call::<_, H256>("author_submitExtrinsic", [to_hex(&xt_bytes, true)]) .await .unwrap(); @@ -190,14 +190,14 @@ async fn author_should_remove_extrinsics() { // Submit three extrinsics, then remove two of them (will cause the third to be removed as well, // having a higher nonce) - let xt1_bytes = uxt(AccountKeyring::Alice, 0).encode(); + let xt1_bytes = uxt(Sr25519Keyring::Alice, 0).encode(); let xt1 = to_hex(&xt1_bytes, true); let xt1_hash: H256 = api.call("author_submitExtrinsic", [xt1]).await.unwrap(); - let xt2 = to_hex(&uxt(AccountKeyring::Alice, 1).encode(), true); + let xt2 = to_hex(&uxt(Sr25519Keyring::Alice, 1).encode(), true); let xt2_hash: H256 = api.call("author_submitExtrinsic", [xt2]).await.unwrap(); - let xt3 = to_hex(&uxt(AccountKeyring::Bob, 0).encode(), true); + let xt3 = to_hex(&uxt(Sr25519Keyring::Bob, 0).encode(), true); let xt3_hash: H256 = api.call("author_submitExtrinsic", [xt3]).await.unwrap(); assert_eq!(setup.pool.status().ready, 3); diff --git a/substrate/client/rpc/src/state/tests.rs b/substrate/client/rpc/src/state/tests.rs index 6b711f2425e9..c02f0d0b759b 100644 --- a/substrate/client/rpc/src/state/tests.rs +++ b/substrate/client/rpc/src/state/tests.rs @@ -228,8 +228,8 @@ async fn should_notify_about_storage_changes() { .unwrap(); builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42, nonce: 0, }) @@ -255,11 +255,11 @@ async fn should_send_initial_storage_changes_and_notifications() { let alice_balance_key = [ sp_crypto_hashing::twox_128(b"System"), sp_crypto_hashing::twox_128(b"Account"), - sp_crypto_hashing::blake2_128(&AccountKeyring::Alice.public()), + sp_crypto_hashing::blake2_128(&Sr25519Keyring::Alice.public()), ] .concat() .iter() - .chain(AccountKeyring::Alice.public().0.iter()) + .chain(Sr25519Keyring::Alice.public().0.iter()) .cloned() .collect::>(); @@ -281,8 +281,8 @@ async fn should_send_initial_storage_changes_and_notifications() { .unwrap(); builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42, nonce: 0, }) diff --git a/substrate/client/runtime-utilities/Cargo.toml b/substrate/client/runtime-utilities/Cargo.toml new file mode 100644 index 000000000000..716b577d384a --- /dev/null +++ b/substrate/client/runtime-utilities/Cargo.toml @@ -0,0 +1,36 @@ +[package] +description = "Substrate client utilities for frame runtime functions calls." +name = "sc-runtime-utilities" +version = "0.1.0" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true +documentation = "https://docs.rs/sc-metadata" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { workspace = true, default-features = true } + +sc-executor = { workspace = true, default-features = true } +sc-executor-common = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-wasm-interface = { workspace = true, default-features = true } + + +thiserror = { workspace = true } + +[dev-dependencies] +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } +cumulus-test-runtime = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +subxt = { workspace = true, features = ["native"] } diff --git a/substrate/client/runtime-utilities/src/error.rs b/substrate/client/runtime-utilities/src/error.rs new file mode 100644 index 000000000000..a0f1e45a5e57 --- /dev/null +++ b/substrate/client/runtime-utilities/src/error.rs @@ -0,0 +1,35 @@ +// 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 . +//! Errors types of runtime utilities. + +/// Generic result for the runtime utilities. +pub type Result = std::result::Result; + +/// Error type for the runtime utilities. +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error("Scale codec error: {0}")] + ScaleCodec(#[from] codec::Error), + #[error("Opaque metadata not found")] + OpaqueMetadataNotFound, + #[error("Stable metadata version not found")] + StableMetadataVersionNotFound, + #[error("WASM executor error: {0}")] + Executor(#[from] sc_executor_common::error::Error), +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/client/runtime-utilities/src/lib.rs similarity index 56% rename from substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs rename to substrate/client/runtime-utilities/src/lib.rs index c498da38afb0..1ae3e2f1105a 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs +++ b/substrate/client/runtime-utilities/src/lib.rs @@ -1,21 +1,29 @@ // 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. +// 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 . + +//! Substrate client runtime utilities. +//! +//! Provides convenient APIs to ease calling functions contained by a FRAME +//! runtime WASM blob. +#![warn(missing_docs)] use codec::{Decode, Encode}; +use error::{Error, Result}; use sc_executor::WasmExecutor; use sp_core::{ traits::{CallContext, CodeExecutor, FetchRuntimeCode, RuntimeCode}, @@ -25,36 +33,35 @@ use sp_state_machine::BasicExternalities; use sp_wasm_interface::HostFunctions; use std::borrow::Cow; +pub mod error; + /// Fetches the latest metadata from the given runtime blob. pub fn fetch_latest_metadata_from_code_blob( executor: &WasmExecutor, code_bytes: Cow<[u8]>, -) -> sc_cli::Result { +) -> Result { let runtime_caller = RuntimeCaller::new(executor, code_bytes); let version_result = runtime_caller.call("Metadata_metadata_versions", ()); - let opaque_metadata: OpaqueMetadata = match version_result { + match version_result { Ok(supported_versions) => { - let latest_version = Vec::::decode(&mut supported_versions.as_slice()) - .map_err(|e| format!("Unable to decode version list: {e}"))? - .pop() - .ok_or("No metadata versions supported".to_string())?; - - let encoded = runtime_caller - .call("Metadata_metadata_at_version", latest_version) - .map_err(|_| "Unable to fetch metadata from blob".to_string())?; + let supported_versions = Vec::::decode(&mut supported_versions.as_slice())?; + let latest_stable = supported_versions + .into_iter() + .filter(|v| *v != u32::MAX) + .max() + .ok_or(Error::StableMetadataVersionNotFound)?; + + let encoded = runtime_caller.call("Metadata_metadata_at_version", latest_stable)?; + Option::::decode(&mut encoded.as_slice())? - .ok_or_else(|| "Metadata not found".to_string())? + .ok_or(Error::OpaqueMetadataNotFound) }, Err(_) => { - let encoded = runtime_caller - .call("Metadata_metadata", ()) - .map_err(|_| "Unable to fetch metadata from blob".to_string())?; - Decode::decode(&mut encoded.as_slice())? + let encoded = runtime_caller.call("Metadata_metadata", ())?; + Decode::decode(&mut encoded.as_slice()).map_err(Into::into) }, - }; - - Ok(subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?) + } } struct BasicCodeFetcher<'a> { @@ -69,11 +76,11 @@ impl<'a> FetchRuntimeCode for BasicCodeFetcher<'a> { } impl<'a> BasicCodeFetcher<'a> { - pub fn new(code: Cow<'a, [u8]>) -> Self { + fn new(code: Cow<'a, [u8]>) -> Self { Self { hash: sp_crypto_hashing::blake2_256(&code).to_vec(), code } } - pub fn runtime_code(&'a self) -> RuntimeCode<'a> { + fn runtime_code(&'a self) -> RuntimeCode<'a> { RuntimeCode { code_fetcher: self as &'a dyn FetchRuntimeCode, heap_pages: None, @@ -83,17 +90,20 @@ impl<'a> BasicCodeFetcher<'a> { } /// Simple utility that is used to call into the runtime. -struct RuntimeCaller<'a, 'b, HF: HostFunctions> { +pub struct RuntimeCaller<'a, 'b, HF: HostFunctions> { executor: &'b WasmExecutor, code_fetcher: BasicCodeFetcher<'a>, } impl<'a, 'b, HF: HostFunctions> RuntimeCaller<'a, 'b, HF> { + /// Instantiate a new runtime caller. pub fn new(executor: &'b WasmExecutor, code_bytes: Cow<'a, [u8]>) -> Self { Self { executor, code_fetcher: BasicCodeFetcher::new(code_bytes) } } - fn call(&self, method: &str, data: impl Encode) -> sc_executor_common::error::Result> { + /// Calls a runtime function represented by a `method` name and `parity-scale-codec` + /// encodable arguments that will be passed to it. + pub fn call(&self, method: &str, data: impl Encode) -> Result> { let mut ext = BasicExternalities::default(); self.executor .call( @@ -104,24 +114,33 @@ impl<'a, 'b, HF: HostFunctions> RuntimeCaller<'a, 'b, HF> { CallContext::Offchain, ) .0 + .map_err(Into::into) } } #[cfg(test)] mod tests { - use crate::overhead::command::ParachainHostFunctions; use codec::Decode; use sc_executor::WasmExecutor; use sp_version::RuntimeVersion; + type ParachainHostFunctions = ( + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions, + sp_io::SubstrateHostFunctions, + ); + #[test] fn test_fetch_latest_metadata_from_blob_fetches_metadata() { let executor: WasmExecutor = WasmExecutor::builder().build(); let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = - super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = subxt::Metadata::decode( + &mut (*super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()) + .unwrap()) + .as_slice(), + ) + .unwrap(); assert!(metadata.pallet_by_name("ParachainInfo").is_some()); } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index f2fc65ef2439..e46b252f30bf 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -20,72 +20,70 @@ default = ["rocksdb"] # The RocksDB feature activates the RocksDB database backend. If it is not activated, and you pass # a path to a database, an error will be produced at runtime. rocksdb = ["sc-client-db/rocksdb"] -# exposes the client type -test-helpers = [] runtime-benchmarks = [ "sc-client-db/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] [dependencies] -jsonrpsee = { features = ["server"], workspace = true } -thiserror = { workspace = true } +async-trait = { workspace = true } +codec = { workspace = true, default-features = true } +directories = { workspace = true } +exit-future = { workspace = true } futures = { workspace = true } -rand = { workspace = true, default-features = true } -parking_lot = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } futures-timer = { workspace = true } -exit-future = { workspace = true } +jsonrpsee = { features = ["server"], workspace = true } +log = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } pin-project = { workspace = true } -serde = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-trie = { workspace = true, default-features = true } -sp-externalities = { workspace = true, default-features = true } -sc-utils = { workspace = true, default-features = true } -sp-version = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sp-session = { workspace = true, default-features = true } -sp-state-machine = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +rand = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-client-db = { workspace = true } sc-consensus = { workspace = true, default-features = true } -sp-storage = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-informant = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-common = { workspace = true, default-features = true } sc-network-light = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } -sc-network-types = { workspace = true, default-features = true } sc-network-transactions = { workspace = true, default-features = true } -sc-chain-spec = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } -sc-client-db = { workspace = true } -codec = { workspace = true, default-features = true } -sc-executor = { workspace = true, default-features = true } -sc-transaction-pool = { workspace = true, default-features = true } -sp-transaction-pool = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } -sp-transaction-storage-proof = { workspace = true, default-features = true } -sc-rpc-server = { workspace = true, default-features = true } +sc-network-types = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } +sc-rpc-server = { workspace = true, default-features = true } sc-rpc-spec-v2 = { workspace = true, default-features = true } -sc-informant = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } -sc-sysinfo = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sc-transaction-pool-api = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } +schnellru = { workspace = true } +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-externalities = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-session = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +sp-transaction-storage-proof = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +static_init = { workspace = true } +tempfile = { workspace = true } +thiserror = { workspace = true } +tokio = { features = ["parking_lot", "rt-multi-thread", "time"], workspace = true, default-features = true } tracing = { workspace = true, default-features = true } tracing-futures = { workspace = true } -async-trait = { workspace = true } -tokio = { features = ["parking_lot", "rt-multi-thread", "time"], workspace = true, default-features = true } -tempfile = { workspace = true } -directories = { workspace = true } -static_init = { workspace = true } -schnellru = { workspace = true } [dev-dependencies] -substrate-test-runtime-client = { workspace = true } substrate-test-runtime = { workspace = true } +substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index f27b7ec6fbad..a47a05c0a190 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -25,7 +25,7 @@ use crate::{ start_rpc_servers, BuildGenesisBlock, GenesisBlockBuilder, RpcHandlers, SpawnTaskHandle, TaskManager, TransactionPoolAdapter, }; -use futures::{channel::oneshot, future::ready, FutureExt, StreamExt}; +use futures::{select, FutureExt, StreamExt}; use jsonrpsee::RpcModule; use log::info; use prometheus_endpoint::Registry; @@ -35,7 +35,7 @@ use sc_client_api::{ BlockBackend, BlockchainEvents, ExecutorProvider, ForkBlocks, StorageProvider, UsageProvider, }; use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, PruningMode}; -use sc_consensus::import_queue::ImportQueue; +use sc_consensus::import_queue::{ImportQueue, ImportQueueService}; use sc_executor::{ sp_wasm_interface::HostFunctions, HeapAllocStrategy, NativeExecutionDispatch, RuntimeVersionOf, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, @@ -50,15 +50,18 @@ use sc_network::{ }, NetworkBackend, NetworkStateInfo, }; -use sc_network_common::role::Roles; +use sc_network_common::role::{Role, Roles}; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ - block_relay_protocol::BlockRelayParams, + block_relay_protocol::{BlockDownloader, BlockRelayParams}, block_request_handler::BlockRequestHandler, engine::SyncingEngine, - service::network::NetworkServiceProvider, + service::network::{NetworkServiceHandle, NetworkServiceProvider}, state_request_handler::StateRequestHandler, - strategy::{PolkadotSyncingStrategy, SyncingConfig, SyncingStrategy}, + strategy::{ + polkadot::{PolkadotSyncingStrategy, PolkadotSyncingStrategyConfig}, + SyncingStrategy, + }, warp_request_handler::RequestHandler as WarpSyncRequestHandler, SyncingService, WarpSyncConfig, }; @@ -87,7 +90,11 @@ use sp_consensus::block_validation::{ use sp_core::traits::{CodeExecutor, SpawnNamed}; use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, BlockIdTo, NumberFor, Zero}; -use std::{str::FromStr, sync::Arc, time::SystemTime}; +use std::{ + str::FromStr, + sync::Arc, + time::{Duration, SystemTime}, +}; /// Full client type. pub type TFullClient = @@ -574,22 +581,42 @@ pub async fn propagate_transaction_notifications( Block: BlockT, ExPool: MaintainedTransactionPool::Hash>, { + const TELEMETRY_INTERVAL: Duration = Duration::from_secs(1); + // transaction notifications - transaction_pool - .import_notification_stream() - .for_each(move |hash| { - tx_handler_controller.propagate_transaction(hash); - let status = transaction_pool.status(); - telemetry!( - telemetry; - SUBSTRATE_INFO; - "txpool.import"; - "ready" => status.ready, - "future" => status.future, - ); - ready(()) - }) - .await; + let mut notifications = transaction_pool.import_notification_stream().fuse(); + let mut timer = futures_timer::Delay::new(TELEMETRY_INTERVAL).fuse(); + let mut tx_imported = false; + + loop { + select! { + notification = notifications.next() => { + let Some(hash) = notification else { return }; + + tx_handler_controller.propagate_transaction(hash); + + tx_imported = true; + }, + _ = timer => { + timer = futures_timer::Delay::new(TELEMETRY_INTERVAL).fuse(); + + if !tx_imported { + continue; + } + + tx_imported = false; + let status = transaction_pool.status(); + + telemetry!( + telemetry; + SUBSTRATE_INFO; + "txpool.import"; + "ready" => status.ready, + "future" => status.future, + ); + } + } + } } /// Initialize telemetry with provided configuration and return telemetry handle @@ -728,8 +755,7 @@ where client.clone(), backend.clone(), genesis_hash, - // Defaults to sensible limits for the `Archive`. - sc_rpc_spec_v2::archive::ArchiveConfig::default(), + task_executor.clone(), ) .into_rpc(); rpc_api.merge(archive_v2).map_err(|e| Error::Application(e.into()))?; @@ -780,7 +806,7 @@ where Ok(rpc_api) } -/// Parameters to pass into `build_network`. +/// Parameters to pass into [`build_network`]. pub struct BuildNetworkParams<'a, Block, Net, TxPool, IQ, Client> where Block: BlockT, @@ -802,8 +828,8 @@ where pub block_announce_validator_builder: Option< Box) -> Box + Send> + Send>, >, - /// Syncing strategy to use in syncing engine. - pub syncing_strategy: Box>, + /// Optional warp sync config. + pub warp_sync_config: Option>, /// User specified block relay params. If not specified, the default /// block request handler will be used. pub block_relay: Option>, @@ -819,7 +845,6 @@ pub fn build_network( Arc, TracingUnboundedSender>, sc_network_transactions::TransactionsHandlerController<::Hash>, - NetworkStarter, Arc>, ), Error, @@ -847,100 +872,216 @@ where spawn_handle, import_queue, block_announce_validator_builder, - syncing_strategy, + warp_sync_config, block_relay, metrics, } = params; - let protocol_id = config.protocol_id(); - let genesis_hash = client.info().genesis_hash; - let block_announce_validator = if let Some(f) = block_announce_validator_builder { f(client.clone()) } else { Box::new(DefaultBlockAnnounceValidator) }; - let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut block_server, block_downloader, block_request_protocol_config) = match block_relay { - Some(params) => (params.server, params.downloader, params.request_response_config), - None => { - // Custom protocol was not specified, use the default block handler. - // Allow both outgoing and incoming requests. - let params = BlockRequestHandler::new::( - chain_sync_network_handle.clone(), - &protocol_id, - config.chain_spec.fork_id(), - client.clone(), - config.network.default_peers_set.in_peers as usize + - config.network.default_peers_set.out_peers as usize, - ); - (params.server, params.downloader, params.request_response_config) + let network_service_provider = NetworkServiceProvider::new(); + let protocol_id = config.protocol_id(); + let fork_id = config.chain_spec.fork_id(); + let metrics_registry = config.prometheus_config.as_ref().map(|config| &config.registry); + + let block_downloader = match block_relay { + Some(params) => { + let BlockRelayParams { mut server, downloader, request_response_config } = params; + + net_config.add_request_response_protocol(request_response_config); + + spawn_handle.spawn("block-request-handler", Some("networking"), async move { + server.run().await; + }); + + downloader }, + None => build_default_block_downloader( + &protocol_id, + fork_id, + &mut net_config, + network_service_provider.handle(), + Arc::clone(&client), + config.network.default_peers_set.in_peers as usize + + config.network.default_peers_set.out_peers as usize, + &spawn_handle, + ), }; - spawn_handle.spawn("block-request-handler", Some("networking"), async move { - block_server.run().await; - }); + + let syncing_strategy = build_polkadot_syncing_strategy( + protocol_id.clone(), + fork_id, + &mut net_config, + warp_sync_config, + block_downloader, + client.clone(), + &spawn_handle, + metrics_registry, + )?; + + let (syncing_engine, sync_service, block_announce_config) = SyncingEngine::new( + Roles::from(&config.role), + Arc::clone(&client), + metrics_registry, + metrics.clone(), + &net_config, + protocol_id.clone(), + fork_id, + block_announce_validator, + syncing_strategy, + network_service_provider.handle(), + import_queue.service(), + net_config.peer_store_handle(), + )?; + + spawn_handle.spawn_blocking("syncing", None, syncing_engine.run()); + + build_network_advanced(BuildNetworkAdvancedParams { + role: config.role, + protocol_id, + fork_id, + ipfs_server: config.network.ipfs_server, + announce_block: config.announce_block, + net_config, + client, + transaction_pool, + spawn_handle, + import_queue, + sync_service, + block_announce_config, + network_service_provider, + metrics_registry, + metrics, + }) +} + +/// Parameters to pass into [`build_network_advanced`]. +pub struct BuildNetworkAdvancedParams<'a, Block, Net, TxPool, IQ, Client> +where + Block: BlockT, + Net: NetworkBackend::Hash>, +{ + /// Role of the local node. + pub role: Role, + /// Protocol name prefix. + pub protocol_id: ProtocolId, + /// Fork ID. + pub fork_id: Option<&'a str>, + /// Enable serving block data over IPFS bitswap. + pub ipfs_server: bool, + /// Announce block automatically after they have been imported. + pub announce_block: bool, + /// Full network configuration. + pub net_config: FullNetworkConfiguration::Hash, Net>, + /// A shared client returned by `new_full_parts`. + pub client: Arc, + /// A shared transaction pool. + pub transaction_pool: Arc, + /// A handle for spawning tasks. + pub spawn_handle: SpawnTaskHandle, + /// An import queue. + pub import_queue: IQ, + /// Syncing service to communicate with syncing engine. + pub sync_service: SyncingService, + /// Block announce config. + pub block_announce_config: Net::NotificationProtocolConfig, + /// Network service provider to drive with network internally. + pub network_service_provider: NetworkServiceProvider, + /// Prometheus metrics registry. + pub metrics_registry: Option<&'a Registry>, + /// Metrics. + pub metrics: NotificationMetrics, +} + +/// Build the network service, the network status sinks and an RPC sender, this is a lower-level +/// version of [`build_network`] for those needing more control. +pub fn build_network_advanced( + params: BuildNetworkAdvancedParams, +) -> Result< + ( + Arc, + TracingUnboundedSender>, + sc_network_transactions::TransactionsHandlerController<::Hash>, + Arc>, + ), + Error, +> +where + Block: BlockT, + Client: ProvideRuntimeApi + + HeaderMetadata + + Chain + + BlockBackend + + BlockIdTo + + ProofProvider + + HeaderBackend + + BlockchainEvents + + 'static, + TxPool: TransactionPool::Hash> + 'static, + IQ: ImportQueue + 'static, + Net: NetworkBackend::Hash>, +{ + let BuildNetworkAdvancedParams { + role, + protocol_id, + fork_id, + ipfs_server, + announce_block, + mut net_config, + client, + transaction_pool, + spawn_handle, + import_queue, + sync_service, + block_announce_config, + network_service_provider, + metrics_registry, + metrics, + } = params; + + let genesis_hash = client.info().genesis_hash; let light_client_request_protocol_config = { // Allow both outgoing and incoming requests. - let (handler, protocol_config) = LightClientRequestHandler::new::( - &protocol_id, - config.chain_spec.fork_id(), - client.clone(), - ); + let (handler, protocol_config) = + LightClientRequestHandler::new::(&protocol_id, fork_id, client.clone()); spawn_handle.spawn("light-client-request-handler", Some("networking"), handler.run()); protocol_config }; // install request handlers to `FullNetworkConfiguration` - net_config.add_request_response_protocol(block_request_protocol_config); net_config.add_request_response_protocol(light_client_request_protocol_config); - let bitswap_config = config.network.ipfs_server.then(|| { + let bitswap_config = ipfs_server.then(|| { let (handler, config) = Net::bitswap_server(client.clone()); spawn_handle.spawn("bitswap-request-handler", Some("networking"), handler); config }); - // create transactions protocol and add it to the list of supported protocols of - let peer_store_handle = net_config.peer_store_handle(); + // Create transactions protocol and add it to the list of supported protocols of let (transactions_handler_proto, transactions_config) = sc_network_transactions::TransactionsHandlerPrototype::new::<_, Block, Net>( protocol_id.clone(), genesis_hash, - config.chain_spec.fork_id(), + fork_id, metrics.clone(), - Arc::clone(&peer_store_handle), + net_config.peer_store_handle(), ); net_config.add_notification_protocol(transactions_config); // Start task for `PeerStore` let peer_store = net_config.take_peer_store(); - let peer_store_handle = peer_store.handle(); spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); - let (engine, sync_service, block_announce_config) = SyncingEngine::new( - Roles::from(&config.role), - client.clone(), - config.prometheus_config.as_ref().map(|config| config.registry.clone()).as_ref(), - metrics.clone(), - &net_config, - protocol_id.clone(), - &config.chain_spec.fork_id().map(ToOwned::to_owned), - block_announce_validator, - syncing_strategy, - chain_sync_network_handle, - import_queue.service(), - block_downloader, - Arc::clone(&peer_store_handle), - )?; - let sync_service_import_queue = sync_service.clone(); let sync_service = Arc::new(sync_service); let network_params = sc_network::config::Params::::Hash, Net> { - role: config.role, + role, executor: { let spawn_handle = Clone::clone(&spawn_handle); Box::new(move |fut| { @@ -950,8 +1091,8 @@ where network_config: net_config, genesis_hash, protocol_id, - fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), - metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), + fork_id: fork_id.map(ToOwned::to_owned), + metrics_registry: metrics_registry.cloned(), block_announce_config, bitswap_config, notification_metrics: metrics, @@ -965,7 +1106,7 @@ where network.clone(), sync_service.clone(), Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }), - config.prometheus_config.as_ref().map(|config| &config.registry), + metrics_registry, )?; spawn_handle.spawn_blocking( "network-transactions-handler", @@ -976,17 +1117,20 @@ where spawn_handle.spawn_blocking( "chain-sync-network-service-provider", Some("networking"), - chain_sync_network_provider.run(Arc::new(network.clone())), + network_service_provider.run(Arc::new(network.clone())), ); - spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(sync_service_import_queue))); - spawn_handle.spawn_blocking("syncing", None, engine.run()); + spawn_handle.spawn("import-queue", None, { + let sync_service = sync_service.clone(); + + async move { import_queue.run(sync_service.as_ref()).await } + }); let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000); spawn_handle.spawn( "system-rpc-handler", Some("networking"), build_system_rpc_future::<_, _, ::Hash>( - config.role, + role, network_mut.network_service(), sync_service.clone(), client.clone(), @@ -999,25 +1143,9 @@ where network_mut, client, sync_service.clone(), - config.announce_block, + announce_block, ); - // TODO: Normally, one is supposed to pass a list of notifications protocols supported by the - // node through the `NetworkConfiguration` struct. But because this function doesn't know in - // advance which components, such as GrandPa or Polkadot, will be plugged on top of the - // service, it is unfortunately not possible to do so without some deep refactoring. To - // bypass this problem, the `NetworkService` provides a `register_notifications_protocol` - // method that can be called even after the network has been initialized. However, we want to - // avoid the situation where `register_notifications_protocol` is called *after* the network - // actually connects to other peers. For this reason, we delay the process of the network - // future until the user calls `NetworkStarter::start_network`. - // - // This entire hack should eventually be removed in favour of passing the list of protocols - // through the configuration. - // - // See also https://github.com/paritytech/substrate/issues/6827 - let (network_start_tx, network_start_rx) = oneshot::channel(); - // The network worker is responsible for gathering all network messages and processing // them. This is quite a heavy task, and at the time of the writing of this comment it // frequently happens that this future takes several seconds or in some situations @@ -1025,26 +1153,150 @@ where // issue, and ideally we would like to fix the network future to take as little time as // possible, but we also take the extra harm-prevention measure to execute the networking // future using `spawn_blocking`. - spawn_handle.spawn_blocking("network-worker", Some("networking"), async move { - if network_start_rx.await.is_err() { - log::warn!( - "The NetworkStart returned as part of `build_network` has been silently dropped" - ); - // This `return` might seem unnecessary, but we don't want to make it look like - // everything is working as normal even though the user is clearly misusing the API. - return - } + spawn_handle.spawn_blocking("network-worker", Some("networking"), future); - future.await + Ok((network, system_rpc_tx, tx_handler_controller, sync_service.clone())) +} + +/// Configuration for [`build_default_syncing_engine`]. +pub struct DefaultSyncingEngineConfig<'a, Block, Client, Net> +where + Block: BlockT, + Net: NetworkBackend::Hash>, +{ + /// Role of the local node. + pub role: Role, + /// Protocol name prefix. + pub protocol_id: ProtocolId, + /// Fork ID. + pub fork_id: Option<&'a str>, + /// Full network configuration. + pub net_config: &'a mut FullNetworkConfiguration::Hash, Net>, + /// Validator for incoming block announcements. + pub block_announce_validator: Box + Send>, + /// Handle to communicate with `NetworkService`. + pub network_service_handle: NetworkServiceHandle, + /// Warp sync configuration (when used). + pub warp_sync_config: Option>, + /// A shared client returned by `new_full_parts`. + pub client: Arc, + /// Blocks import queue API. + pub import_queue_service: Box>, + /// Expected max total number of peer connections (in + out). + pub num_peers_hint: usize, + /// A handle for spawning tasks. + pub spawn_handle: &'a SpawnTaskHandle, + /// Prometheus metrics registry. + pub metrics_registry: Option<&'a Registry>, + /// Metrics. + pub metrics: NotificationMetrics, +} + +/// Build default syncing engine using [`build_default_block_downloader`] and +/// [`build_polkadot_syncing_strategy`] internally. +pub fn build_default_syncing_engine( + config: DefaultSyncingEngineConfig, +) -> Result<(SyncingService, Net::NotificationProtocolConfig), Error> +where + Block: BlockT, + Client: HeaderBackend + + BlockBackend + + HeaderMetadata + + ProofProvider + + Send + + Sync + + 'static, + Net: NetworkBackend::Hash>, +{ + let DefaultSyncingEngineConfig { + role, + protocol_id, + fork_id, + net_config, + block_announce_validator, + network_service_handle, + warp_sync_config, + client, + import_queue_service, + num_peers_hint, + spawn_handle, + metrics_registry, + metrics, + } = config; + + let block_downloader = build_default_block_downloader( + &protocol_id, + fork_id, + net_config, + network_service_handle.clone(), + client.clone(), + num_peers_hint, + spawn_handle, + ); + let syncing_strategy = build_polkadot_syncing_strategy( + protocol_id.clone(), + fork_id, + net_config, + warp_sync_config, + block_downloader, + client.clone(), + spawn_handle, + metrics_registry, + )?; + + let (syncing_engine, sync_service, block_announce_config) = SyncingEngine::new( + Roles::from(&role), + client, + metrics_registry, + metrics, + &net_config, + protocol_id, + fork_id, + block_announce_validator, + syncing_strategy, + network_service_handle, + import_queue_service, + net_config.peer_store_handle(), + )?; + + spawn_handle.spawn_blocking("syncing", None, syncing_engine.run()); + + Ok((sync_service, block_announce_config)) +} + +/// Build default block downloader +pub fn build_default_block_downloader( + protocol_id: &ProtocolId, + fork_id: Option<&str>, + net_config: &mut FullNetworkConfiguration::Hash, Net>, + network_service_handle: NetworkServiceHandle, + client: Arc, + num_peers_hint: usize, + spawn_handle: &SpawnTaskHandle, +) -> Arc> +where + Block: BlockT, + Client: HeaderBackend + BlockBackend + Send + Sync + 'static, + Net: NetworkBackend::Hash>, +{ + // Custom protocol was not specified, use the default block handler. + // Allow both outgoing and incoming requests. + let BlockRelayParams { mut server, downloader, request_response_config } = + BlockRequestHandler::new::( + network_service_handle, + &protocol_id, + fork_id, + client.clone(), + num_peers_hint, + ); + + spawn_handle.spawn("block-request-handler", Some("networking"), async move { + server.run().await; }); - Ok(( - network, - system_rpc_tx, - tx_handler_controller, - NetworkStarter(network_start_tx), - sync_service.clone(), - )) + net_config.add_request_response_protocol(request_response_config); + + downloader } /// Build standard polkadot syncing strategy @@ -1053,6 +1305,7 @@ pub fn build_polkadot_syncing_strategy( fork_id: Option<&str>, net_config: &mut FullNetworkConfiguration::Hash, Net>, warp_sync_config: Option>, + block_downloader: Arc>, client: Arc, spawn_handle: &SpawnTaskHandle, metrics_registry: Option<&Registry>, @@ -1066,7 +1319,6 @@ where + Send + Sync + 'static, - Net: NetworkBackend::Hash>, { if warp_sync_config.is_none() && net_config.network_config.sync_mode.is_warp() { @@ -1117,12 +1369,13 @@ where net_config.add_request_response_protocol(config); } - let syncing_config = SyncingConfig { + let syncing_config = PolkadotSyncingStrategyConfig { mode: net_config.network_config.sync_mode, max_parallel_downloads: net_config.network_config.max_parallel_downloads, max_blocks_per_request: net_config.network_config.max_blocks_per_request, metrics_registry: metrics_registry.cloned(), state_request_protocol_name, + block_downloader, }; Ok(Box::new(PolkadotSyncingStrategy::new( syncing_config, @@ -1131,21 +1384,3 @@ where warp_sync_protocol_name, )?)) } - -/// Object used to start the network. -#[must_use] -pub struct NetworkStarter(oneshot::Sender<()>); - -impl NetworkStarter { - /// Create a new NetworkStarter - pub fn new(sender: oneshot::Sender<()>) -> Self { - NetworkStarter(sender) - } - - /// Start the network. Call this after all sub-components have been initialized. - /// - /// > **Note**: If you don't call this function, the networking will not work. - pub fn start_network(self) { - let _ = self.0.send(()); - } -} diff --git a/substrate/client/service/src/chain_ops/import_blocks.rs b/substrate/client/service/src/chain_ops/import_blocks.rs index 661fc09a8f19..8e759faa0775 100644 --- a/substrate/client/service/src/chain_ops/import_blocks.rs +++ b/substrate/client/service/src/chain_ops/import_blocks.rs @@ -37,6 +37,10 @@ use sp_runtime::{ use std::{ io::Read, pin::Pin, + sync::{ + atomic::{AtomicBool, AtomicU64, Ordering}, + Arc, + }, task::Poll, time::{Duration, Instant}, }; @@ -50,8 +54,6 @@ const DELAY_TIME: u64 = 200; /// Number of milliseconds that must have passed between two updates. const TIME_BETWEEN_UPDATES: u64 = 3_000; -use std::sync::Arc; - /// Build a chain spec json pub fn build_spec(spec: &dyn ChainSpec, raw: bool) -> error::Result { spec.as_json(raw).map_err(Into::into) @@ -301,29 +303,29 @@ where IQ: ImportQueue + 'static, { struct WaitLink { - imported_blocks: u64, - has_error: bool, + imported_blocks: AtomicU64, + has_error: AtomicBool, } impl WaitLink { fn new() -> WaitLink { - WaitLink { imported_blocks: 0, has_error: false } + WaitLink { imported_blocks: AtomicU64::new(0), has_error: AtomicBool::new(false) } } } impl Link for WaitLink { fn blocks_processed( - &mut self, + &self, imported: usize, _num_expected_blocks: usize, results: Vec<(Result>, BlockImportError>, B::Hash)>, ) { - self.imported_blocks += imported as u64; + self.imported_blocks.fetch_add(imported as u64, Ordering::AcqRel); for result in results { if let (Err(err), hash) = result { warn!("There was an error importing block with hash {:?}: {}", hash, err); - self.has_error = true; + self.has_error.store(true, Ordering::Release); break } } @@ -373,7 +375,9 @@ where let read_block_count = block_iter.read_block_count(); match block_result { Ok(block) => { - if read_block_count - link.imported_blocks >= MAX_PENDING_BLOCKS { + if read_block_count - link.imported_blocks.load(Ordering::Acquire) >= + MAX_PENDING_BLOCKS + { // The queue is full, so do not add this block and simply wait // until the queue has made some progress. let delay = Delay::new(Duration::from_millis(DELAY_TIME)); @@ -399,7 +403,9 @@ where }, ImportState::WaitingForImportQueueToCatchUp { block_iter, mut delay, block } => { let read_block_count = block_iter.read_block_count(); - if read_block_count - link.imported_blocks >= MAX_PENDING_BLOCKS { + if read_block_count - link.imported_blocks.load(Ordering::Acquire) >= + MAX_PENDING_BLOCKS + { // Queue is still full, so wait until there is room to insert our block. match Pin::new(&mut delay).poll(cx) { Poll::Pending => { @@ -433,7 +439,11 @@ where } => { // All the blocks have been added to the queue, which doesn't mean they // have all been properly imported. - if importing_is_done(num_expected_blocks, read_block_count, link.imported_blocks) { + if importing_is_done( + num_expected_blocks, + read_block_count, + link.imported_blocks.load(Ordering::Acquire), + ) { // Importing is done, we can log the result and return. info!( "🎉 Imported {} blocks. Best: #{}", @@ -472,10 +482,10 @@ where let best_number = client.info().best_number; speedometer.notify_user(best_number); - if link.has_error { + if link.has_error.load(Ordering::Acquire) { return Poll::Ready(Err(Error::Other(format!( "Stopping after #{} blocks because of an error", - link.imported_blocks + link.imported_blocks.load(Ordering::Acquire) )))) } diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index ce5b92551bf2..eddbb9260c05 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -85,10 +85,8 @@ use std::{ sync::Arc, }; -#[cfg(feature = "test-helpers")] -use { - super::call_executor::LocalCallExecutor, sc_client_api::in_mem, sp_core::traits::CodeExecutor, -}; +use super::call_executor::LocalCallExecutor; +use sp_core::traits::CodeExecutor; type NotificationSinks = Mutex>>; @@ -152,39 +150,6 @@ enum PrepareStorageChangesResult { Discard(ImportResult), Import(Option>), } - -/// Create an instance of in-memory client. -#[cfg(feature = "test-helpers")] -pub fn new_in_mem( - backend: Arc>, - executor: E, - genesis_block_builder: G, - prometheus_registry: Option, - telemetry: Option, - spawn_handle: Box, - config: ClientConfig, -) -> sp_blockchain::Result< - Client, LocalCallExecutor, E>, Block, RA>, -> -where - E: CodeExecutor + sc_executor::RuntimeVersionOf, - Block: BlockT, - G: BuildGenesisBlock< - Block, - BlockImportOperation = as backend::Backend>::BlockImportOperation, - >, -{ - new_with_backend( - backend, - executor, - genesis_block_builder, - spawn_handle, - prometheus_registry, - telemetry, - config, - ) -} - /// Client configuration items. #[derive(Debug, Clone)] pub struct ClientConfig { @@ -218,7 +183,6 @@ impl Default for ClientConfig { /// Create a client with the explicitly provided backend. /// This is useful for testing backend implementations. -#[cfg(feature = "test-helpers")] pub fn new_with_backend( backend: Arc, executor: E, diff --git a/substrate/client/service/src/client/mod.rs b/substrate/client/service/src/client/mod.rs index ec77a92f162f..3020b3d296f4 100644 --- a/substrate/client/service/src/client/mod.rs +++ b/substrate/client/service/src/client/mod.rs @@ -56,5 +56,4 @@ pub use call_executor::LocalCallExecutor; pub use client::{Client, ClientConfig}; pub(crate) use code_provider::CodeProvider; -#[cfg(feature = "test-helpers")] -pub use self::client::{new_in_mem, new_with_backend}; +pub use self::client::new_with_backend; diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index 3df9020b0418..2a3144a33e1a 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -23,14 +23,11 @@ #![recursion_limit = "1024"] pub mod chain_ops; +pub mod client; pub mod config; pub mod error; mod builder; -#[cfg(feature = "test-helpers")] -pub mod client; -#[cfg(not(feature = "test-helpers"))] -mod client; mod metrics; mod task_manager; @@ -59,11 +56,13 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; pub use self::{ builder::{ - build_network, build_polkadot_syncing_strategy, gen_rpc_module, init_telemetry, new_client, - new_db_backend, new_full_client, new_full_parts, new_full_parts_record_import, + build_default_block_downloader, build_default_syncing_engine, build_network, + build_network_advanced, build_polkadot_syncing_strategy, gen_rpc_module, init_telemetry, + new_client, new_db_backend, new_full_client, new_full_parts, new_full_parts_record_import, new_full_parts_with_genesis_builder, new_wasm_executor, - propagate_transaction_notifications, spawn_tasks, BuildNetworkParams, KeystoreContainer, - NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, TFullClient, + propagate_transaction_notifications, spawn_tasks, BuildNetworkAdvancedParams, + BuildNetworkParams, DefaultSyncingEngineConfig, KeystoreContainer, SpawnTasksParams, + TFullBackend, TFullCallExecutor, TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, @@ -526,13 +525,17 @@ where }; let start = std::time::Instant::now(); - let import_future = self.pool.submit_one( - self.client.info().best_hash, - sc_transaction_pool_api::TransactionSource::External, - uxt, - ); + let pool = self.pool.clone(); + let client = self.client.clone(); Box::pin(async move { - match import_future.await { + match pool + .submit_one( + client.info().best_hash, + sc_transaction_pool_api::TransactionSource::External, + uxt, + ) + .await + { Ok(_) => { let elapsed = start.elapsed(); debug!(target: sc_transaction_pool::LOG_TARGET, "import transaction: {elapsed:?}"); @@ -593,8 +596,8 @@ mod tests { let transaction = Transfer { amount: 5, nonce: 0, - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), } .into_unchecked_extrinsic(); block_on(pool.submit_one(best.hash(), source, transaction.clone())).unwrap(); diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index 0edfc5b19314..45b2d8c5eea3 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -15,15 +15,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-channel = { workspace = true } array-bytes = { workspace = true, default-features = true } +async-channel = { workspace = true } +codec = { workspace = true, default-features = true } fdlimit = { workspace = true } futures = { workspace = true } log = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -tempfile = { workspace = true } -tokio = { features = ["time"], workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-client-db = { workspace = true } @@ -31,17 +29,19 @@ sc-consensus = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } -sc-service = { features = ["test-helpers"], workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } sp-storage = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } substrate-test-runtime = { workspace = true } substrate-test-runtime-client = { workspace = true } +tempfile = { workspace = true } +tokio = { features = ["time"], workspace = true, default-features = true } diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index 55bbfcdd8594..ef5de93d64ca 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -29,7 +29,7 @@ use sc_consensus::{ BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, }; use sc_executor::WasmExecutor; -use sc_service::client::{new_in_mem, Client, LocalCallExecutor}; +use sc_service::client::{new_with_backend, Client, LocalCallExecutor}; use sp_api::ProvideRuntimeApi; use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; use sp_core::{testing::TaskExecutor, traits::CallContext, H256}; @@ -48,8 +48,8 @@ use substrate_test_runtime_client::{ genesismap::{insert_genesis_block, GenesisStorageBuilder}, Block, BlockNumber, Digest, Hash, Header, RuntimeApi, Transfer, }, - AccountKeyring, BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, - Sr25519Keyring, TestClientBuilder, TestClientBuilderExt, + BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, Sr25519Keyring, + TestClientBuilder, TestClientBuilderExt, }; mod db; @@ -126,8 +126,8 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> Vec 1, genesis_hash, vec![Transfer { - from: AccountKeyring::One.into(), - to: AccountKeyring::Two.into(), + from: Sr25519Keyring::One.into(), + to: Sr25519Keyring::Two.into(), amount: 69 * DOLLARS, nonce: 0, }], @@ -158,7 +158,7 @@ fn finality_notification_check( fn construct_genesis_should_work_with_native() { let mut storage = GenesisStorageBuilder::new( vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], - vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()], 1000 * DOLLARS, ) .build(); @@ -189,7 +189,7 @@ fn construct_genesis_should_work_with_native() { fn construct_genesis_should_work_with_wasm() { let mut storage = GenesisStorageBuilder::new( vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], - vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()], 1000 * DOLLARS, ) .build(); @@ -223,14 +223,14 @@ fn client_initializes_from_genesis_ok() { assert_eq!( client .runtime_api() - .balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into()) + .balance_of(client.chain_info().best_hash, Sr25519Keyring::Alice.into()) .unwrap(), 1000 * DOLLARS ); assert_eq!( client .runtime_api() - .balance_of(client.chain_info().best_hash, AccountKeyring::Ferdie.into()) + .balance_of(client.chain_info().best_hash, Sr25519Keyring::Ferdie.into()) .unwrap(), 0 * DOLLARS ); @@ -266,8 +266,8 @@ fn block_builder_works_with_transactions() { builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42 * DOLLARS, nonce: 0, }) @@ -301,14 +301,14 @@ fn block_builder_works_with_transactions() { assert_eq!( client .runtime_api() - .balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into()) + .balance_of(client.chain_info().best_hash, Sr25519Keyring::Alice.into()) .unwrap(), 958 * DOLLARS ); assert_eq!( client .runtime_api() - .balance_of(client.chain_info().best_hash, AccountKeyring::Ferdie.into()) + .balance_of(client.chain_info().best_hash, Sr25519Keyring::Ferdie.into()) .unwrap(), 42 * DOLLARS ); @@ -325,8 +325,8 @@ fn block_builder_does_not_include_invalid() { builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 42 * DOLLARS, nonce: 0, }) @@ -334,8 +334,8 @@ fn block_builder_does_not_include_invalid() { assert!(builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 30 * DOLLARS, nonce: 0, }) @@ -491,8 +491,8 @@ fn uncles_with_multiple_forks() { // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41 * DOLLARS, nonce: 0, }) @@ -531,8 +531,8 @@ fn uncles_with_multiple_forks() { // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 1, }) @@ -549,8 +549,8 @@ fn uncles_with_multiple_forks() { // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) @@ -691,8 +691,8 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41 * DOLLARS, nonce: 0, }) @@ -732,8 +732,8 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 1, }) @@ -751,8 +751,8 @@ fn finality_target_on_longest_chain_with_multiple_forks() { // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) @@ -982,8 +982,8 @@ fn finality_target_with_best_not_on_longest_chain() { // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41 * DOLLARS, nonce: 0, }) @@ -1134,8 +1134,8 @@ fn importing_diverged_finalized_block_should_trigger_reorg() { .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) @@ -1195,8 +1195,8 @@ fn finalizing_diverged_block_should_trigger_reorg() { .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) @@ -1303,8 +1303,8 @@ fn finality_notifications_content() { .unwrap(); // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 0, }) @@ -1329,8 +1329,8 @@ fn finality_notifications_content() { .unwrap(); // needed to make sure B1 gets a different hash from A1 c1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 2 * DOLLARS, nonce: 0, }) @@ -1346,8 +1346,8 @@ fn finality_notifications_content() { // needed to make sure D3 gets a different hash from A3 d3.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 2 * DOLLARS, nonce: 0, }) @@ -1415,7 +1415,7 @@ fn state_reverted_on_reorg() { let current_balance = |client: &substrate_test_runtime_client::TestClient| { client .runtime_api() - .balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into()) + .balance_of(client.chain_info().best_hash, Sr25519Keyring::Alice.into()) .unwrap() }; @@ -1428,8 +1428,8 @@ fn state_reverted_on_reorg() { .build() .unwrap(); a1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), amount: 10 * DOLLARS, nonce: 0, }) @@ -1443,8 +1443,8 @@ fn state_reverted_on_reorg() { .build() .unwrap(); b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 50 * DOLLARS, nonce: 0, }) @@ -1460,8 +1460,8 @@ fn state_reverted_on_reorg() { .build() .unwrap(); a2.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Charlie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Charlie.into(), amount: 10 * DOLLARS, nonce: 1, }) @@ -1530,8 +1530,8 @@ fn doesnt_import_blocks_that_revert_finality() { // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) @@ -1580,8 +1580,8 @@ fn doesnt_import_blocks_that_revert_finality() { // needed to make sure C1 gets a different hash from A1 and B1 c1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 2 * DOLLARS, nonce: 0, }) @@ -1788,8 +1788,8 @@ fn returns_status_for_pruned_blocks() { // b1 is created, but not imported b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) @@ -2087,13 +2087,13 @@ fn cleans_up_closed_notification_sinks_on_block_import() { // NOTE: we need to build the client here instead of using the client // provided by test_runtime_client otherwise we can't access the private // `import_notification_sinks` and `finality_notification_sinks` fields. - let mut client = new_in_mem::<_, Block, _, RuntimeApi>( + let mut client = new_with_backend::<_, _, Block, _, RuntimeApi>( backend, executor, genesis_block_builder, + Box::new(TaskExecutor::new()), None, None, - Box::new(TaskExecutor::new()), client_config, ) .unwrap(); @@ -2191,8 +2191,8 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi // needed to make sure B1 gets a different hash from A1 b1.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1 * DOLLARS, nonce: 0, }) diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index e5087eae6eca..c0219b294ced 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -17,18 +17,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true, default-features = true } -parking_lot = { workspace = true, default-features = true } parity-db = { workspace = true } -tokio = { features = ["time"], workspace = true, default-features = true } -sp-statement-store = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-keystore = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sc-keystore = { workspace = true, default-features = true } +sp-statement-store = { workspace = true, default-features = true } +tokio = { features = ["time"], workspace = true, default-features = true } [dev-dependencies] -tempfile = { workspace = true } sp-tracing = { workspace = true } +tempfile = { workspace = true } diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index c017184ced66..3d8cb72b1a92 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -13,8 +13,8 @@ workspace = true [dependencies] clap = { features = ["derive", "string"], workspace = true } -log = { workspace = true, default-features = true } fs4 = { workspace = true } +log = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -tokio = { features = ["time"], workspace = true, default-features = true } thiserror = { workspace = true } +tokio = { features = ["time"], workspace = true, default-features = true } diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index cbab8f4d7b0d..91c30f5aa2cc 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -17,13 +17,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true, default-features = true } jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } -serde = { features = ["derive"], workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -thiserror = { workspace = true } sc-chain-spec = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-consensus-babe = { workspace = true, default-features = true } sc-consensus-epochs = { workspace = true, default-features = true } sc-consensus-grandpa = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +thiserror = { workspace = true } diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 190e6e279b90..c7eed77eda7f 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -17,16 +17,16 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +derive_more = { workspace = true, default-features = true } futures = { workspace = true } libc = { workspace = true } log = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } rand_pcg = { workspace = true } -derive_more = { workspace = true, default-features = true } regex = { workspace = true } +sc-telemetry = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -sc-telemetry = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index f87e8b66f731..4a41a6b6deca 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = { workspace = true } futures = { workspace = true } -libp2p = { features = ["dns", "tcp", "tokio", "wasm-ext", "websocket"], workspace = true } +libp2p = { features = ["dns", "tcp", "tokio", "websocket"], workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } pin-project = { workspace = true } -sc-utils = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-utils = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/telemetry/src/node.rs b/substrate/client/telemetry/src/node.rs index 0bbdbfb622ef..2c8d424c4340 100644 --- a/substrate/client/telemetry/src/node.rs +++ b/substrate/client/telemetry/src/node.rs @@ -18,7 +18,13 @@ use crate::TelemetryPayload; use futures::{channel::mpsc, prelude::*}; -use libp2p::{core::transport::Transport, Multiaddr}; +use libp2p::{ + core::{ + transport::{DialOpts, PortUse, Transport}, + Endpoint, + }, + Multiaddr, +}; use rand::Rng as _; use std::{ fmt, mem, @@ -229,7 +235,10 @@ where }, NodeSocket::ReconnectNow => { let addr = self.addr.clone(); - match self.transport.dial(addr) { + match self + .transport + .dial(addr, DialOpts { role: Endpoint::Dialer, port_use: PortUse::New }) + { Ok(d) => { log::trace!(target: "telemetry", "Re-dialing {}", self.addr); socket = NodeSocket::Dialing(d); diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index b8f5e40caf83..949f6f6018ad 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -16,30 +16,30 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -console = { workspace = true } -is-terminal = { workspace = true } chrono = { workspace = true } codec = { workspace = true, default-features = true } +console = { workspace = true } +is-terminal = { workspace = true } libc = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } rustc-hash = { workspace = true } -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", -] } sc-client-api = { workspace = true, default-features = true } sc-tracing-proc-macro = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-rpc = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-tracing = { 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", +] } [dev-dependencies] criterion = { workspace = true, default-features = true } diff --git a/substrate/client/tracing/src/logging/directives.rs b/substrate/client/tracing/src/logging/directives.rs index a99e9c4c8909..811511bb20f5 100644 --- a/substrate/client/tracing/src/logging/directives.rs +++ b/substrate/client/tracing/src/logging/directives.rs @@ -40,7 +40,7 @@ pub(crate) fn add_default_directives(directives: &str) { add_directives(directives); } -/// Add directives to current directives +/// Add directives to current directives. pub fn add_directives(directives: &str) { CURRENT_DIRECTIVES .get_or_init(|| Mutex::new(Vec::new())) @@ -48,6 +48,11 @@ pub fn add_directives(directives: &str) { .push(directives.to_owned()); } +/// Returns the current directives. +pub fn get_directives() -> Vec { + CURRENT_DIRECTIVES.get_or_init(|| Mutex::new(Vec::new())).lock().clone() +} + /// Parse `Directive` and add to default directives if successful. /// /// Ensures the supplied directive will be restored when resetting the log filter. diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index d346add93a64..72586b984920 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -25,12 +25,11 @@ itertools = { workspace = true } linked-hash-map = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } prometheus-endpoint = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } @@ -38,8 +37,9 @@ sp-crypto-hashing = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } sp-transaction-pool = { workspace = true, default-features = true } -tokio-stream = { workspace = true } +thiserror = { workspace = true } tokio = { workspace = true, default-features = true, features = ["macros", "time"] } +tokio-stream = { workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index c55ee70b2cf5..6671492a4e92 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -17,10 +17,10 @@ codec = { workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } -thiserror = { workspace = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +thiserror = { workspace = true } [dev-dependencies] serde_json = { workspace = true, default-features = true } diff --git a/substrate/client/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index 3ac1a79a0c28..6f771e9479bd 100644 --- a/substrate/client/transaction-pool/api/src/lib.rs +++ b/substrate/client/transaction-pool/api/src/lib.rs @@ -23,7 +23,7 @@ pub mod error; use async_trait::async_trait; use codec::Codec; -use futures::{Future, Stream}; +use futures::Stream; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_core::offchain::TransactionPoolExt; use sp_runtime::traits::{Block as BlockT, Member}; @@ -208,9 +208,6 @@ pub type LocalTransactionFor

= <

::Block as BlockT> /// Transaction's index within the block in which it was included. pub type TxIndex = usize; -/// Typical future type used in transaction pool api. -pub type PoolFuture = std::pin::Pin> + Send>>; - /// In-pool transaction interface. /// /// The pool is container of transactions that are implementing this trait. @@ -238,6 +235,7 @@ pub trait InPoolTransaction { } /// Transaction pool interface. +#[async_trait] pub trait TransactionPool: Send + Sync { /// Block type. type Block: BlockT; @@ -253,46 +251,40 @@ pub trait TransactionPool: Send + Sync { // *** RPC - /// Returns a future that imports a bunch of unverified transactions to the pool. - fn submit_at( + /// Asynchronously imports a bunch of unverified transactions to the pool. + async fn submit_at( &self, at: ::Hash, source: TransactionSource, xts: Vec>, - ) -> PoolFuture, Self::Error>>, Self::Error>; + ) -> Result, Self::Error>>, Self::Error>; - /// Returns a future that imports one unverified transaction to the pool. - fn submit_one( + /// Asynchronously imports one unverified transaction to the pool. + async fn submit_one( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture, Self::Error>; + ) -> Result, Self::Error>; - /// Returns a future that imports a single transaction and starts to watch their progress in the + /// Asynchronously imports a single transaction and starts to watch their progress in the /// pool. - fn submit_and_watch( + async fn submit_and_watch( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture>>, Self::Error>; + ) -> Result>>, Self::Error>; // *** Block production / Networking /// Get an iterator for ready transactions ordered by priority. /// - /// Guarantees to return only when transaction pool got updated at `at` block. - /// Guarantees to return immediately when `None` is passed. - fn ready_at( + /// Guaranteed to resolve only when transaction pool got updated at `at` block. + /// Guaranteed to resolve immediately when `None` is passed. + async fn ready_at( &self, at: ::Hash, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send, - >, - >; + ) -> Box> + Send>; /// Get an iterator for ready transactions ordered by priority. fn ready(&self) -> Box> + Send>; @@ -322,22 +314,15 @@ pub trait TransactionPool: Send + Sync { /// Return specific ready transaction by hash, if there is one. fn ready_transaction(&self, hash: &TxHash) -> Option>; - /// Returns set of ready transaction at given block within given timeout. + /// Asynchronously returns a set of ready transaction at given block within given timeout. /// - /// If the timeout is hit during method execution then the best effort set of ready transactions - /// for given block, without executing full maintain process is returned. - fn ready_at_with_timeout( + /// If the timeout is hit during method execution, then the best effort (without executing full + /// maintain process) set of ready transactions for given block is returned. + async fn ready_at_with_timeout( &self, at: ::Hash, timeout: std::time::Duration, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send - + '_, - >, - >; + ) -> Box> + Send>; } /// An iterator of ready transactions. diff --git a/substrate/client/transaction-pool/benches/basics.rs b/substrate/client/transaction-pool/benches/basics.rs index 0d8c1cbba9b4..5e40b0fb72d6 100644 --- a/substrate/client/transaction-pool/benches/basics.rs +++ b/substrate/client/transaction-pool/benches/basics.rs @@ -152,7 +152,7 @@ fn uxt(transfer: TransferData) -> Extrinsic { } fn bench_configured(pool: Pool, number: u64, api: Arc) { - let source = TransactionSource::External; + let source = TimedTransactionSource::new_external(false); let mut futures = Vec::new(); let mut tags = Vec::new(); let at = HashAndNumber { @@ -171,7 +171,7 @@ fn bench_configured(pool: Pool, number: u64, api: Arc) { tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1)))); - futures.push(pool.submit_one(&at, source, xt)); + futures.push(pool.submit_one(&at, source.clone(), xt)); } let res = block_on(futures::future::join_all(futures.into_iter())); diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/dropped_watcher.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/dropped_watcher.rs index 2dd5836c570f..7679e3b169d2 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/dropped_watcher.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/dropped_watcher.rs @@ -24,7 +24,7 @@ use crate::{ common::log_xt::log_xt_trace, fork_aware_txpool::stream_map_util::next_event, - graph::{BlockHash, ChainApi, ExtrinsicHash}, + graph::{self, BlockHash, ExtrinsicHash}, LOG_TARGET, }; use futures::stream::StreamExt; @@ -33,12 +33,44 @@ use sc_transaction_pool_api::TransactionStatus; use sc_utils::mpsc; use sp_runtime::traits::Block as BlockT; use std::{ - collections::{hash_map::Entry, HashMap, HashSet}, + collections::{ + hash_map::{Entry, OccupiedEntry}, + HashMap, HashSet, + }, fmt::{self, Debug, Formatter}, pin::Pin, }; use tokio_stream::StreamMap; +/// Represents a transaction that was removed from the transaction pool, including the reason of its +/// removal. +#[derive(Debug, PartialEq)] +pub struct DroppedTransaction { + /// Hash of the dropped extrinsic. + pub tx_hash: Hash, + /// Reason of the transaction being dropped. + pub reason: DroppedReason, +} + +impl DroppedTransaction { + fn new_usurped(tx_hash: Hash, by: Hash) -> Self { + Self { reason: DroppedReason::Usurped(by), tx_hash } + } + + fn new_enforced_by_limts(tx_hash: Hash) -> Self { + Self { reason: DroppedReason::LimitsEnforced, tx_hash } + } +} + +/// Provides reason of why transactions was dropped. +#[derive(Debug, PartialEq)] +pub enum DroppedReason { + /// Transaction was replaced by other transaction (e.g. because of higher priority). + Usurped(Hash), + /// Transaction was dropped because of internal pool limits being enforced. + LimitsEnforced, +} + /// Dropped-logic related event from the single view. pub type ViewStreamEvent = crate::graph::DroppedByLimitsEvent, BlockHash>; @@ -47,7 +79,8 @@ type ViewStream = Pin> + Se /// Stream of extrinsic hashes that were dropped by the views and have no references by existing /// views. -pub(crate) type StreamOfDropped = Pin> + Send>>; +pub(crate) type StreamOfDropped = + Pin>> + Send>>; /// A type alias for a sender used as the controller of the [`MultiViewDropWatcherContext`]. /// Used to send control commands from the [`MultiViewDroppedWatcherController`] to @@ -59,38 +92,29 @@ type Controller = mpsc::TracingUnboundedSender; type CommandReceiver = mpsc::TracingUnboundedReceiver; /// Commands to control the instance of dropped transactions stream [`StreamOfDropped`]. -enum Command +enum Command where - C: ChainApi, + ChainApi: graph::ChainApi, { /// Adds a new stream of dropped-related events originating in a view with a specific block /// hash - AddView(BlockHash, ViewStream), + AddView(BlockHash, ViewStream), /// Removes an existing view's stream associated with a specific block hash. - RemoveView(BlockHash), - /// Adds initial views for given extrinsics hashes. - /// - /// This message should be sent when the external submission of a transaction occures. It - /// provides the list of initial views for given extrinsics hashes. - /// The dropped notification is not sent if it comes from the initial views. It allows to keep - /// transaction in the mempool, even if all the views are full at the time of submitting - /// transaction to the pool. - AddInitialViews(Vec>, BlockHash), - /// Removes all initial views for given extrinsic hashes. + RemoveView(BlockHash), + /// Removes referencing views for given extrinsic hashes. /// /// Intended to ba called on finalization. - RemoveFinalizedTxs(Vec>), + RemoveFinalizedTxs(Vec>), } -impl Debug for Command +impl Debug for Command where - C: ChainApi, + ChainApi: graph::ChainApi, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Command::AddView(..) => write!(f, "AddView"), Command::RemoveView(..) => write!(f, "RemoveView"), - Command::AddInitialViews(..) => write!(f, "AddInitialViews"), Command::RemoveFinalizedTxs(..) => write!(f, "RemoveFinalizedTxs"), } } @@ -101,37 +125,114 @@ where /// /// This struct maintains a mapping of active views and their corresponding streams, as well as the /// state of each transaction with respect to these views. -struct MultiViewDropWatcherContext +struct MultiViewDropWatcherContext where - C: ChainApi, + ChainApi: graph::ChainApi, { /// A map that associates the views identified by corresponding block hashes with their streams /// of dropped-related events. This map is used to keep track of active views and their event /// streams. - stream_map: StreamMap, ViewStream>, + stream_map: StreamMap, ViewStream>, /// A receiver for commands to control the state of the stream, allowing the addition and /// removal of views. This is used to dynamically update which views are being tracked. - command_receiver: CommandReceiver>, - + command_receiver: CommandReceiver>, /// For each transaction hash we keep the set of hashes representing the views that see this - /// transaction as ready or future. + /// transaction as ready or in_block. + /// + /// Even if all views referencing a ready transactions are removed, we still want to keep + /// transaction, there can be a fork which sees the transaction as ready. /// /// Once transaction is dropped, dropping view is removed from the set. - transaction_states: HashMap, HashSet>>, - - /// The list of initial view for every extrinsic. + ready_transaction_views: HashMap, HashSet>>, + /// For each transaction hash we keep the set of hashes representing the views that see this + /// transaction as future. + /// + /// Once all views referencing a future transactions are removed, the future can be dropped. /// - /// Dropped notifications from initial views will be silenced. This allows to accept the - /// transaction into the mempool, even if all the views are full at the time of submitting new - /// transaction. - initial_views: HashMap, HashSet>>, + /// Once transaction is dropped, dropping view is removed from the set. + future_transaction_views: HashMap, HashSet>>, + + /// Transactions that need to be notified as dropped. + pending_dropped_transactions: Vec>, } impl MultiViewDropWatcherContext where - C: ChainApi + 'static, - <::Block as BlockT>::Hash: Unpin, + C: graph::ChainApi + 'static, + <::Block as BlockT>::Hash: Unpin, { + /// Provides the ready or future `HashSet` containing views referencing given transaction. + fn transaction_views( + &mut self, + tx_hash: ExtrinsicHash, + ) -> Option, HashSet>>> { + if let Entry::Occupied(views_keeping_tx_valid) = self.ready_transaction_views.entry(tx_hash) + { + return Some(views_keeping_tx_valid) + } + if let Entry::Occupied(views_keeping_tx_valid) = + self.future_transaction_views.entry(tx_hash) + { + return Some(views_keeping_tx_valid) + } + None + } + + /// Processes the command and updates internal state accordingly. + fn handle_command(&mut self, cmd: Command) { + match cmd { + Command::AddView(key, stream) => { + trace!( + target: LOG_TARGET, + "dropped_watcher: Command::AddView {key:?} views:{:?}", + self.stream_map.keys().collect::>() + ); + self.stream_map.insert(key, stream); + }, + Command::RemoveView(key) => { + trace!( + target: LOG_TARGET, + "dropped_watcher: Command::RemoveView {key:?} views:{:?}", + self.stream_map.keys().collect::>() + ); + self.stream_map.remove(&key); + self.ready_transaction_views.iter_mut().for_each(|(tx_hash, views)| { + trace!( + target: LOG_TARGET, + "[{:?}] dropped_watcher: Command::RemoveView ready views: {:?}", + tx_hash, + views + ); + views.remove(&key); + }); + + self.future_transaction_views.iter_mut().for_each(|(tx_hash, views)| { + trace!( + target: LOG_TARGET, + "[{:?}] dropped_watcher: Command::RemoveView future views: {:?}", + tx_hash, + views + ); + views.remove(&key); + if views.is_empty() { + self.pending_dropped_transactions.push(*tx_hash); + } + }); + }, + Command::RemoveFinalizedTxs(xts) => { + log_xt_trace!( + target: LOG_TARGET, + xts.clone(), + "[{:?}] dropped_watcher: finalized xt removed" + ); + xts.iter().for_each(|xt| { + self.ready_transaction_views.remove(xt); + self.future_transaction_views.remove(xt); + }); + }, + } + } + /// Processes a `ViewStreamEvent` from a specific view and updates the internal state /// accordingly. /// @@ -141,49 +242,69 @@ where &mut self, block_hash: BlockHash, event: ViewStreamEvent, - ) -> Option> { + ) -> Option>> { trace!( target: LOG_TARGET, - "dropped_watcher: handle_event: event:{:?} views:{:?}, ", - event, + "dropped_watcher: handle_event: event:{event:?} from:{block_hash:?} future_views:{:?} ready_views:{:?} stream_map views:{:?}, ", + self.future_transaction_views.get(&event.0), + self.ready_transaction_views.get(&event.0), self.stream_map.keys().collect::>(), ); let (tx_hash, status) = event; match status { - TransactionStatus::Ready | TransactionStatus::Future => { - self.transaction_states.entry(tx_hash).or_default().insert(block_hash); + TransactionStatus::Future => { + self.future_transaction_views.entry(tx_hash).or_default().insert(block_hash); + }, + TransactionStatus::Ready | TransactionStatus::InBlock(..) => { + // note: if future transaction was once seens as the ready we may want to treat it + // as ready transactions. Unreferenced future transactions are more likely to be + // removed when the last referencing view is removed then ready transactions. + // Transcaction seen as ready is likely quite close to be included in some + // future fork. + if let Some(mut views) = self.future_transaction_views.remove(&tx_hash) { + views.insert(block_hash); + self.ready_transaction_views.insert(tx_hash, views); + } else { + self.ready_transaction_views.entry(tx_hash).or_default().insert(block_hash); + } }, - TransactionStatus::Dropped | TransactionStatus::Usurped(_) => { - if let Entry::Occupied(mut views_keeping_tx_valid) = - self.transaction_states.entry(tx_hash) - { + TransactionStatus::Dropped => { + if let Some(mut views_keeping_tx_valid) = self.transaction_views(tx_hash) { views_keeping_tx_valid.get_mut().remove(&block_hash); - if views_keeping_tx_valid.get().is_empty() || - views_keeping_tx_valid - .get() - .iter() - .all(|h| !self.stream_map.contains_key(h)) - { - return self - .initial_views - .get(&tx_hash) - .map(|list| !list.contains(&block_hash)) - .unwrap_or(true) - .then(|| { - debug!("[{:?}] dropped_watcher: removing tx", tx_hash); - tx_hash - }) + if views_keeping_tx_valid.get().is_empty() { + return Some(DroppedTransaction::new_enforced_by_limts(tx_hash)) } } else { debug!("[{:?}] dropped_watcher: removing (non-tracked) tx", tx_hash); - return Some(tx_hash) + return Some(DroppedTransaction::new_enforced_by_limts(tx_hash)) } }, + TransactionStatus::Usurped(by) => + return Some(DroppedTransaction::new_usurped(tx_hash, by)), _ => {}, }; None } + /// Gets pending dropped transactions if any. + fn get_pending_dropped_transaction(&mut self) -> Option>> { + while let Some(tx_hash) = self.pending_dropped_transactions.pop() { + // never drop transaction that was seen as ready. It may not have a referencing + // view now, but such fork can appear. + if self.ready_transaction_views.get(&tx_hash).is_some() { + continue + } + + if let Some(views) = self.future_transaction_views.get(&tx_hash) { + if views.is_empty() { + self.future_transaction_views.remove(&tx_hash); + return Some(DroppedTransaction::new_enforced_by_limts(tx_hash)) + } + } + } + None + } + /// Creates a new `StreamOfDropped` and its associated event stream controller. /// /// This method initializes the internal structures and unfolds the stream of dropped @@ -200,47 +321,29 @@ where let ctx = Self { stream_map: StreamMap::new(), command_receiver, - transaction_states: Default::default(), - initial_views: Default::default(), + ready_transaction_views: Default::default(), + future_transaction_views: Default::default(), + pending_dropped_transactions: Default::default(), }; let stream_map = futures::stream::unfold(ctx, |mut ctx| async move { loop { + if let Some(dropped) = ctx.get_pending_dropped_transaction() { + debug!("dropped_watcher: sending out (pending): {dropped:?}"); + return Some((dropped, ctx)); + } tokio::select! { biased; - cmd = ctx.command_receiver.next() => { - match cmd? { - Command::AddView(key,stream) => { - trace!(target: LOG_TARGET,"dropped_watcher: Command::AddView {key:?} views:{:?}",ctx.stream_map.keys().collect::>()); - ctx.stream_map.insert(key,stream); - }, - Command::RemoveView(key) => { - trace!(target: LOG_TARGET,"dropped_watcher: Command::RemoveView {key:?} views:{:?}",ctx.stream_map.keys().collect::>()); - ctx.stream_map.remove(&key); - }, - Command::AddInitialViews(xts,block_hash) => { - log_xt_trace!(target: LOG_TARGET, xts.clone(), "[{:?}] dropped_watcher: xt initial view added {block_hash:?}"); - xts.into_iter().for_each(|xt| { - ctx.initial_views.entry(xt).or_default().insert(block_hash); - }); - }, - Command::RemoveFinalizedTxs(xts) => { - log_xt_trace!(target: LOG_TARGET, xts.clone(), "[{:?}] dropped_watcher: finalized xt removed"); - xts.iter().for_each(|xt| { - ctx.initial_views.remove(xt); - ctx.transaction_states.remove(xt); - }); - - }, - } - }, - Some(event) = next_event(&mut ctx.stream_map) => { if let Some(dropped) = ctx.handle_event(event.0, event.1) { debug!("dropped_watcher: sending out: {dropped:?}"); return Some((dropped, ctx)); } + }, + cmd = ctx.command_receiver.next() => { + ctx.handle_command(cmd?); } + } } }) @@ -254,30 +357,30 @@ where /// /// This struct provides methods to add and remove streams associated with views to and from the /// stream. -pub struct MultiViewDroppedWatcherController { +pub struct MultiViewDroppedWatcherController { /// A controller allowing to update the state of the associated [`StreamOfDropped`]. - controller: Controller>, + controller: Controller>, } -impl Clone for MultiViewDroppedWatcherController { +impl Clone for MultiViewDroppedWatcherController { fn clone(&self) -> Self { Self { controller: self.controller.clone() } } } -impl MultiViewDroppedWatcherController +impl MultiViewDroppedWatcherController where - C: ChainApi + 'static, - <::Block as BlockT>::Hash: Unpin, + ChainApi: graph::ChainApi + 'static, + <::Block as BlockT>::Hash: Unpin, { /// Creates new [`StreamOfDropped`] and its controller. - pub fn new() -> (MultiViewDroppedWatcherController, StreamOfDropped) { - let (stream_map, ctrl) = MultiViewDropWatcherContext::::event_stream(); + pub fn new() -> (MultiViewDroppedWatcherController, StreamOfDropped) { + let (stream_map, ctrl) = MultiViewDropWatcherContext::::event_stream(); (Self { controller: ctrl }, stream_map.boxed()) } /// Notifies the [`StreamOfDropped`] that new view was created. - pub fn add_view(&self, key: BlockHash, view: ViewStream) { + pub fn add_view(&self, key: BlockHash, view: ViewStream) { let _ = self.controller.unbounded_send(Command::AddView(key, view)).map_err(|e| { trace!(target: LOG_TARGET, "dropped_watcher: add_view {key:?} send message failed: {e}"); }); @@ -285,40 +388,22 @@ where /// Notifies the [`StreamOfDropped`] that the view was destroyed and shall be removed the /// stream map. - pub fn remove_view(&self, key: BlockHash) { + pub fn remove_view(&self, key: BlockHash) { let _ = self.controller.unbounded_send(Command::RemoveView(key)).map_err(|e| { trace!(target: LOG_TARGET, "dropped_watcher: remove_view {key:?} send message failed: {e}"); }); } - /// Adds the initial view for the given transactions hashes. - /// - /// This message should be called when the external submission of a transaction occures. It - /// provides the list of initial views for given extrinsics hashes. - /// - /// The dropped notification is not sent if it comes from the initial views. It allows to keep - /// transaction in the mempool, even if all the views are full at the time of submitting - /// transaction to the pool. - pub fn add_initial_views( + /// Removes status info for finalized transactions. + pub fn remove_finalized_txs( &self, - xts: impl IntoIterator> + Clone, - block_hash: BlockHash, + xts: impl IntoIterator> + Clone, ) { - let _ = self - .controller - .unbounded_send(Command::AddInitialViews(xts.into_iter().collect(), block_hash)) - .map_err(|e| { - trace!(target: LOG_TARGET, "dropped_watcher: add_initial_views_ send message failed: {e}"); - }); - } - - /// Removes all initial views for finalized transactions. - pub fn remove_finalized_txs(&self, xts: impl IntoIterator> + Clone) { let _ = self .controller .unbounded_send(Command::RemoveFinalizedTxs(xts.into_iter().collect())) .map_err(|e| { - trace!(target: LOG_TARGET, "dropped_watcher: remove_initial_views send message failed: {e}"); + trace!(target: LOG_TARGET, "dropped_watcher: remove_finalized_txs send message failed: {e}"); }); } } @@ -348,7 +433,7 @@ mod dropped_watcher_tests { watcher.add_view(block_hash, view_stream); let handle = tokio::spawn(async move { output_stream.take(1).collect::>().await }); - assert_eq!(handle.await.unwrap(), vec![tx_hash]); + assert_eq!(handle.await.unwrap(), vec![DroppedTransaction::new_enforced_by_limts(tx_hash)]); } #[tokio::test] @@ -398,7 +483,10 @@ mod dropped_watcher_tests { watcher.add_view(block_hash0, view_stream0); watcher.add_view(block_hash1, view_stream1); let handle = tokio::spawn(async move { output_stream.take(1).collect::>().await }); - assert_eq!(handle.await.unwrap(), vec![tx_hash1]); + assert_eq!( + handle.await.unwrap(), + vec![DroppedTransaction::new_enforced_by_limts(tx_hash1)] + ); } #[tokio::test] @@ -423,10 +511,11 @@ mod dropped_watcher_tests { watcher.add_view(block_hash0, view_stream0); assert!(output_stream.next().now_or_never().is_none()); + watcher.remove_view(block_hash0); watcher.add_view(block_hash1, view_stream1); let handle = tokio::spawn(async move { output_stream.take(1).collect::>().await }); - assert_eq!(handle.await.unwrap(), vec![tx_hash]); + assert_eq!(handle.await.unwrap(), vec![DroppedTransaction::new_enforced_by_limts(tx_hash)]); } #[tokio::test] @@ -469,65 +558,6 @@ mod dropped_watcher_tests { let block_hash2 = H256::repeat_byte(0x03); watcher.add_view(block_hash2, view_stream2); let handle = tokio::spawn(async move { output_stream.take(1).collect::>().await }); - assert_eq!(handle.await.unwrap(), vec![tx_hash]); - } - - #[tokio::test] - async fn test06() { - sp_tracing::try_init_simple(); - let (watcher, mut output_stream) = MultiViewDroppedWatcher::new(); - assert!(output_stream.next().now_or_never().is_none()); - - let block_hash0 = H256::repeat_byte(0x01); - let block_hash1 = H256::repeat_byte(0x02); - let tx_hash = H256::repeat_byte(0x0b); - - let view_stream0 = futures::stream::iter(vec![ - (tx_hash, TransactionStatus::Future), - (tx_hash, TransactionStatus::InBlock((block_hash1, 0))), - ]) - .boxed(); - watcher.add_view(block_hash0, view_stream0); - assert!(output_stream.next().now_or_never().is_none()); - - let view_stream1 = futures::stream::iter(vec![ - (tx_hash, TransactionStatus::Ready), - (tx_hash, TransactionStatus::Dropped), - ]) - .boxed(); - - watcher.add_view(block_hash1, view_stream1); - watcher.add_initial_views(vec![tx_hash], block_hash1); - assert!(output_stream.next().now_or_never().is_none()); - } - - #[tokio::test] - async fn test07() { - sp_tracing::try_init_simple(); - let (watcher, mut output_stream) = MultiViewDroppedWatcher::new(); - assert!(output_stream.next().now_or_never().is_none()); - - let block_hash0 = H256::repeat_byte(0x01); - let block_hash1 = H256::repeat_byte(0x02); - let tx_hash = H256::repeat_byte(0x0b); - - let view_stream0 = futures::stream::iter(vec![ - (tx_hash, TransactionStatus::Future), - (tx_hash, TransactionStatus::InBlock((block_hash1, 0))), - ]) - .boxed(); - watcher.add_view(block_hash0, view_stream0); - watcher.add_initial_views(vec![tx_hash], block_hash0); - assert!(output_stream.next().now_or_never().is_none()); - - let view_stream1 = futures::stream::iter(vec![ - (tx_hash, TransactionStatus::Ready), - (tx_hash, TransactionStatus::Dropped), - ]) - .boxed(); - watcher.add_view(block_hash1, view_stream1); - - let handle = tokio::spawn(async move { output_stream.take(1).collect::>().await }); - assert_eq!(handle.await.unwrap(), vec![tx_hash]); + assert_eq!(handle.await.unwrap(), vec![DroppedTransaction::new_enforced_by_limts(tx_hash)]); } } diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs index 7e72b44adf38..4ec87f1fefa4 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs @@ -23,7 +23,7 @@ use super::{ import_notification_sink::MultiViewImportNotificationSink, metrics::MetricsLink as PrometheusMetrics, multi_view_listener::MultiViewListener, - tx_mem_pool::{TxInMemPool, TxMemPool, TXMEMPOOL_TRANSACTION_LIMIT_MULTIPLIER}, + tx_mem_pool::{InsertionInfo, TxInMemPool, TxMemPool, TXMEMPOOL_TRANSACTION_LIMIT_MULTIPLIER}, view::View, view_store::ViewStore, }; @@ -31,9 +31,13 @@ use crate::{ api::FullChainApi, common::log_xt::log_xt_trace, enactment_state::{EnactmentAction, EnactmentState}, - fork_aware_txpool::revalidation_worker, - graph::{self, base_pool::Transaction, ExtrinsicFor, ExtrinsicHash, IsValidator, Options}, - PolledIterator, ReadyIteratorFor, LOG_TARGET, + fork_aware_txpool::{dropped_watcher::DroppedReason, revalidation_worker}, + graph::{ + self, + base_pool::{TimedTransactionSource, Transaction}, + ExtrinsicFor, ExtrinsicHash, IsValidator, Options, + }, + ReadyIteratorFor, LOG_TARGET, }; use async_trait::async_trait; use futures::{ @@ -45,9 +49,8 @@ use futures::{ use parking_lot::Mutex; use prometheus_endpoint::Registry as PrometheusRegistry; use sc_transaction_pool_api::{ - error::{Error, IntoPoolError}, - ChainEvent, ImportNotificationStream, MaintainedTransactionPool, PoolFuture, PoolStatus, - TransactionFor, TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, + ChainEvent, ImportNotificationStream, MaintainedTransactionPool, PoolStatus, TransactionFor, + TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, }; use sp_blockchain::{HashAndNumber, TreeRoute}; use sp_core::traits::SpawnEssentialNamed; @@ -193,13 +196,19 @@ where listener.clone(), Default::default(), mempool_max_transactions_count, + ready_limits.total_bytes + future_limits.total_bytes, )); let (dropped_stream_controller, dropped_stream) = MultiViewDroppedWatcherController::::new(); + + let view_store = + Arc::new(ViewStore::new(pool_api.clone(), listener, dropped_stream_controller)); + let dropped_monitor_task = Self::dropped_monitor_task( dropped_stream, mempool.clone(), + view_store.clone(), import_notification_sink.clone(), ); @@ -216,8 +225,8 @@ where ( Self { mempool, - api: pool_api.clone(), - view_store: Arc::new(ViewStore::new(pool_api, listener, dropped_stream_controller)), + api: pool_api, + view_store, ready_poll: Arc::from(Mutex::from(ReadyPoll::new())), enactment_state: Arc::new(Mutex::new(EnactmentState::new( best_block_hash, @@ -233,14 +242,17 @@ where ) } - /// Monitors the stream of dropped transactions and removes them from the mempool. + /// Monitors the stream of dropped transactions and removes them from the mempool and + /// view_store. /// /// This asynchronous task continuously listens for dropped transaction notifications provided /// within `dropped_stream` and ensures that these transactions are removed from the `mempool` - /// and `import_notification_sink` instances. + /// and `import_notification_sink` instances. For Usurped events, the transaction is also + /// removed from the view_store. async fn dropped_monitor_task( mut dropped_stream: StreamOfDropped, mempool: Arc>, + view_store: Arc>, import_notification_sink: MultiViewImportNotificationSink< Block::Hash, ExtrinsicHash, @@ -251,9 +263,33 @@ where log::debug!(target: LOG_TARGET, "fatp::dropped_monitor_task: terminated..."); break; }; - log::trace!(target: LOG_TARGET, "[{:?}] fatp::dropped notification, removing", dropped); - mempool.remove_dropped_transactions(&[dropped]).await; - import_notification_sink.clean_notified_items(&[dropped]); + let dropped_tx_hash = dropped.tx_hash; + log::trace!(target: LOG_TARGET, "[{:?}] fatp::dropped notification {:?}, removing", dropped_tx_hash,dropped.reason); + match dropped.reason { + DroppedReason::Usurped(new_tx_hash) => { + if let Some(new_tx) = mempool.get_by_hash(new_tx_hash) { + view_store + .replace_transaction( + new_tx.source(), + new_tx.tx(), + dropped_tx_hash, + new_tx.is_watched(), + ) + .await; + } else { + log::trace!( + target:LOG_TARGET, + "error: dropped_monitor_task: no entry in mempool for new transaction {:?}", + new_tx_hash, + ); + } + }, + DroppedReason::LimitsEnforced => {}, + }; + + mempool.remove_dropped_transaction(&dropped_tx_hash).await; + view_store.listener.transaction_dropped(dropped); + import_notification_sink.clean_notified_items(&[dropped_tx_hash]); } } @@ -283,13 +319,18 @@ where listener.clone(), metrics.clone(), TXMEMPOOL_TRANSACTION_LIMIT_MULTIPLIER * (options.ready.count + options.future.count), + options.ready.total_bytes + options.future.total_bytes, )); let (dropped_stream_controller, dropped_stream) = MultiViewDroppedWatcherController::::new(); + + let view_store = + Arc::new(ViewStore::new(pool_api.clone(), listener, dropped_stream_controller)); let dropped_monitor_task = Self::dropped_monitor_task( dropped_stream, mempool.clone(), + view_store.clone(), import_notification_sink.clone(), ); @@ -305,8 +346,8 @@ where Self { mempool, - api: pool_api.clone(), - view_store: Arc::new(ViewStore::new(pool_api, listener, dropped_stream_controller)), + api: pool_api, + view_store, ready_poll: Arc::from(Mutex::from(ReadyPoll::new())), enactment_state: Arc::new(Mutex::new(EnactmentState::new( best_block_hash, @@ -365,6 +406,16 @@ where self.mempool.unwatched_and_watched_count() } + /// Returns a set of future transactions for given block hash. + /// + /// Intended for logging / tests. + pub fn futures_at( + &self, + at: Block::Hash, + ) -> Option, ExtrinsicFor>>> { + self.view_store.futures_at(at) + } + /// Returns a best-effort set of ready transactions for a given block, without executing full /// maintain process. /// @@ -374,14 +425,13 @@ where /// /// Pruning is just rebuilding the underlying transactions graph, no validations are executed, /// so this process shall be fast. - pub fn ready_at_light(&self, at: Block::Hash) -> PolledIterator { + pub async fn ready_at_light(&self, at: Block::Hash) -> ReadyIteratorFor { let start = Instant::now(); let api = self.api.clone(); log::trace!(target: LOG_TARGET, "fatp::ready_at_light {:?}", at); let Ok(block_number) = self.api.resolve_block_number(at) else { - let empty: ReadyIteratorFor = Box::new(std::iter::empty()); - return Box::pin(async { empty }) + return Box::new(std::iter::empty()) }; let best_result = { @@ -400,57 +450,53 @@ where ) }; - Box::pin(async move { - if let Ok((Some(best_tree_route), Some(best_view))) = best_result { - let tmp_view: View = View::new_from_other( - &best_view, - &HashAndNumber { hash: at, number: block_number }, - ); + if let Ok((Some(best_tree_route), Some(best_view))) = best_result { + let tmp_view: View = + View::new_from_other(&best_view, &HashAndNumber { hash: at, number: block_number }); - let mut all_extrinsics = vec![]; - - for h in best_tree_route.enacted() { - let extrinsics = api - .block_body(h.hash) - .await - .unwrap_or_else(|e| { - log::warn!(target: LOG_TARGET, "Compute ready light transactions: error request: {}", e); - None - }) - .unwrap_or_default() - .into_iter() - .map(|t| api.hash_and_length(&t).0); - all_extrinsics.extend(extrinsics); - } + let mut all_extrinsics = vec![]; - let before_count = tmp_view.pool.validated_pool().status().ready; - let tags = tmp_view - .pool - .validated_pool() - .extrinsics_tags(&all_extrinsics) + for h in best_tree_route.enacted() { + let extrinsics = api + .block_body(h.hash) + .await + .unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Compute ready light transactions: error request: {}", e); + None + }) + .unwrap_or_default() .into_iter() - .flatten() - .flatten() - .collect::>(); - let _ = tmp_view.pool.validated_pool().prune_tags(tags); - - let after_count = tmp_view.pool.validated_pool().status().ready; - log::debug!(target: LOG_TARGET, - "fatp::ready_at_light {} from {} before: {} to be removed: {} after: {} took:{:?}", - at, - best_view.at.hash, - before_count, - all_extrinsics.len(), - after_count, - start.elapsed() - ); - Box::new(tmp_view.pool.validated_pool().ready()) - } else { - let empty: ReadyIteratorFor = Box::new(std::iter::empty()); - log::debug!(target: LOG_TARGET, "fatp::ready_at_light {} -> empty, took:{:?}", at, start.elapsed()); - empty + .map(|t| api.hash_and_length(&t).0); + all_extrinsics.extend(extrinsics); } - }) + + let before_count = tmp_view.pool.validated_pool().status().ready; + let tags = tmp_view + .pool + .validated_pool() + .extrinsics_tags(&all_extrinsics) + .into_iter() + .flatten() + .flatten() + .collect::>(); + let _ = tmp_view.pool.validated_pool().prune_tags(tags); + + let after_count = tmp_view.pool.validated_pool().status().ready; + log::debug!(target: LOG_TARGET, + "fatp::ready_at_light {} from {} before: {} to be removed: {} after: {} took:{:?}", + at, + best_view.at.hash, + before_count, + all_extrinsics.len(), + after_count, + start.elapsed() + ); + Box::new(tmp_view.pool.validated_pool().ready()) + } else { + let empty: ReadyIteratorFor = Box::new(std::iter::empty()); + log::debug!(target: LOG_TARGET, "fatp::ready_at_light {} -> empty, took:{:?}", at, start.elapsed()); + empty + } } /// Waits for the set of ready transactions for a given block up to a specified timeout. @@ -463,18 +509,18 @@ where /// maintain. /// /// Returns a future resolving to a ready iterator of transactions. - fn ready_at_with_timeout_internal( + async fn ready_at_with_timeout_internal( &self, at: Block::Hash, timeout: std::time::Duration, - ) -> PolledIterator { + ) -> ReadyIteratorFor { log::debug!(target: LOG_TARGET, "fatp::ready_at_with_timeout at {:?} allowed delay: {:?}", at, timeout); let timeout = futures_timer::Delay::new(timeout); let (view_already_exists, ready_at) = self.ready_at_internal(at); if view_already_exists { - return ready_at; + return ready_at.await; } let maybe_ready = async move { @@ -492,18 +538,19 @@ where }; let fall_back_ready = self.ready_at_light(at); - Box::pin(async { - let (maybe_ready, fall_back_ready) = - futures::future::join(maybe_ready.boxed(), fall_back_ready.boxed()).await; - maybe_ready.unwrap_or(fall_back_ready) - }) + let (maybe_ready, fall_back_ready) = + futures::future::join(maybe_ready, fall_back_ready).await; + maybe_ready.unwrap_or(fall_back_ready) } - fn ready_at_internal(&self, at: Block::Hash) -> (bool, PolledIterator) { + fn ready_at_internal( + &self, + at: Block::Hash, + ) -> (bool, Pin> + Send>>) { let mut ready_poll = self.ready_poll.lock(); if let Some((view, inactive)) = self.view_store.get_view_at(at, true) { - log::debug!(target: LOG_TARGET, "fatp::ready_at {at:?} (inactive:{inactive:?})"); + log::debug!(target: LOG_TARGET, "fatp::ready_at_internal {at:?} (inactive:{inactive:?})"); let iterator: ReadyIteratorFor = Box::new(view.pool.validated_pool().ready()); return (true, async move { iterator }.boxed()); } @@ -518,7 +565,7 @@ where }) .boxed(); log::debug!(target: LOG_TARGET, - "fatp::ready_at {at:?} pending keys: {:?}", + "fatp::ready_at_internal {at:?} pending keys: {:?}", ready_poll.pollers.keys() ); (false, pending) @@ -572,6 +619,7 @@ fn reduce_multiview_result(input: HashMap>>) -> Vec TransactionPool for ForkAwareTxPool where Block: BlockT, @@ -589,131 +637,93 @@ where /// /// The internal limits of the pool are checked. The results of submissions to individual views /// are reduced to single result. Refer to `reduce_multiview_result` for more details. - fn submit_at( + async fn submit_at( &self, _: ::Hash, source: TransactionSource, xts: Vec>, - ) -> PoolFuture, Self::Error>>, Self::Error> { + ) -> Result, Self::Error>>, Self::Error> { let view_store = self.view_store.clone(); log::debug!(target: LOG_TARGET, "fatp::submit_at count:{} views:{}", xts.len(), self.active_views_count()); log_xt_trace!(target: LOG_TARGET, xts.iter().map(|xt| self.tx_hash(xt)), "[{:?}] fatp::submit_at"); let xts = xts.into_iter().map(Arc::from).collect::>(); - let mempool_result = self.mempool.extend_unwatched(source, &xts); + let mempool_results = self.mempool.extend_unwatched(source, &xts); if view_store.is_empty() { - return future::ready(Ok(mempool_result)).boxed() + return Ok(mempool_results.into_iter().map(|r| r.map(|r| r.hash)).collect::>()) } - let (hashes, to_be_submitted): (Vec>, Vec>) = - mempool_result - .iter() - .zip(xts) - .filter_map(|(result, xt)| result.as_ref().ok().map(|xt_hash| (xt_hash, xt))) - .unzip(); + let to_be_submitted = mempool_results + .iter() + .zip(xts) + .filter_map(|(result, xt)| { + result.as_ref().ok().map(|insertion| (insertion.source.clone(), xt)) + }) + .collect::>(); self.metrics .report(|metrics| metrics.submitted_transactions.inc_by(to_be_submitted.len() as _)); let mempool = self.mempool.clone(); - async move { - let results_map = view_store.submit(source, to_be_submitted.into_iter(), hashes).await; - let mut submission_results = reduce_multiview_result(results_map).into_iter(); + let results_map = view_store.submit(to_be_submitted.into_iter()).await; + let mut submission_results = reduce_multiview_result(results_map).into_iter(); - Ok(mempool_result + Ok(mempool_results .into_iter() .map(|result| { - result.and_then(|xt_hash| { - let result = submission_results + result.and_then(|insertion| { + submission_results .next() - .expect("The number of Ok results in mempool is exactly the same as the size of to-views-submission result. qed."); - result.or_else(|error| { - let error = error.into_pool_error(); - match error { - Ok( - // The transaction is still in mempool it may get included into the view for the next block. - Error::ImmediatelyDropped - ) => Ok(xt_hash), - Ok(e) => { - mempool.remove(xt_hash); - Err(e.into()) - }, - Err(e) => Err(e), - } - }) + .expect("The number of Ok results in mempool is exactly the same as the size of to-views-submission result. qed.") + .inspect_err(|_| + mempool.remove(insertion.hash) + ) }) }) .collect::>()) - } - .boxed() } /// Submits a single transaction and returns a future resolving to the submission results. /// /// Actual transaction submission process is delegated to the `submit_at` function. - fn submit_one( + async fn submit_one( &self, _at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture, Self::Error> { + ) -> Result, Self::Error> { log::trace!(target: LOG_TARGET, "[{:?}] fatp::submit_one views:{}", self.tx_hash(&xt), self.active_views_count()); - let result_future = self.submit_at(_at, source, vec![xt]); - async move { - let result = result_future.await; - match result { - Ok(mut v) => - v.pop().expect("There is exactly one element in result of submit_at. qed."), - Err(e) => Err(e), - } + match self.submit_at(_at, source, vec![xt]).await { + Ok(mut v) => + v.pop().expect("There is exactly one element in result of submit_at. qed."), + Err(e) => Err(e), } - .boxed() } /// Submits a transaction and starts to watch its progress in the pool, returning a stream of /// status updates. /// /// Actual transaction submission process is delegated to the `ViewStore` internal instance. - fn submit_and_watch( + async fn submit_and_watch( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture>>, Self::Error> { + ) -> Result>>, Self::Error> { log::trace!(target: LOG_TARGET, "[{:?}] fatp::submit_and_watch views:{}", self.tx_hash(&xt), self.active_views_count()); let xt = Arc::from(xt); - let xt_hash = match self.mempool.push_watched(source, xt.clone()) { - Ok(xt_hash) => xt_hash, - Err(e) => return future::ready(Err(e)).boxed(), - }; + let InsertionInfo { hash: xt_hash, source: timed_source } = + match self.mempool.push_watched(source, xt.clone()) { + Ok(result) => result, + Err(e) => return Err(e), + }; self.metrics.report(|metrics| metrics.submitted_transactions.inc()); - let view_store = self.view_store.clone(); - let mempool = self.mempool.clone(); - async move { - let result = view_store.submit_and_watch(at, source, xt).await; - let result = result.or_else(|(e, maybe_watcher)| { - let error = e.into_pool_error(); - match (error, maybe_watcher) { - ( - Ok( - // The transaction is still in mempool it may get included into the - // view for the next block. - Error::ImmediatelyDropped, - ), - Some(watcher), - ) => Ok(watcher), - (Ok(e), _) => { - mempool.remove(xt_hash); - Err(e.into()) - }, - (Err(e), _) => Err(e), - } - }); - result - } - .boxed() + self.view_store + .submit_and_watch(at, timed_source, xt) + .await + .inspect_err(|_| self.mempool.remove(xt_hash)) } /// Intended to remove transactions identified by the given hashes, and any dependent @@ -784,9 +794,9 @@ where } /// Returns an iterator for ready transactions at a specific block, ordered by priority. - fn ready_at(&self, at: ::Hash) -> PolledIterator { + async fn ready_at(&self, at: ::Hash) -> ReadyIteratorFor { let (_, result) = self.ready_at_internal(at); - result + result.await } /// Returns an iterator for ready transactions, ordered by priority. @@ -809,12 +819,12 @@ where /// /// If the timeout expires before the maintain process is accomplished, a best-effort /// set of transactions is returned (refer to `ready_at_light`). - fn ready_at_with_timeout( + async fn ready_at_with_timeout( &self, at: ::Hash, timeout: std::time::Duration, - ) -> PolledIterator { - self.ready_at_with_timeout_internal(at, timeout) + ) -> ReadyIteratorFor { + self.ready_at_with_timeout_internal(at, timeout).await } } @@ -842,12 +852,12 @@ where ) -> Result { log::debug!(target: LOG_TARGET, "fatp::submit_local views:{}", self.active_views_count()); let xt = Arc::from(xt); - let result = self + let InsertionInfo { hash: xt_hash, .. } = self .mempool .extend_unwatched(TransactionSource::Local, &[xt.clone()]) .remove(0)?; - self.view_store.submit_local(xt).or_else(|_| Ok(result)) + self.view_store.submit_local(xt).or_else(|_| Ok(xt_hash)) } } @@ -955,6 +965,9 @@ where let start = Instant::now(); let watched_xts = self.register_listeners(&mut view).await; let duration = start.elapsed(); + // sync the transactions statuses and referencing views in all the listeners with newly + // cloned view. + view.pool.validated_pool().retrigger_notifications(); log::debug!(target: LOG_TARGET, "register_listeners: at {at:?} took {duration:?}"); // 2. Handle transactions from the tree route. Pruning transactions from the view first @@ -1056,7 +1069,7 @@ where future::join_all(results).await } - /// Updates the given view with the transaction from the internal mempol. + /// Updates the given view with the transactions from the internal mempol. /// /// All transactions from the mempool (excluding those which are either already imported or /// already included in blocks since recently finalized block) are submitted to the @@ -1082,69 +1095,43 @@ where self.active_views_count() ); let included_xts = self.extrinsics_included_since_finalized(view.at.hash).await; - let xts = self.mempool.clone_unwatched(); - - let mut all_submitted_count = 0; - if !xts.is_empty() { - let unwatched_count = xts.len(); - let mut buckets = HashMap::>>::default(); - xts.into_iter() - .filter(|(hash, _)| !view.pool.validated_pool().pool.read().is_imported(hash)) - .filter(|(hash, _)| !included_xts.contains(&hash)) - .map(|(_, tx)| (tx.source(), tx.tx())) - .for_each(|(source, tx)| buckets.entry(source).or_default().push(tx)); - - for (source, xts) in buckets { - all_submitted_count += xts.len(); - let _ = view.submit_many(source, xts).await; - } - log::debug!(target: LOG_TARGET, "update_view_with_mempool: at {:?} unwatched {}/{}", view.at.hash, all_submitted_count, unwatched_count); - } - - let watched_submitted_count = watched_xts.len(); - let mut buckets = HashMap::< - TransactionSource, - Vec<(ExtrinsicHash, ExtrinsicFor)>, - >::default(); - watched_xts + let (hashes, xts_filtered): (Vec<_>, Vec<_>) = watched_xts .into_iter() + .chain(self.mempool.clone_unwatched().into_iter()) + .filter(|(hash, _)| !view.is_imported(hash)) .filter(|(hash, _)| !included_xts.contains(&hash)) - .map(|(tx_hash, tx)| (tx.source(), tx_hash, tx.tx())) - .for_each(|(source, tx_hash, tx)| { - buckets.entry(source).or_default().push((tx_hash, tx)) - }); + .map(|(tx_hash, tx)| (tx_hash, (tx.source(), tx.tx()))) + .unzip(); - let mut watched_results = Vec::default(); - for (source, watched_xts) in buckets { - let hashes = watched_xts.iter().map(|i| i.0).collect::>(); - let results = view - .submit_many(source, watched_xts.into_iter().map(|i| i.1)) - .await - .into_iter() - .zip(hashes) - .map(|(result, tx_hash)| result.or_else(|_| Err(tx_hash))) - .collect::>(); - watched_results.extend(results); - } + let watched_results = view + .submit_many(xts_filtered) + .await + .into_iter() + .zip(hashes) + .map(|(result, tx_hash)| result.or_else(|_| Err(tx_hash))) + .collect::>(); - log::debug!(target: LOG_TARGET, "update_view_with_mempool: at {:?} watched {}/{}", view.at.hash, watched_submitted_count, self.mempool_len().1); + let submitted_count = watched_results.len(); - all_submitted_count += watched_submitted_count; - let _ = all_submitted_count - .try_into() - .map(|v| self.metrics.report(|metrics| metrics.submitted_from_mempool_txs.inc_by(v))); + log::debug!( + target: LOG_TARGET, + "update_view_with_mempool: at {:?} submitted {}/{}", + view.at.hash, + submitted_count, + self.mempool.len() + ); + + self.metrics + .report(|metrics| metrics.submitted_from_mempool_txs.inc_by(submitted_count as _)); // if there are no views yet, and a single newly created view is reporting error, just send // out the invalid event, and remove transaction. if self.view_store.is_empty() { for result in watched_results { - match result { - Err(tx_hash) => { - self.view_store.listener.invalidate_transactions(&[tx_hash]); - self.mempool.remove(tx_hash); - }, - Ok(_) => {}, + if let Err(tx_hash) = result { + self.view_store.listener.invalidate_transactions(&[tx_hash]); + self.mempool.remove(tx_hash); } } } @@ -1220,7 +1207,14 @@ where }) .map(|(tx_hash, tx)| { //find arc if tx is known - self.mempool.get_by_hash(tx_hash).unwrap_or_else(|| Arc::from(tx)) + self.mempool + .get_by_hash(tx_hash) + .map(|tx| (tx.source(), tx.tx())) + .unwrap_or_else(|| { + // These transactions are coming from retracted blocks, we + // should simply consider them external. + (TimedTransactionSource::new_external(true), Arc::from(tx)) + }) }), ); @@ -1229,16 +1223,7 @@ where }); } - let _ = view - .pool - .resubmit_at( - &hash_and_number, - // These transactions are coming from retracted blocks, we should - // simply consider them external. - TransactionSource::External, - resubmit_transactions, - ) - .await; + let _ = view.pool.resubmit_at(&hash_and_number, resubmit_transactions).await; } } diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/import_notification_sink.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/import_notification_sink.rs index 7fbdcade63b8..f9a41673bb8f 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/import_notification_sink.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/import_notification_sink.rs @@ -326,6 +326,7 @@ mod tests { let j0 = tokio::spawn(runnable); let stream = ctrl.event_stream(); + let stream2 = ctrl.event_stream(); let mut v1 = View::new(vec![(10, 1), (10, 2), (10, 3)]); let mut v2 = View::new(vec![(20, 1), (20, 2), (20, 6)]); @@ -342,20 +343,16 @@ mod tests { ctrl.add_view(1000, o1); ctrl.add_view(2000, o2); - let j4 = { - let ctrl = ctrl.clone(); - tokio::spawn(async move { - tokio::time::sleep(Duration::from_millis(70)).await; - ctrl.clean_notified_items(&vec![1, 3]); - ctrl.add_view(3000, o3.boxed()); - }) - }; + let out = stream.take(4).collect::>().await; + assert_eq!(out, vec![1, 2, 3, 6]); - let out = stream.take(6).collect::>().await; + ctrl.clean_notified_items(&vec![1, 3]); + ctrl.add_view(3000, o3.boxed()); + let out = stream2.take(6).collect::>().await; assert_eq!(out, vec![1, 2, 3, 6, 1, 3]); - drop(ctrl); - futures::future::join_all(vec![j0, j1, j2, j3, j4]).await; + drop(ctrl); + futures::future::join_all(vec![j0, j1, j2, j3]).await; } #[tokio::test] diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs index 9f979e216b6d..5f7294a24fd7 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs @@ -201,12 +201,12 @@ //! required to accomplish it. //! //! ### Providing ready transactions: `ready_at` -//! The [`ready_at`] function returns a [future][`crate::PolledIterator`] that resolves to the -//! [ready transactions iterator][`ReadyTransactions`]. The block builder shall wait either for the -//! future to be resolved or for timeout to be hit. To avoid building empty blocks in case of -//! timeout, the waiting for timeout functionality was moved into the transaction pool, and new API -//! function was added: [`ready_at_with_timeout`]. This function also provides a fall back ready -//! iterator which is result of [light maintain](#light-maintain). +//! The asynchronous [`ready_at`] function resolves to the [ready transactions +//! iterator][`ReadyTransactions`]. The block builder shall wait either for the future to be +//! resolved or for timeout to be hit. To avoid building empty blocks in case of timeout, the +//! waiting for timeout functionality was moved into the transaction pool, and new API function was +//! added: [`ready_at_with_timeout`]. This function also provides a fall back ready iterator which +//! is result of [light maintain](#light-maintain). //! //! New function internally waits either for [maintain](#maintain) process triggered for requested //! block to be accomplished or for the timeout. If timeout hits then the result of [light diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/multi_view_listener.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/multi_view_listener.rs index 8d0e69db2e9a..a00234a99808 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/multi_view_listener.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/multi_view_listener.rs @@ -36,6 +36,8 @@ use std::{ }; use tokio_stream::StreamMap; +use super::dropped_watcher::{DroppedReason, DroppedTransaction}; + /// A side channel allowing to control the external stream instance (one per transaction) with /// [`ControllerCommand`]. /// @@ -79,7 +81,7 @@ enum ControllerCommand { /// Notifies that a transaction was dropped from the pool. /// /// If all preconditions are met, an external dropped event will be sent out. - TransactionDropped, + TransactionDropped(DroppedReason>), } impl std::fmt::Debug for ControllerCommand @@ -99,8 +101,8 @@ where ControllerCommand::TransactionBroadcasted(_) => { write!(f, "ListenerAction::TransactionBroadcasted(...)") }, - ControllerCommand::TransactionDropped => { - write!(f, "ListenerAction::TransactionDropped") + ControllerCommand::TransactionDropped(r) => { + write!(f, "ListenerAction::TransactionDropped {r:?}") }, } } @@ -268,6 +270,7 @@ where /// stream map. fn remove_view(&mut self, block_hash: BlockHash) { self.status_stream_map.remove(&block_hash); + self.views_keeping_tx_valid.remove(&block_hash); trace!(target: LOG_TARGET, "[{:?}] RemoveView view: {:?} views:{:?}", self.tx_hash, block_hash, self.status_stream_map.keys().collect::>()); } } @@ -282,6 +285,11 @@ where Self { controllers: Default::default() } } + /// Returns `true` if the listener contains a stream controller for the specified hash. + pub fn contains_tx(&self, tx_hash: &ExtrinsicHash) -> bool { + self.controllers.read().contains_key(tx_hash) + } + /// Creates an external aggregated stream of events for given transaction. /// /// This method initializes an `ExternalWatcherContext` for the provided transaction hash, sets @@ -346,11 +354,16 @@ where log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Broadcasted", ctx.tx_hash); return Some((TransactionStatus::Broadcast(peers), ctx)) }, - ControllerCommand::TransactionDropped => { + ControllerCommand::TransactionDropped(DroppedReason::LimitsEnforced) => { log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Dropped", ctx.tx_hash); ctx.terminate = true; return Some((TransactionStatus::Dropped, ctx)) }, + ControllerCommand::TransactionDropped(DroppedReason::Usurped(by)) => { + log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Usurped({:?})", ctx.tx_hash, by); + ctx.terminate = true; + return Some((TransactionStatus::Usurped(by), ctx)) + }, } }, }; @@ -445,16 +458,15 @@ where /// /// This method sends a `TransactionDropped` command to the controller of each requested /// transaction prompting and external `Broadcasted` event. - pub(crate) fn transactions_dropped(&self, dropped: &[ExtrinsicHash]) { + pub(crate) fn transaction_dropped(&self, dropped: DroppedTransaction>) { let mut controllers = self.controllers.write(); - debug!(target: LOG_TARGET, "mvl::transactions_dropped: {:?}", dropped); - for tx_hash in dropped { - if let Some(tx) = controllers.remove(&tx_hash) { - debug!(target: LOG_TARGET, "[{:?}] transaction_dropped", tx_hash); - if let Err(e) = tx.unbounded_send(ControllerCommand::TransactionDropped) { - trace!(target: LOG_TARGET, "[{:?}] transactions_dropped: send message failed: {:?}", tx_hash, e); - }; - } + debug!(target: LOG_TARGET, "mvl::transaction_dropped: {:?}", dropped); + if let Some(tx) = controllers.remove(&dropped.tx_hash) { + let DroppedTransaction { tx_hash, reason } = dropped; + debug!(target: LOG_TARGET, "[{:?}] transaction_dropped", tx_hash); + if let Err(e) = tx.unbounded_send(ControllerCommand::TransactionDropped(reason)) { + trace!(target: LOG_TARGET, "[{:?}] transaction_dropped: send message failed: {:?}", tx_hash, e); + }; } } diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/revalidation_worker.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/revalidation_worker.rs index 9464ab3f5766..e1c65a08a70b 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/revalidation_worker.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/revalidation_worker.rs @@ -186,11 +186,11 @@ mod tests { use crate::{ common::tests::{uxt, TestApi}, fork_aware_txpool::view::FinishRevalidationLocalChannels, + TimedTransactionSource, }; use futures::executor::block_on; - use sc_transaction_pool_api::TransactionSource; use substrate_test_runtime::{AccountId, Transfer, H256}; - use substrate_test_runtime_client::AccountKeyring::Alice; + use substrate_test_runtime_client::Sr25519Keyring::Alice; #[test] fn revalidation_queue_works() { let api = Arc::new(TestApi::default()); @@ -212,9 +212,10 @@ mod tests { nonce: 0, }); - let _ = block_on( - view.submit_many(TransactionSource::External, std::iter::once(uxt.clone().into())), - ); + let _ = block_on(view.submit_many(std::iter::once(( + TimedTransactionSource::new_external(false), + uxt.clone().into(), + )))); assert_eq!(api.validation_requests().len(), 1); let (finish_revalidation_request_tx, finish_revalidation_request_rx) = diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/tx_mem_pool.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/tx_mem_pool.rs index 989c7e8ef356..989ae4425dc4 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/tx_mem_pool.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/tx_mem_pool.rs @@ -30,12 +30,11 @@ use super::{metrics::MetricsLink as PrometheusMetrics, multi_view_listener::Mult use crate::{ common::log_xt::log_xt_trace, graph, - graph::{ExtrinsicFor, ExtrinsicHash}, + graph::{base_pool::TimedTransactionSource, tracked_map::Size, ExtrinsicFor, ExtrinsicHash}, LOG_TARGET, }; use futures::FutureExt; use itertools::Itertools; -use parking_lot::RwLock; use sc_transaction_pool_api::TransactionSource; use sp_blockchain::HashAndNumber; use sp_runtime::{ @@ -43,7 +42,7 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, }; use std::{ - collections::{hash_map::Entry, HashMap}, + collections::HashMap, sync::{atomic, atomic::AtomicU64, Arc}, time::Instant, }; @@ -72,8 +71,10 @@ where watched: bool, /// Extrinsic actual body. tx: ExtrinsicFor, + /// Size of the extrinsics actual body. + bytes: usize, /// Transaction source. - source: TransactionSource, + source: TimedTransactionSource, /// When the transaction was revalidated, used to periodically revalidate the mem pool buffer. validated_at: AtomicU64, //todo: we need to add future / ready status at finalized block. @@ -94,18 +95,30 @@ where /// Shall the progress of transaction be watched. /// /// Was transaction sent with `submit_and_watch`. - fn is_watched(&self) -> bool { + pub(crate) fn is_watched(&self) -> bool { self.watched } /// Creates a new instance of wrapper for unwatched transaction. - fn new_unwatched(source: TransactionSource, tx: ExtrinsicFor) -> Self { - Self { watched: false, tx, source, validated_at: AtomicU64::new(0) } + fn new_unwatched(source: TransactionSource, tx: ExtrinsicFor, bytes: usize) -> Self { + Self { + watched: false, + tx, + source: TimedTransactionSource::from_transaction_source(source, true), + validated_at: AtomicU64::new(0), + bytes, + } } /// Creates a new instance of wrapper for watched transaction. - fn new_watched(source: TransactionSource, tx: ExtrinsicFor) -> Self { - Self { watched: true, tx, source, validated_at: AtomicU64::new(0) } + fn new_watched(source: TransactionSource, tx: ExtrinsicFor, bytes: usize) -> Self { + Self { + watched: true, + tx, + source: TimedTransactionSource::from_transaction_source(source, true), + validated_at: AtomicU64::new(0), + bytes, + } } /// Provides a clone of actual transaction body. @@ -116,15 +129,23 @@ where } /// Returns the source of the transaction. - pub(crate) fn source(&self) -> TransactionSource { - self.source + pub(crate) fn source(&self) -> TimedTransactionSource { + self.source.clone() + } +} + +impl Size for Arc> +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, +{ + fn size(&self) -> usize { + self.bytes } } type InternalTxMemPoolMap = - HashMap, Arc>>; -type InternalTxMemPoolMapEntry<'a, ChainApi, Block> = - Entry<'a, ExtrinsicHash, Arc>>; + graph::tracked_map::TrackedMap, Arc>>; /// An intermediary transactions buffer. /// @@ -153,13 +174,29 @@ where /// /// The key is the hash of the transaction, and the value is a wrapper /// structure, which contains the mempool specific details of the transaction. - transactions: RwLock>, + transactions: InternalTxMemPoolMap, /// Prometheus's metrics endpoint. metrics: PrometheusMetrics, /// Indicates the maximum number of transactions that can be maintained in the memory pool. max_transactions_count: usize, + + /// Maximal size of encodings of all transactions in the memory pool. + max_transactions_total_bytes: usize, +} + +/// Helper structure to encapsulate a result of [`TxMemPool::try_insert`]. +#[derive(Debug)] +pub(super) struct InsertionInfo { + pub(super) hash: Hash, + pub(super) source: TimedTransactionSource, +} + +impl InsertionInfo { + fn new(hash: Hash, source: TimedTransactionSource) -> Self { + Self { hash, source } + } } impl TxMemPool @@ -175,19 +212,32 @@ where listener: Arc>, metrics: PrometheusMetrics, max_transactions_count: usize, + max_transactions_total_bytes: usize, ) -> Self { - Self { api, listener, transactions: Default::default(), metrics, max_transactions_count } + Self { + api, + listener, + transactions: Default::default(), + metrics, + max_transactions_count, + max_transactions_total_bytes, + } } /// Creates a new `TxMemPool` instance for testing purposes. #[allow(dead_code)] - fn new_test(api: Arc, max_transactions_count: usize) -> Self { + fn new_test( + api: Arc, + max_transactions_count: usize, + max_transactions_total_bytes: usize, + ) -> Self { Self { api, listener: Arc::from(MultiViewListener::new()), transactions: Default::default(), metrics: Default::default(), max_transactions_count, + max_transactions_total_bytes, } } @@ -195,37 +245,57 @@ where pub(super) fn get_by_hash( &self, hash: ExtrinsicHash, - ) -> Option> { - self.transactions.read().get(&hash).map(|t| t.tx()) + ) -> Option>> { + self.transactions.read().get(&hash).map(Clone::clone) } /// Returns a tuple with the count of unwatched and watched transactions in the memory pool. - pub(super) fn unwatched_and_watched_count(&self) -> (usize, usize) { + pub fn unwatched_and_watched_count(&self) -> (usize, usize) { let transactions = self.transactions.read(); let watched_count = transactions.values().filter(|t| t.is_watched()).count(); (transactions.len() - watched_count, watched_count) } + /// Returns a total number of transactions kept within mempool. + pub fn len(&self) -> usize { + self.transactions.read().len() + } + + /// Returns the number of bytes used by all extrinsics in the the pool. + #[cfg(test)] + pub fn bytes(&self) -> usize { + return self.transactions.bytes() + } + + /// Returns true if provided values would exceed defined limits. + fn is_limit_exceeded(&self, length: usize, current_total_bytes: usize) -> bool { + length > self.max_transactions_count || + current_total_bytes > self.max_transactions_total_bytes + } + /// Attempts to insert a transaction into the memory pool, ensuring it does not /// exceed the maximum allowed transaction count. fn try_insert( &self, - current_len: usize, - entry: InternalTxMemPoolMapEntry<'_, ChainApi, Block>, hash: ExtrinsicHash, tx: TxInMemPool, - ) -> Result, ChainApi::Error> { - //todo: obey size limits [#5476] - let result = match (current_len < self.max_transactions_count, entry) { - (true, Entry::Vacant(v)) => { - v.insert(Arc::from(tx)); - Ok(hash) + ) -> Result>, ChainApi::Error> { + let bytes = self.transactions.bytes(); + let mut transactions = self.transactions.write(); + let result = match ( + !self.is_limit_exceeded(transactions.len() + 1, bytes + tx.bytes), + transactions.contains_key(&hash), + ) { + (true, false) => { + let source = tx.source(); + transactions.insert(hash, Arc::from(tx)); + Ok(InsertionInfo::new(hash, source)) }, - (_, Entry::Occupied(_)) => + (_, true) => Err(sc_transaction_pool_api::error::Error::AlreadyImported(Box::new(hash)).into()), (false, _) => Err(sc_transaction_pool_api::error::Error::ImmediatelyDropped.into()), }; - log::trace!(target: LOG_TARGET, "[{:?}] mempool::try_insert: {:?}", hash, result); + log::trace!(target: LOG_TARGET, "[{:?}] mempool::try_insert: {:?}", hash, result.as_ref().map(|r| r.hash)); result } @@ -238,18 +308,12 @@ where &self, source: TransactionSource, xts: &[ExtrinsicFor], - ) -> Vec, ChainApi::Error>> { - let mut transactions = self.transactions.write(); + ) -> Vec>, ChainApi::Error>> { let result = xts .iter() .map(|xt| { - let hash = self.api.hash_and_length(&xt).0; - self.try_insert( - transactions.len(), - transactions.entry(hash), - hash, - TxInMemPool::new_unwatched(source, xt.clone()), - ) + let (hash, length) = self.api.hash_and_length(&xt); + self.try_insert(hash, TxInMemPool::new_unwatched(source, xt.clone(), length)) }) .collect::>(); result @@ -261,31 +325,18 @@ where &self, source: TransactionSource, xt: ExtrinsicFor, - ) -> Result, ChainApi::Error> { - let mut transactions = self.transactions.write(); - let hash = self.api.hash_and_length(&xt).0; - self.try_insert( - transactions.len(), - transactions.entry(hash), - hash, - TxInMemPool::new_watched(source, xt.clone()), - ) - } - - /// Removes transactions from the memory pool which are specified by the given list of hashes - /// and send the `Dropped` event to the listeners of these transactions. - pub(super) async fn remove_dropped_transactions( - &self, - to_be_removed: &[ExtrinsicHash], - ) { - log::debug!(target: LOG_TARGET, "remove_dropped_transactions count:{:?}", to_be_removed.len()); - log_xt_trace!(target: LOG_TARGET, to_be_removed, "[{:?}] mempool::remove_dropped_transactions"); - let mut transactions = self.transactions.write(); - to_be_removed.iter().for_each(|t| { - transactions.remove(t); - }); + ) -> Result>, ChainApi::Error> { + let (hash, length) = self.api.hash_and_length(&xt); + self.try_insert(hash, TxInMemPool::new_watched(source, xt.clone(), length)) + } - self.listener.transactions_dropped(to_be_removed); + /// Removes transaction from the memory pool which are specified by the given list of hashes. + pub(super) async fn remove_dropped_transaction( + &self, + dropped: &ExtrinsicHash, + ) -> Option>> { + log::debug!(target: LOG_TARGET, "[{:?}] mempool::remove_dropped_transaction", dropped); + self.transactions.write().remove(dropped) } /// Clones and returns a `HashMap` of references to all unwatched transactions in the memory @@ -324,12 +375,11 @@ where let start = Instant::now(); let (count, input) = { - let transactions = self.transactions.read(); + let transactions = self.transactions.clone_map(); ( transactions.len(), transactions - .clone() .into_iter() .filter(|xt| { let finalized_block_number = finalized_block.number.into().as_u64(); @@ -343,13 +393,13 @@ where }; let validations_futures = input.into_iter().map(|(xt_hash, xt)| { - self.api.validate_transaction(finalized_block.hash, xt.source, xt.tx()).map( - move |validation_result| { + self.api + .validate_transaction(finalized_block.hash, xt.source.clone().into(), xt.tx()) + .map(move |validation_result| { xt.validated_at .store(finalized_block.number.into().as_u64(), atomic::Ordering::Relaxed); (xt_hash, validation_result) - }, - ) + }) }); let validation_results = futures::future::join_all(validations_futures).await; let input_len = validation_results.len(); @@ -377,7 +427,7 @@ where log::debug!( target: LOG_TARGET, - "mempool::revalidate: at {finalized_block:?} count:{input_len}/{count} purged:{} took {duration:?}", invalid_hashes.len(), + "mempool::revalidate: at {finalized_block:?} count:{input_len}/{count} invalid_hashes:{} took {duration:?}", invalid_hashes.len(), ); invalid_hashes @@ -417,9 +467,9 @@ where #[cfg(test)] mod tx_mem_pool_tests { use super::*; - use crate::common::tests::TestApi; - use substrate_test_runtime::{AccountId, Extrinsic, Transfer, H256}; - use substrate_test_runtime_client::AccountKeyring::*; + use crate::{common::tests::TestApi, graph::ChainApi}; + use substrate_test_runtime::{AccountId, Extrinsic, ExtrinsicBuilder, Transfer, H256}; + use substrate_test_runtime_client::Sr25519Keyring::*; fn uxt(nonce: u64) -> Extrinsic { crate::common::tests::uxt(Transfer { from: Alice.into(), @@ -433,7 +483,7 @@ mod tx_mem_pool_tests { fn extend_unwatched_obeys_limit() { let max = 10; let api = Arc::from(TestApi::default()); - let mempool = TxMemPool::new_test(api, max); + let mempool = TxMemPool::new_test(api, max, usize::MAX); let xts = (0..max + 1).map(|x| Arc::from(uxt(x as _))).collect::>(); @@ -450,7 +500,7 @@ mod tx_mem_pool_tests { sp_tracing::try_init_simple(); let max = 10; let api = Arc::from(TestApi::default()); - let mempool = TxMemPool::new_test(api, max); + let mempool = TxMemPool::new_test(api, max, usize::MAX); let mut xts = (0..max - 1).map(|x| Arc::from(uxt(x as _))).collect::>(); xts.push(xts.iter().last().unwrap().clone()); @@ -467,7 +517,7 @@ mod tx_mem_pool_tests { fn push_obeys_limit() { let max = 10; let api = Arc::from(TestApi::default()); - let mempool = TxMemPool::new_test(api, max); + let mempool = TxMemPool::new_test(api, max, usize::MAX); let xts = (0..max).map(|x| Arc::from(uxt(x as _))).collect::>(); @@ -492,7 +542,7 @@ mod tx_mem_pool_tests { fn push_detects_already_imported() { let max = 10; let api = Arc::from(TestApi::default()); - let mempool = TxMemPool::new_test(api, 2 * max); + let mempool = TxMemPool::new_test(api, 2 * max, usize::MAX); let xts = (0..max).map(|x| Arc::from(uxt(x as _))).collect::>(); let xt0 = xts.iter().last().unwrap().clone(); @@ -517,7 +567,7 @@ mod tx_mem_pool_tests { fn count_works() { let max = 100; let api = Arc::from(TestApi::default()); - let mempool = TxMemPool::new_test(api, max); + let mempool = TxMemPool::new_test(api, max, usize::MAX); let xts0 = (0..10).map(|x| Arc::from(uxt(x as _))).collect::>(); @@ -532,4 +582,39 @@ mod tx_mem_pool_tests { assert!(results.iter().all(Result::is_ok)); assert_eq!(mempool.unwatched_and_watched_count(), (10, 5)); } + + fn large_uxt(x: usize) -> Extrinsic { + ExtrinsicBuilder::new_include_data(vec![x as u8; 1024]).build() + } + + #[test] + fn push_obeys_size_limit() { + sp_tracing::try_init_simple(); + let max = 10; + let api = Arc::from(TestApi::default()); + //size of large extrinsic is: 1129 + let mempool = TxMemPool::new_test(api.clone(), usize::MAX, max * 1129); + + let xts = (0..max).map(|x| Arc::from(large_uxt(x))).collect::>(); + + let total_xts_bytes = xts.iter().fold(0, |r, x| r + api.hash_and_length(&x).1); + + let results = mempool.extend_unwatched(TransactionSource::External, &xts); + assert!(results.iter().all(Result::is_ok)); + assert_eq!(mempool.bytes(), total_xts_bytes); + + let xt = Arc::from(large_uxt(98)); + let result = mempool.push_watched(TransactionSource::External, xt); + assert!(matches!( + result.unwrap_err(), + sc_transaction_pool_api::error::Error::ImmediatelyDropped + )); + + let xt = Arc::from(large_uxt(99)); + let mut result = mempool.extend_unwatched(TransactionSource::External, &[xt]); + assert!(matches!( + result.pop().unwrap().unwrap_err(), + sc_transaction_pool_api::error::Error::ImmediatelyDropped + )); + } } diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/view.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/view.rs index 99095d88cb0a..3cbb8fa4871d 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/view.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/view.rs @@ -27,13 +27,13 @@ use super::metrics::MetricsLink as PrometheusMetrics; use crate::{ common::log_xt::log_xt_trace, graph::{ - self, watcher::Watcher, ExtrinsicFor, ExtrinsicHash, IsValidator, ValidatedTransaction, - ValidatedTransactionFor, + self, base_pool::TimedTransactionSource, watcher::Watcher, ExtrinsicFor, ExtrinsicHash, + IsValidator, ValidatedTransaction, ValidatedTransactionFor, }, LOG_TARGET, }; use parking_lot::Mutex; -use sc_transaction_pool_api::{error::Error as TxPoolError, PoolStatus, TransactionSource}; +use sc_transaction_pool_api::{error::Error as TxPoolError, PoolStatus}; use sp_blockchain::HashAndNumber; use sp_runtime::{ generic::BlockId, traits::Block as BlockT, transaction_validity::TransactionValidityError, @@ -157,22 +157,21 @@ where /// Imports many unvalidated extrinsics into the view. pub(super) async fn submit_many( &self, - source: TransactionSource, - xts: impl IntoIterator>, + xts: impl IntoIterator)>, ) -> Vec, ChainApi::Error>> { if log::log_enabled!(target: LOG_TARGET, log::Level::Trace) { let xts = xts.into_iter().collect::>(); - log_xt_trace!(target: LOG_TARGET, xts.iter().map(|xt| self.pool.validated_pool().api().hash_and_length(xt).0), "[{:?}] view::submit_many at:{}", self.at.hash); - self.pool.submit_at(&self.at, source, xts).await + log_xt_trace!(target: LOG_TARGET, xts.iter().map(|(_,xt)| self.pool.validated_pool().api().hash_and_length(xt).0), "[{:?}] view::submit_many at:{}", self.at.hash); + self.pool.submit_at(&self.at, xts).await } else { - self.pool.submit_at(&self.at, source, xts).await + self.pool.submit_at(&self.at, xts).await } } /// Import a single extrinsic and starts to watch its progress in the view. pub(super) async fn submit_and_watch( &self, - source: TransactionSource, + source: TimedTransactionSource, xt: ExtrinsicFor, ) -> Result, ExtrinsicHash>, ChainApi::Error> { log::trace!(target: LOG_TARGET, "[{:?}] view::submit_and_watch at:{}", self.pool.validated_pool().api().hash_and_length(&xt).0, self.at.hash); @@ -193,7 +192,7 @@ where .api() .validate_transaction_blocking( self.at.hash, - TransactionSource::Local, + sc_transaction_pool_api::TransactionSource::Local, Arc::from(xt.clone()), )? .map_err(|e| { @@ -214,7 +213,7 @@ where let validated = ValidatedTransaction::valid_at( block_number.saturated_into::(), hash, - TransactionSource::Local, + TimedTransactionSource::new_local(true), Arc::from(xt), length, validity, @@ -285,7 +284,7 @@ where } _ = async { if let Some(tx) = batch_iter.next() { - let validation_result = (api.validate_transaction(self.at.hash, tx.source, tx.data.clone()).await, tx.hash, tx); + let validation_result = (api.validate_transaction(self.at.hash, tx.source.clone().into(), tx.data.clone()).await, tx.hash, tx); validation_results.push(validation_result); } else { self.revalidation_worker_channels.lock().as_mut().map(|ch| ch.remove_sender()); @@ -324,7 +323,7 @@ where ValidatedTransaction::valid_at( self.at.number.saturated_into::(), tx_hash, - tx.source, + tx.source.clone(), tx.data.clone(), api.hash_and_length(&tx.data).1, validity, @@ -455,4 +454,10 @@ where ); } } + + /// Returns true if the transaction with given hash is already imported into the view. + pub(super) fn is_imported(&self, tx_hash: &ExtrinsicHash) -> bool { + const IGNORE_BANNED: bool = false; + self.pool.validated_pool().check_is_known(tx_hash, IGNORE_BANNED).is_err() + } } diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/view_store.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/view_store.rs index 413fca223242..a06c051f0a7e 100644 --- a/substrate/client/transaction-pool/src/fork_aware_txpool/view_store.rs +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/view_store.rs @@ -24,17 +24,51 @@ use super::{ }; use crate::{ fork_aware_txpool::dropped_watcher::MultiViewDroppedWatcherController, - graph, - graph::{base_pool::Transaction, ExtrinsicFor, ExtrinsicHash, TransactionFor}, + graph::{ + self, + base_pool::{TimedTransactionSource, Transaction}, + ExtrinsicFor, ExtrinsicHash, TransactionFor, + }, ReadyIteratorFor, LOG_TARGET, }; use futures::prelude::*; use itertools::Itertools; use parking_lot::RwLock; -use sc_transaction_pool_api::{error::Error as PoolError, PoolStatus, TransactionSource}; +use sc_transaction_pool_api::{error::Error as PoolError, PoolStatus}; use sp_blockchain::TreeRoute; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; -use std::{collections::HashMap, sync::Arc, time::Instant}; +use std::{ + collections::{hash_map::Entry, HashMap}, + sync::Arc, + time::Instant, +}; + +/// Helper struct to keep the context for transaction replacements. +#[derive(Clone)] +struct PendingTxReplacement +where + ChainApi: graph::ChainApi, +{ + /// Indicates if the new transaction was already submitted to all the views in the view_store. + /// If true, it can be removed after inserting any new view. + processed: bool, + /// New transaction replacing the old one. + xt: ExtrinsicFor, + /// Source of the transaction. + source: TimedTransactionSource, + /// Inidicates if transaction is watched. + watched: bool, +} + +impl PendingTxReplacement +where + ChainApi: graph::ChainApi, +{ + /// Creates new unprocessed instance of pending transaction replacement. + fn new(xt: ExtrinsicFor, source: TimedTransactionSource, watched: bool) -> Self { + Self { processed: false, xt, source, watched } + } +} /// The helper structure encapsulates all the views. pub(super) struct ViewStore @@ -62,6 +96,13 @@ where pub(super) most_recent_view: RwLock>, /// The controller of multi view dropped stream. pub(super) dropped_stream_controller: MultiViewDroppedWatcherController, + /// The map used to synchronize replacement of transactions between maintain and dropped + /// notifcication threads. It is meant to assure that replaced transaction is also removed from + /// newly built views in maintain process. + /// + /// The map's key is hash of replaced extrinsic. + pending_txs_replacements: + RwLock, PendingTxReplacement>>, } impl ViewStore @@ -83,15 +124,14 @@ where listener, most_recent_view: RwLock::from(None), dropped_stream_controller, + pending_txs_replacements: Default::default(), } } /// Imports a bunch of unverified extrinsics to every active view. pub(super) async fn submit( &self, - source: TransactionSource, - xts: impl IntoIterator> + Clone, - xts_hashes: impl IntoIterator> + Clone, + xts: impl IntoIterator)> + Clone, ) -> HashMap, ChainApi::Error>>> { let submit_futures = { let active_views = self.active_views.read(); @@ -100,9 +140,7 @@ where .map(|(_, view)| { let view = view.clone(); let xts = xts.clone(); - self.dropped_stream_controller - .add_initial_views(xts_hashes.clone(), view.at.hash); - async move { (view.at.hash, view.submit_many(source, xts.clone()).await) } + async move { (view.at.hash, view.submit_many(xts).await) } }) .collect::>() }; @@ -127,11 +165,7 @@ where let result = active_views .iter() - .map(|view| { - self.dropped_stream_controller - .add_initial_views(std::iter::once(tx_hash), view.at.hash); - view.submit_local(xt.clone()) - }) + .map(|view| view.submit_local(xt.clone())) .find_or_first(Result::is_ok); if let Some(Err(err)) = result { @@ -152,12 +186,12 @@ where pub(super) async fn submit_and_watch( &self, _at: Block::Hash, - source: TransactionSource, + source: TimedTransactionSource, xt: ExtrinsicFor, - ) -> Result, (ChainApi::Error, Option>)> { + ) -> Result, ChainApi::Error> { let tx_hash = self.api.hash_and_length(&xt).0; let Some(external_watcher) = self.listener.create_external_watcher_for_tx(tx_hash) else { - return Err((PoolError::AlreadyImported(Box::new(tx_hash)).into(), None)) + return Err(PoolError::AlreadyImported(Box::new(tx_hash)).into()) }; let submit_and_watch_futures = { let active_views = self.active_views.read(); @@ -166,8 +200,7 @@ where .map(|(_, view)| { let view = view.clone(); let xt = xt.clone(); - self.dropped_stream_controller - .add_initial_views(std::iter::once(tx_hash), view.at.hash); + let source = source.clone(); async move { match view.submit_and_watch(source, xt).await { Ok(watcher) => { @@ -191,7 +224,7 @@ where if let Some(Err(err)) = maybe_error { log::trace!(target: LOG_TARGET, "[{:?}] submit_and_watch: err: {}", tx_hash, err); - return Err((err, Some(external_watcher))); + return Err(err); }; Ok(external_watcher) @@ -270,12 +303,20 @@ where ) -> Vec, ExtrinsicFor>> { self.most_recent_view .read() - .map(|at| self.get_view_at(at, true)) + .map(|at| self.futures_at(at)) .flatten() - .map(|(v, _)| v.pool.validated_pool().pool.read().futures().cloned().collect()) .unwrap_or_default() } + /// Returns a list of future transactions in the view at given block hash. + pub(super) fn futures_at( + &self, + at: Block::Hash, + ) -> Option, ExtrinsicFor>>> { + self.get_view_at(at, true) + .map(|(v, _)| v.pool.validated_pool().pool.read().futures().cloned().collect()) + } + /// Collects all the transactions included in the blocks on the provided `tree_route` and /// triggers finalization event for them. /// @@ -338,12 +379,16 @@ where /// - moved to the inactive views set (`inactive_views`), /// - removed from the multi view listeners. /// - /// The `most_recent_view` is update with the reference to the newly inserted view. + /// The `most_recent_view` is updated with the reference to the newly inserted view. + /// + /// If there are any pending tx replacments, they are applied to the new view. pub(super) async fn insert_new_view( &self, view: Arc>, tree_route: &TreeRoute, ) { + self.apply_pending_tx_replacements(view.clone()).await; + //note: most_recent_view must be synced with changes in in/active_views. { let mut most_recent_view_lock = self.most_recent_view.write(); @@ -395,8 +440,10 @@ where let mut removed_views = vec![]; { - self.active_views - .read() + let active_views = self.active_views.read(); + let inactive_views = self.inactive_views.read(); + + active_views .iter() .filter(|(hash, v)| !match finalized_number { Err(_) | Ok(None) => **hash == finalized_hash, @@ -405,11 +452,8 @@ where }) .map(|(_, v)| removed_views.push(v.at.hash)) .for_each(drop); - } - { - self.inactive_views - .read() + inactive_views .iter() .filter(|(_, v)| !match finalized_number { Err(_) | Ok(None) => false, @@ -447,30 +491,48 @@ where let finalized_xts = self.finalize_route(finalized_hash, tree_route).await; let finalized_number = self.api.block_id_to_number(&BlockId::Hash(finalized_hash)); + let mut dropped_views = vec![]; //clean up older then finalized { let mut active_views = self.active_views.write(); - active_views.retain(|hash, v| match finalized_number { - Err(_) | Ok(None) => *hash == finalized_hash, - Ok(Some(n)) if v.at.number == n => *hash == finalized_hash, - Ok(Some(n)) => v.at.number > n, + let mut inactive_views = self.inactive_views.write(); + active_views.retain(|hash, v| { + let retain = match finalized_number { + Err(_) | Ok(None) => *hash == finalized_hash, + Ok(Some(n)) if v.at.number == n => *hash == finalized_hash, + Ok(Some(n)) => v.at.number > n, + }; + if !retain { + dropped_views.push(*hash); + } + retain }); - } - { - let mut inactive_views = self.inactive_views.write(); - inactive_views.retain(|_, v| match finalized_number { - Err(_) | Ok(None) => false, - Ok(Some(n)) => v.at.number >= n, + inactive_views.retain(|hash, v| { + let retain = match finalized_number { + Err(_) | Ok(None) => false, + Ok(Some(n)) => v.at.number >= n, + }; + if !retain { + dropped_views.push(*hash); + } + retain }); log::trace!(target:LOG_TARGET,"handle_finalized: inactive_views: {:?}", inactive_views.keys()); } - self.listener.remove_view(finalized_hash); + log::trace!(target:LOG_TARGET,"handle_finalized: dropped_views: {:?}", dropped_views); + self.listener.remove_stale_controllers(); self.dropped_stream_controller.remove_finalized_txs(finalized_xts.clone()); + self.listener.remove_view(finalized_hash); + for view in dropped_views { + self.listener.remove_view(view); + self.dropped_stream_controller.remove_view(view); + } + finalized_xts } @@ -493,4 +555,139 @@ where futures::future::join_all(finish_revalidation_futures).await; log::trace!(target:LOG_TARGET,"finish_background_revalidations took {:?}", start.elapsed()); } + + /// Replaces an existing transaction in the view_store with a new one. + /// + /// Attempts to replace a transaction identified by `replaced` with a new transaction `xt`. + /// + /// Before submitting a transaction to the views, the new *unprocessed* transaction replacement + /// record will be inserted into a pending replacement map. Once the submission to all the views + /// is accomplished, the record is marked as *processed*. + /// + /// This map is later applied in `insert_new_view` method executed from different thread. + /// + /// If the transaction is already being replaced, it will simply return without making + /// changes. + pub(super) async fn replace_transaction( + &self, + source: TimedTransactionSource, + xt: ExtrinsicFor, + replaced: ExtrinsicHash, + watched: bool, + ) { + if let Entry::Vacant(entry) = self.pending_txs_replacements.write().entry(replaced) { + entry.insert(PendingTxReplacement::new(xt.clone(), source.clone(), watched)); + } else { + return + }; + + let xt_hash = self.api.hash_and_length(&xt).0; + log::trace!(target:LOG_TARGET,"[{replaced:?}] replace_transaction wtih {xt_hash:?}, w:{watched}"); + + self.replace_transaction_in_views(source, xt, xt_hash, replaced, watched).await; + + if let Some(replacement) = self.pending_txs_replacements.write().get_mut(&replaced) { + replacement.processed = true; + } + } + + /// Applies pending transaction replacements to the specified view. + /// + /// After application, all already processed replacements are removed. + async fn apply_pending_tx_replacements(&self, view: Arc>) { + let mut futures = vec![]; + for replacement in self.pending_txs_replacements.read().values() { + let xt_hash = self.api.hash_and_length(&replacement.xt).0; + futures.push(self.replace_transaction_in_view( + view.clone(), + replacement.source.clone(), + replacement.xt.clone(), + xt_hash, + replacement.watched, + )); + } + let _results = futures::future::join_all(futures).await; + self.pending_txs_replacements.write().retain(|_, r| r.processed); + } + + /// Submits `xt` to the given view. + /// + /// For watched transaction stream is added to the listener. + async fn replace_transaction_in_view( + &self, + view: Arc>, + source: TimedTransactionSource, + xt: ExtrinsicFor, + xt_hash: ExtrinsicHash, + watched: bool, + ) { + if watched { + match view.submit_and_watch(source, xt).await { + Ok(watcher) => { + self.listener.add_view_watcher_for_tx( + xt_hash, + view.at.hash, + watcher.into_stream().boxed(), + ); + }, + Err(e) => { + log::trace!( + target:LOG_TARGET, + "[{:?}] replace_transaction: submit_and_watch to {} failed {}", + xt_hash, view.at.hash, e + ); + }, + } + } else { + if let Some(Err(e)) = view.submit_many(std::iter::once((source, xt))).await.pop() { + log::trace!( + target:LOG_TARGET, + "[{:?}] replace_transaction: submit to {} failed {}", + xt_hash, view.at.hash, e + ); + } + } + } + + /// Sends `xt` to every view (both active and inactive) containing `replaced` extrinsics. + /// + /// It is assumed that transaction is already known by the pool. Intended to ba called when `xt` + /// is replacing `replaced` extrinsic. + async fn replace_transaction_in_views( + &self, + source: TimedTransactionSource, + xt: ExtrinsicFor, + xt_hash: ExtrinsicHash, + replaced: ExtrinsicHash, + watched: bool, + ) { + if watched && !self.listener.contains_tx(&xt_hash) { + log::trace!( + target:LOG_TARGET, + "error: replace_transaction_in_views: no listener for watched transaction {:?}", + xt_hash, + ); + return; + } + + let submit_futures = { + let active_views = self.active_views.read(); + let inactive_views = self.inactive_views.read(); + active_views + .iter() + .chain(inactive_views.iter()) + .filter(|(_, view)| view.is_imported(&replaced)) + .map(|(_, view)| { + self.replace_transaction_in_view( + view.clone(), + source.clone(), + xt.clone(), + xt_hash, + watched, + ) + }) + .collect::>() + }; + let _results = futures::future::join_all(submit_futures).await; + } } diff --git a/substrate/client/transaction-pool/src/graph/base_pool.rs b/substrate/client/transaction-pool/src/graph/base_pool.rs index e4c3a6c425a9..04eaa998f42e 100644 --- a/substrate/client/transaction-pool/src/graph/base_pool.rs +++ b/substrate/client/transaction-pool/src/graph/base_pool.rs @@ -20,7 +20,7 @@ //! //! For a more full-featured pool, have a look at the `pool` module. -use std::{cmp::Ordering, collections::HashSet, fmt, hash, sync::Arc}; +use std::{cmp::Ordering, collections::HashSet, fmt, hash, sync::Arc, time::Instant}; use crate::LOG_TARGET; use log::{trace, warn}; @@ -30,8 +30,8 @@ use sp_core::hexdisplay::HexDisplay; use sp_runtime::{ traits::Member, transaction_validity::{ - TransactionLongevity as Longevity, TransactionPriority as Priority, - TransactionSource as Source, TransactionTag as Tag, + TransactionLongevity as Longevity, TransactionPriority as Priority, TransactionSource, + TransactionTag as Tag, }, }; @@ -83,6 +83,44 @@ pub struct PruneStatus { pub pruned: Vec>>, } +/// A transaction source that includes a timestamp indicating when the transaction was submitted. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TimedTransactionSource { + /// The original source of the transaction. + pub source: TransactionSource, + + /// The time at which the transaction was submitted. + pub timestamp: Option, +} + +impl From for TransactionSource { + fn from(value: TimedTransactionSource) -> Self { + value.source + } +} + +impl TimedTransactionSource { + /// Creates a new instance with an internal `TransactionSource::InBlock` source and an optional + /// timestamp. + pub fn new_in_block(with_timestamp: bool) -> Self { + Self { source: TransactionSource::InBlock, timestamp: with_timestamp.then(Instant::now) } + } + /// Creates a new instance with an internal `TransactionSource::External` source and an optional + /// timestamp. + pub fn new_external(with_timestamp: bool) -> Self { + Self { source: TransactionSource::External, timestamp: with_timestamp.then(Instant::now) } + } + /// Creates a new instance with an internal `TransactionSource::Local` source and an optional + /// timestamp. + pub fn new_local(with_timestamp: bool) -> Self { + Self { source: TransactionSource::Local, timestamp: with_timestamp.then(Instant::now) } + } + /// Creates a new instance with an given source and an optional timestamp. + pub fn from_transaction_source(source: TransactionSource, with_timestamp: bool) -> Self { + Self { source, timestamp: with_timestamp.then(Instant::now) } + } +} + /// Immutable transaction #[derive(PartialEq, Eq, Clone)] pub struct Transaction { @@ -102,8 +140,8 @@ pub struct Transaction { pub provides: Vec, /// Should that transaction be propagated. pub propagate: bool, - /// Source of that transaction. - pub source: Source, + /// Timed source of that transaction. + pub source: TimedTransactionSource, } impl AsRef for Transaction { @@ -157,7 +195,7 @@ impl Transaction { bytes: self.bytes, hash: self.hash.clone(), priority: self.priority, - source: self.source, + source: self.source.clone(), valid_till: self.valid_till, requires: self.requires.clone(), provides: self.provides.clone(), @@ -322,22 +360,36 @@ impl BasePool { if !first { - promoted.push(current_hash); + promoted.push(current_hash.clone()); } + // If there were conflicting future transactions promoted, removed them from + // promoted set. + promoted.retain(|hash| replaced.iter().all(|tx| *hash != tx.hash)); // The transactions were removed from the ready pool. We might attempt to // re-import them. removed.append(&mut replaced); }, + Err(e @ error::Error::TooLowPriority { .. }) => + if first { + trace!(target: LOG_TARGET, "[{:?}] Error importing {first}: {:?}", current_tx.hash, e); + return Err(e) + } else { + trace!(target: LOG_TARGET, "[{:?}] Error importing {first}: {:?}", current_tx.hash, e); + removed.push(current_tx); + promoted.retain(|hash| *hash != current_hash); + }, // transaction failed to be imported. Err(e) => if first { - trace!(target: LOG_TARGET, "[{:?}] Error importing: {:?}", current_hash, e); + trace!(target: LOG_TARGET, "[{:?}] Error importing {first}: {:?}", current_tx.hash, e); return Err(e) } else { - failed.push(current_hash); + trace!(target: LOG_TARGET, "[{:?}] Error importing {first}: {:?}", current_tx.hash, e); + failed.push(current_tx.hash.clone()); }, } first = false; @@ -434,8 +486,24 @@ impl BasePool Some(current.clone()), - Some(ref tx) if tx.imported_at > current.imported_at => Some(current.clone()), - other => other, + Some(worst) => Some( + match (worst.transaction.source.timestamp, current.transaction.source.timestamp) + { + (Some(worst_timestamp), Some(current_timestamp)) => { + if worst_timestamp > current_timestamp { + current.clone() + } else { + worst + } + }, + _ => + if worst.imported_at > current.imported_at { + current.clone() + } else { + worst + }, + }, + ), }); if let Some(worst) = worst { @@ -562,7 +630,7 @@ mod tests { requires: vec![], provides: vec![], propagate: true, - source: Source::External, + source: TimedTransactionSource::new_external(false), } } @@ -760,6 +828,58 @@ mod tests { ); } + #[test] + fn should_remove_conflicting_future() { + let mut pool = pool(); + pool.import(Transaction { + data: vec![3u8].into(), + hash: 3, + requires: vec![vec![1]], + priority: 50u64, + provides: vec![vec![3]], + ..default_tx().clone() + }) + .unwrap(); + assert_eq!(pool.ready().count(), 0); + assert_eq!(pool.ready.len(), 0); + + let tx2 = Transaction { + data: vec![2u8].into(), + hash: 2, + requires: vec![vec![1]], + provides: vec![vec![3]], + ..default_tx().clone() + }; + pool.import(tx2.clone()).unwrap(); + assert_eq!(pool.future.len(), 2); + + let res = pool + .import(Transaction { + data: vec![1u8].into(), + hash: 1, + provides: vec![vec![1]], + ..default_tx().clone() + }) + .unwrap(); + + assert_eq!( + res, + Imported::Ready { + hash: 1, + promoted: vec![3], + failed: vec![], + removed: vec![tx2.into()] + } + ); + + let mut it = pool.ready().into_iter().map(|tx| tx.data[0]); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(3)); + assert_eq!(it.next(), None); + + assert_eq!(pool.future.len(), 0); + } + #[test] fn should_handle_a_cycle() { // given @@ -783,14 +903,14 @@ mod tests { assert_eq!(pool.ready.len(), 0); // when - pool.import(Transaction { + let tx2 = Transaction { data: vec![2u8].into(), hash: 2, requires: vec![vec![2]], provides: vec![vec![0]], ..default_tx().clone() - }) - .unwrap(); + }; + pool.import(tx2.clone()).unwrap(); // then { @@ -817,7 +937,12 @@ mod tests { assert_eq!(it.next(), None); assert_eq!( res, - Imported::Ready { hash: 4, promoted: vec![1, 3], failed: vec![2], removed: vec![] } + Imported::Ready { + hash: 4, + promoted: vec![1, 3], + failed: vec![], + removed: vec![tx2.into()] + } ); assert_eq!(pool.future.len(), 0); } @@ -1024,7 +1149,7 @@ mod tests { ), "Transaction { \ hash: 4, priority: 1000, valid_till: 64, bytes: 1, propagate: true, \ -source: TransactionSource::External, requires: [03, 02], provides: [04], data: [4]}" +source: TimedTransactionSource { source: TransactionSource::External, timestamp: None }, requires: [03, 02], provides: [04], data: [4]}" .to_owned() ); } diff --git a/substrate/client/transaction-pool/src/graph/listener.rs b/substrate/client/transaction-pool/src/graph/listener.rs index a5593920eec4..41daf5491f70 100644 --- a/substrate/client/transaction-pool/src/graph/listener.rs +++ b/substrate/client/transaction-pool/src/graph/listener.rs @@ -36,6 +36,7 @@ pub type DroppedByLimitsStream = TracingUnboundedReceiver { + /// Map containing per-transaction sinks for emitting transaction status events. watchers: HashMap>>, finality_watchers: LinkedHashMap, Vec>, @@ -119,32 +120,44 @@ impl Listener, limits_enforced: bool) { + /// Transaction was dropped from the pool because of enforcing the limit. + pub fn limit_enforced(&mut self, tx: &H) { + trace!(target: LOG_TARGET, "[{:?}] Dropped (limit enforced)", tx); + self.fire(tx, |watcher| watcher.limit_enforced()); + + if let Some(ref sink) = self.dropped_by_limits_sink { + if let Err(e) = sink.unbounded_send((tx.clone(), TransactionStatus::Dropped)) { + trace!(target: LOG_TARGET, "[{:?}] dropped_sink: send message failed: {:?}", tx, e); + } + } + } + + /// Transaction was replaced with other extrinsic. + pub fn usurped(&mut self, tx: &H, by: &H) { trace!(target: LOG_TARGET, "[{:?}] Dropped (replaced with {:?})", tx, by); - self.fire(tx, |watcher| match by { - Some(t) => watcher.usurped(t.clone()), - None => watcher.dropped(), - }); - - //note: LimitEnforced could be introduced as new status to get rid of this flag. - if limits_enforced { - if let Some(ref sink) = self.dropped_by_limits_sink { - if let Err(e) = sink.unbounded_send((tx.clone(), TransactionStatus::Dropped)) { - trace!(target: LOG_TARGET, "[{:?}] dropped_sink/future: send message failed: {:?}", tx, e); - } + self.fire(tx, |watcher| watcher.usurped(by.clone())); + + if let Some(ref sink) = self.dropped_by_limits_sink { + if let Err(e) = + sink.unbounded_send((tx.clone(), TransactionStatus::Usurped(by.clone()))) + { + trace!(target: LOG_TARGET, "[{:?}] dropped_sink: send message failed: {:?}", tx, e); } } } + /// Transaction was dropped from the pool because of the failure during the resubmission of + /// revalidate transactions or failure during pruning tags. + pub fn dropped(&mut self, tx: &H) { + trace!(target: LOG_TARGET, "[{:?}] Dropped", tx); + self.fire(tx, |watcher| watcher.dropped()); + } + /// Transaction was removed as invalid. pub fn invalid(&mut self, tx: &H) { trace!(target: LOG_TARGET, "[{:?}] Extrinsic invalid", tx); diff --git a/substrate/client/transaction-pool/src/graph/mod.rs b/substrate/client/transaction-pool/src/graph/mod.rs index c1225d7356d9..d93898b1b22a 100644 --- a/substrate/client/transaction-pool/src/graph/mod.rs +++ b/substrate/client/transaction-pool/src/graph/mod.rs @@ -31,7 +31,7 @@ mod listener; mod pool; mod ready; mod rotator; -mod tracked_map; +pub(crate) mod tracked_map; mod validated_pool; pub mod base_pool; diff --git a/substrate/client/transaction-pool/src/graph/pool.rs b/substrate/client/transaction-pool/src/graph/pool.rs index 2dd8de352c6b..ff9cc1541af4 100644 --- a/substrate/client/transaction-pool/src/graph/pool.rs +++ b/substrate/client/transaction-pool/src/graph/pool.rs @@ -181,10 +181,8 @@ impl Pool { pub async fn submit_at( &self, at: &HashAndNumber, - source: TransactionSource, - xts: impl IntoIterator>, + xts: impl IntoIterator)>, ) -> Vec, B::Error>> { - let xts = xts.into_iter().map(|xt| (source, xt)); let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::Yes).await; self.validated_pool.submit(validated_transactions.into_values()) } @@ -195,10 +193,8 @@ impl Pool { pub async fn resubmit_at( &self, at: &HashAndNumber, - source: TransactionSource, - xts: impl IntoIterator>, + xts: impl IntoIterator)>, ) -> Vec, B::Error>> { - let xts = xts.into_iter().map(|xt| (source, xt)); let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::No).await; self.validated_pool.submit(validated_transactions.into_values()) } @@ -207,10 +203,10 @@ impl Pool { pub async fn submit_one( &self, at: &HashAndNumber, - source: TransactionSource, + source: base::TimedTransactionSource, xt: ExtrinsicFor, ) -> Result, B::Error> { - let res = self.submit_at(at, source, std::iter::once(xt)).await.pop(); + let res = self.submit_at(at, std::iter::once((source, xt))).await.pop(); res.expect("One extrinsic passed; one result returned; qed") } @@ -218,7 +214,7 @@ impl Pool { pub async fn submit_and_watch( &self, at: &HashAndNumber, - source: TransactionSource, + source: base::TimedTransactionSource, xt: ExtrinsicFor, ) -> Result, ExtrinsicHash>, B::Error> { let (_, tx) = self @@ -368,7 +364,7 @@ impl Pool { // Try to re-validate pruned transactions since some of them might be still valid. // note that `known_imported_hashes` will be rejected here due to temporary ban. let pruned_transactions = - prune_status.pruned.into_iter().map(|tx| (tx.source, tx.data.clone())); + prune_status.pruned.into_iter().map(|tx| (tx.source.clone(), tx.data.clone())); let reverified_transactions = self.verify(at, pruned_transactions, CheckBannedBeforeVerify::Yes).await; @@ -396,7 +392,7 @@ impl Pool { async fn verify( &self, at: &HashAndNumber, - xts: impl IntoIterator)>, + xts: impl IntoIterator)>, check: CheckBannedBeforeVerify, ) -> IndexMap, ValidatedTransactionFor> { let HashAndNumber { number, hash } = *at; @@ -417,7 +413,7 @@ impl Pool { &self, block_hash: ::Hash, block_number: NumberFor, - source: TransactionSource, + source: base::TimedTransactionSource, xt: ExtrinsicFor, check: CheckBannedBeforeVerify, ) -> (ExtrinsicHash, ValidatedTransactionFor) { @@ -431,7 +427,7 @@ impl Pool { let validation_result = self .validated_pool .api() - .validate_transaction(block_hash, source, xt.clone()) + .validate_transaction(block_hash, source.clone().into(), xt.clone()) .await; let status = match validation_result { @@ -488,6 +484,7 @@ mod tests { use super::{super::base_pool::Limit, *}; use crate::common::tests::{pool, uxt, TestApi, INVALID_NONCE}; use assert_matches::assert_matches; + use base::TimedTransactionSource; use codec::Encode; use futures::executor::block_on; use parking_lot::Mutex; @@ -495,9 +492,10 @@ mod tests { use sp_runtime::transaction_validity::TransactionSource; use std::{collections::HashMap, time::Instant}; use substrate_test_runtime::{AccountId, ExtrinsicBuilder, Transfer, H256}; - use substrate_test_runtime_client::AccountKeyring::{Alice, Bob}; + use substrate_test_runtime_client::Sr25519Keyring::{Alice, Bob}; - const SOURCE: TransactionSource = TransactionSource::External; + const SOURCE: TimedTransactionSource = + TimedTransactionSource { source: TransactionSource::External, timestamp: None }; #[test] fn should_validate_and_import_transaction() { @@ -545,8 +543,8 @@ mod tests { let initial_hashes = txs.iter().map(|t| api.hash_and_length(t).0).collect::>(); // when - let txs = txs.into_iter().map(|x| Arc::from(x)).collect::>(); - let hashes = block_on(pool.submit_at(&api.expect_hash_and_number(0), SOURCE, txs)); + let txs = txs.into_iter().map(|x| (SOURCE, Arc::from(x))).collect::>(); + let hashes = block_on(pool.submit_at(&api.expect_hash_and_number(0), txs)); log::debug!("--> {hashes:#?}"); // then diff --git a/substrate/client/transaction-pool/src/graph/ready.rs b/substrate/client/transaction-pool/src/graph/ready.rs index 860bcff0bace..9061d0e25581 100644 --- a/substrate/client/transaction-pool/src/graph/ready.rs +++ b/substrate/client/transaction-pool/src/graph/ready.rs @@ -589,7 +589,6 @@ fn remove_item(vec: &mut Vec, item: &T) { #[cfg(test)] mod tests { use super::*; - use sp_runtime::transaction_validity::TransactionSource as Source; fn tx(id: u8) -> Transaction> { Transaction { @@ -601,7 +600,7 @@ mod tests { requires: vec![vec![1], vec![2]], provides: vec![vec![3], vec![4]], propagate: true, - source: Source::External, + source: crate::TimedTransactionSource::new_external(false), } } @@ -711,7 +710,7 @@ mod tests { requires: vec![tx1.provides[0].clone()], provides: vec![], propagate: true, - source: Source::External, + source: crate::TimedTransactionSource::new_external(false), }; // when diff --git a/substrate/client/transaction-pool/src/graph/rotator.rs b/substrate/client/transaction-pool/src/graph/rotator.rs index 61a26fb4138c..9a2e269b5eed 100644 --- a/substrate/client/transaction-pool/src/graph/rotator.rs +++ b/substrate/client/transaction-pool/src/graph/rotator.rs @@ -106,7 +106,6 @@ impl PoolRotator { #[cfg(test)] mod tests { use super::*; - use sp_runtime::transaction_validity::TransactionSource; type Hash = u64; type Ex = (); @@ -126,7 +125,7 @@ mod tests { requires: vec![], provides: vec![], propagate: true, - source: TransactionSource::External, + source: crate::TimedTransactionSource::new_external(false), }; (hash, tx) @@ -192,7 +191,7 @@ mod tests { requires: vec![], provides: vec![], propagate: true, - source: TransactionSource::External, + source: crate::TimedTransactionSource::new_external(false), } } diff --git a/substrate/client/transaction-pool/src/graph/tracked_map.rs b/substrate/client/transaction-pool/src/graph/tracked_map.rs index 9e92dffc9f96..6c3bbbf34b55 100644 --- a/substrate/client/transaction-pool/src/graph/tracked_map.rs +++ b/substrate/client/transaction-pool/src/graph/tracked_map.rs @@ -18,7 +18,7 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::{ - collections::HashMap, + collections::{hash_map::Iter, HashMap}, sync::{ atomic::{AtomicIsize, Ordering as AtomicOrdering}, Arc, @@ -101,20 +101,30 @@ impl<'a, K, V> TrackedMapReadAccess<'a, K, V> where K: Eq + std::hash::Hash, { - /// Returns true if map contains key. + /// Returns true if the map contains given key. pub fn contains_key(&self, key: &K) -> bool { self.inner_guard.contains_key(key) } - /// Returns reference to the contained value by key, if exists. + /// Returns the reference to the contained value by key, if exists. pub fn get(&self, key: &K) -> Option<&V> { self.inner_guard.get(key) } - /// Returns iterator over all values. + /// Returns an iterator over all values. pub fn values(&self) -> std::collections::hash_map::Values { self.inner_guard.values() } + + /// Returns the number of elements in the map. + pub fn len(&self) -> usize { + self.inner_guard.len() + } + + /// Returns an iterator over all key-value pairs. + pub fn iter(&self) -> Iter<'_, K, V> { + self.inner_guard.iter() + } } pub struct TrackedMapWriteAccess<'a, K, V> { @@ -149,10 +159,20 @@ where val } + /// Returns `true` if the inner map contains a value for the specified key. + pub fn contains_key(&self, key: &K) -> bool { + self.inner_guard.contains_key(key) + } + /// Returns mutable reference to the contained value by key, if exists. pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { self.inner_guard.get_mut(key) } + + /// Returns the number of elements in the map. + pub fn len(&mut self) -> usize { + self.inner_guard.len() + } } #[cfg(test)] diff --git a/substrate/client/transaction-pool/src/graph/validated_pool.rs b/substrate/client/transaction-pool/src/graph/validated_pool.rs index d7f55198a40a..14df63d9673e 100644 --- a/substrate/client/transaction-pool/src/graph/validated_pool.rs +++ b/substrate/client/transaction-pool/src/graph/validated_pool.rs @@ -30,7 +30,7 @@ use serde::Serialize; use sp_blockchain::HashAndNumber; use sp_runtime::{ traits::{self, SaturatedConversion}, - transaction_validity::{TransactionSource, TransactionTag as Tag, ValidTransaction}, + transaction_validity::{TransactionTag as Tag, ValidTransaction}, }; use std::time::Instant; @@ -62,7 +62,7 @@ impl ValidatedTransaction { pub fn valid_at( at: u64, hash: Hash, - source: TransactionSource, + source: base::TimedTransactionSource, data: Ex, bytes: usize, validity: ValidTransaction, @@ -280,7 +280,7 @@ impl ValidatedPool { // run notifications let mut listener = self.listener.write(); for h in &removed { - listener.dropped(h, None, true); + listener.limit_enforced(h); } removed @@ -453,7 +453,7 @@ impl ValidatedPool { match final_status { Status::Future => listener.future(&hash), Status::Ready => listener.ready(&hash, None), - Status::Dropped => listener.dropped(&hash, None, false), + Status::Dropped => listener.dropped(&hash), Status::Failed => listener.invalid(&hash), } } @@ -492,7 +492,7 @@ impl ValidatedPool { fire_events(&mut *listener, promoted); } for f in &status.failed { - listener.dropped(f, None, false); + listener.dropped(f); } } @@ -671,6 +671,21 @@ impl ValidatedPool { ) -> super::listener::DroppedByLimitsStream, BlockHash> { self.listener.write().create_dropped_by_limits_stream() } + + /// Resends ready and future events for all the ready and future transactions that are already + /// in the pool. + /// + /// Intended to be called after cloning the instance of `ValidatedPool`. + pub fn retrigger_notifications(&self) { + let pool = self.pool.read(); + let mut listener = self.listener.write(); + pool.ready().for_each(|r| { + listener.ready(&r.hash, None); + }); + pool.futures().for_each(|f| { + listener.future(&f.hash); + }); + } } fn fire_events(listener: &mut Listener, imported: &base::Imported) @@ -682,7 +697,7 @@ where base::Imported::Ready { ref promoted, ref failed, ref removed, ref hash } => { listener.ready(hash, None); failed.iter().for_each(|f| listener.invalid(f)); - removed.iter().for_each(|r| listener.dropped(&r.hash, Some(hash), false)); + removed.iter().for_each(|r| listener.usurped(&r.hash, hash)); promoted.iter().for_each(|p| listener.ready(p, None)); }, base::Imported::Future { ref hash } => listener.future(hash), diff --git a/substrate/client/transaction-pool/src/graph/watcher.rs b/substrate/client/transaction-pool/src/graph/watcher.rs index fb7cf99d4dc6..2fd31e772fd8 100644 --- a/substrate/client/transaction-pool/src/graph/watcher.rs +++ b/substrate/client/transaction-pool/src/graph/watcher.rs @@ -113,6 +113,12 @@ impl Sender { } /// Transaction has been dropped from the pool because of the limit. + pub fn limit_enforced(&mut self) { + self.send(TransactionStatus::Dropped); + self.is_finalized = true; + } + + /// Transaction has been dropped from the pool. pub fn dropped(&mut self) { self.send(TransactionStatus::Dropped); self.is_finalized = true; diff --git a/substrate/client/transaction-pool/src/lib.rs b/substrate/client/transaction-pool/src/lib.rs index 888d25d3a0d2..366d91a973d2 100644 --- a/substrate/client/transaction-pool/src/lib.rs +++ b/substrate/client/transaction-pool/src/lib.rs @@ -30,13 +30,16 @@ mod single_state_txpool; mod transaction_pool_wrapper; use common::{api, enactment_state}; -use std::{future::Future, pin::Pin, sync::Arc}; +use std::sync::Arc; pub use api::FullChainApi; pub use builder::{Builder, TransactionPoolHandle, TransactionPoolOptions, TransactionPoolType}; pub use common::notification_future; pub use fork_aware_txpool::{ForkAwareTxPool, ForkAwareTxPoolTask}; -pub use graph::{base_pool::Limit as PoolLimit, ChainApi, Options, Pool}; +pub use graph::{ + base_pool::{Limit as PoolLimit, TimedTransactionSource}, + ChainApi, Options, Pool, +}; use single_state_txpool::prune_known_txs_for_block; pub use single_state_txpool::{BasicPool, RevalidationType}; pub use transaction_pool_wrapper::TransactionPoolWrapper; @@ -50,8 +53,6 @@ type BoxedReadyIterator = Box< type ReadyIteratorFor = BoxedReadyIterator, graph::ExtrinsicFor>; -type PolledIterator = Pin> + Send>>; - /// Log target for transaction pool. /// /// It can be used by other components for logging functionality strictly related to txpool (e.g. diff --git a/substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs b/substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs index 5ef726c9f7d3..f22fa2ddabde 100644 --- a/substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs +++ b/substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs @@ -88,7 +88,7 @@ async fn batch_revalidate( let validation_results = futures::future::join_all(batch.into_iter().filter_map(|ext_hash| { pool.validated_pool().ready_by_hash(&ext_hash).map(|ext| { - api.validate_transaction(at, ext.source, ext.data.clone()) + api.validate_transaction(at, ext.source.clone().into(), ext.data.clone()) .map(move |validation_result| (validation_result, ext_hash, ext)) }) })) @@ -121,7 +121,7 @@ async fn batch_revalidate( ValidatedTransaction::valid_at( block_number.saturated_into::(), ext_hash, - ext.source, + ext.source.clone(), ext.data.clone(), api.hash_and_length(&ext.data).1, validity, @@ -375,11 +375,11 @@ mod tests { use crate::{ common::tests::{uxt, TestApi}, graph::Pool, + TimedTransactionSource, }; use futures::executor::block_on; - use sc_transaction_pool_api::TransactionSource; use substrate_test_runtime::{AccountId, Transfer, H256}; - use substrate_test_runtime_client::AccountKeyring::{Alice, Bob}; + use substrate_test_runtime_client::Sr25519Keyring::{Alice, Bob}; #[test] fn revalidation_queue_works() { @@ -398,7 +398,7 @@ mod tests { let uxt_hash = block_on(pool.submit_one( &han_of_block0, - TransactionSource::External, + TimedTransactionSource::new_external(false), uxt.clone().into(), )) .expect("Should be valid"); @@ -433,14 +433,15 @@ mod tests { let han_of_block0 = api.expect_hash_and_number(0); let unknown_block = H256::repeat_byte(0x13); - let uxt_hashes = block_on(pool.submit_at( - &han_of_block0, - TransactionSource::External, - vec![uxt0.into(), uxt1.into()], - )) - .into_iter() - .map(|r| r.expect("Should be valid")) - .collect::>(); + let source = TimedTransactionSource::new_external(false); + let uxt_hashes = + block_on(pool.submit_at( + &han_of_block0, + vec![(source.clone(), uxt0.into()), (source, uxt1.into())], + )) + .into_iter() + .map(|r| r.expect("Should be valid")) + .collect::>(); assert_eq!(api.validation_requests().len(), 2); assert_eq!(pool.validated_pool().status().ready, 2); diff --git a/substrate/client/transaction-pool/src/single_state_txpool/single_state_txpool.rs b/substrate/client/transaction-pool/src/single_state_txpool/single_state_txpool.rs index 0826b95cf070..e7504012ca67 100644 --- a/substrate/client/transaction-pool/src/single_state_txpool/single_state_txpool.rs +++ b/substrate/client/transaction-pool/src/single_state_txpool/single_state_txpool.rs @@ -29,9 +29,8 @@ use crate::{ error, log_xt::log_xt_trace, }, - graph, - graph::{ExtrinsicHash, IsValidator}, - PolledIterator, ReadyIteratorFor, LOG_TARGET, + graph::{self, base_pool::TimedTransactionSource, ExtrinsicHash, IsValidator}, + ReadyIteratorFor, LOG_TARGET, }; use async_trait::async_trait; use futures::{channel::oneshot, future, prelude::*, Future, FutureExt}; @@ -39,8 +38,8 @@ use parking_lot::Mutex; use prometheus_endpoint::Registry as PrometheusRegistry; use sc_transaction_pool_api::{ error::Error as TxPoolError, ChainEvent, ImportNotificationStream, MaintainedTransactionPool, - PoolFuture, PoolStatus, TransactionFor, TransactionPool, TransactionSource, - TransactionStatusStreamFor, TxHash, + PoolStatus, TransactionFor, TransactionPool, TransactionSource, TransactionStatusStreamFor, + TxHash, }; use sp_blockchain::{HashAndNumber, TreeRoute}; use sp_core::traits::SpawnEssentialNamed; @@ -224,26 +223,19 @@ where &self.api } - fn ready_at_with_timeout_internal( + async fn ready_at_with_timeout_internal( &self, at: Block::Hash, timeout: std::time::Duration, - ) -> PolledIterator { - let timeout = futures_timer::Delay::new(timeout); - let ready_maintained = self.ready_at(at); - let ready_current = self.ready(); - - let ready = async { - select! { - ready = ready_maintained => ready, - _ = timeout => ready_current - } - }; - - Box::pin(ready) + ) -> ReadyIteratorFor { + select! { + ready = self.ready_at(at)=> ready, + _ = futures_timer::Delay::new(timeout)=> self.ready() + } } } +#[async_trait] impl TransactionPool for BasicPool where Block: BlockT, @@ -255,51 +247,51 @@ where graph::base_pool::Transaction, graph::ExtrinsicFor>; type Error = PoolApi::Error; - fn submit_at( + async fn submit_at( &self, at: ::Hash, source: TransactionSource, xts: Vec>, - ) -> PoolFuture, Self::Error>>, Self::Error> { + ) -> Result, Self::Error>>, Self::Error> { let pool = self.pool.clone(); - let xts = xts.into_iter().map(Arc::from).collect::>(); + let xts = xts + .into_iter() + .map(|xt| { + (TimedTransactionSource::from_transaction_source(source, false), Arc::from(xt)) + }) + .collect::>(); self.metrics .report(|metrics| metrics.submitted_transactions.inc_by(xts.len() as u64)); let number = self.api.resolve_block_number(at); - async move { - let at = HashAndNumber { hash: at, number: number? }; - Ok(pool.submit_at(&at, source, xts).await) - } - .boxed() + let at = HashAndNumber { hash: at, number: number? }; + Ok(pool.submit_at(&at, xts).await) } - fn submit_one( + async fn submit_one( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture, Self::Error> { + ) -> Result, Self::Error> { let pool = self.pool.clone(); let xt = Arc::from(xt); self.metrics.report(|metrics| metrics.submitted_transactions.inc()); let number = self.api.resolve_block_number(at); - async move { - let at = HashAndNumber { hash: at, number: number? }; - pool.submit_one(&at, source, xt).await - } - .boxed() + let at = HashAndNumber { hash: at, number: number? }; + pool.submit_one(&at, TimedTransactionSource::from_transaction_source(source, false), xt) + .await } - fn submit_and_watch( + async fn submit_and_watch( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture>>, Self::Error> { + ) -> Result>>, Self::Error> { let pool = self.pool.clone(); let xt = Arc::from(xt); @@ -307,13 +299,16 @@ where let number = self.api.resolve_block_number(at); - async move { - let at = HashAndNumber { hash: at, number: number? }; - let watcher = pool.submit_and_watch(&at, source, xt).await?; + let at = HashAndNumber { hash: at, number: number? }; + let watcher = pool + .submit_and_watch( + &at, + TimedTransactionSource::from_transaction_source(source, false), + xt, + ) + .await?; - Ok(watcher.into_stream().boxed()) - } - .boxed() + Ok(watcher.into_stream().boxed()) } fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { @@ -343,9 +338,9 @@ where self.pool.validated_pool().ready_by_hash(hash) } - fn ready_at(&self, at: ::Hash) -> PolledIterator { + async fn ready_at(&self, at: ::Hash) -> ReadyIteratorFor { let Ok(at) = self.api.resolve_block_number(at) else { - return async { Box::new(std::iter::empty()) as Box<_> }.boxed() + return Box::new(std::iter::empty()) as Box<_> }; let status = self.status(); @@ -354,25 +349,23 @@ where // There could be transaction being added because of some re-org happening at the relevant // block, but this is relative unlikely. if status.ready == 0 && status.future == 0 { - return async { Box::new(std::iter::empty()) as Box<_> }.boxed() + return Box::new(std::iter::empty()) as Box<_> } if self.ready_poll.lock().updated_at() >= at { log::trace!(target: LOG_TARGET, "Transaction pool already processed block #{}", at); let iterator: ReadyIteratorFor = Box::new(self.pool.validated_pool().ready()); - return async move { iterator }.boxed() + return iterator } - self.ready_poll - .lock() - .add(at) - .map(|received| { - received.unwrap_or_else(|e| { - log::warn!(target: LOG_TARGET, "Error receiving pending set: {:?}", e); - Box::new(std::iter::empty()) - }) + let result = self.ready_poll.lock().add(at).map(|received| { + received.unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Error receiving pending set: {:?}", e); + Box::new(std::iter::empty()) }) - .boxed() + }); + + result.await } fn ready(&self) -> ReadyIteratorFor { @@ -384,12 +377,12 @@ where pool.futures().cloned().collect::>() } - fn ready_at_with_timeout( + async fn ready_at_with_timeout( &self, at: ::Hash, timeout: std::time::Duration, - ) -> PolledIterator { - self.ready_at_with_timeout_internal(at, timeout) + ) -> ReadyIteratorFor { + self.ready_at_with_timeout_internal(at, timeout).await } } @@ -477,7 +470,7 @@ where let validated = ValidatedTransaction::valid_at( block_number.saturated_into::(), hash, - TransactionSource::Local, + TimedTransactionSource::new_local(false), Arc::from(xt), bytes, validity, @@ -681,8 +674,8 @@ where resubmit_transactions.extend( //todo: arctx - we need to get ref from somewhere - block_transactions.into_iter().map(Arc::from).filter(|tx| { - let tx_hash = pool.hash_of(tx); + block_transactions.into_iter().map(Arc::from).filter_map(|tx| { + let tx_hash = pool.hash_of(&tx); let contains = pruned_log.contains(&tx_hash); // need to count all transactions, not just filtered, here @@ -695,8 +688,15 @@ where tx_hash, hash, ); + Some(( + // These transactions are coming from retracted blocks, we should + // simply consider them external. + TimedTransactionSource::new_external(false), + tx, + )) + } else { + None } - !contains }), ); @@ -705,14 +705,7 @@ where }); } - pool.resubmit_at( - &hash_and_number, - // These transactions are coming from retracted blocks, we should - // simply consider them external. - TransactionSource::External, - resubmit_transactions, - ) - .await; + pool.resubmit_at(&hash_and_number, resubmit_transactions).await; } let extra_pool = pool.clone(); diff --git a/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs b/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs index 4e1b53833b8f..e373c0278d80 100644 --- a/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs +++ b/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs @@ -22,16 +22,16 @@ use crate::{ builder::FullClientTransactionPool, graph::{base_pool::Transaction, ExtrinsicFor, ExtrinsicHash}, - ChainApi, FullChainApi, + ChainApi, FullChainApi, ReadyIteratorFor, }; use async_trait::async_trait; use sc_transaction_pool_api::{ ChainEvent, ImportNotificationStream, LocalTransactionFor, LocalTransactionPool, - MaintainedTransactionPool, PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, - TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, + MaintainedTransactionPool, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, + TransactionSource, TransactionStatusStreamFor, TxHash, }; use sp_runtime::traits::Block as BlockT; -use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc}; +use std::{collections::HashMap, pin::Pin, sync::Arc}; /// The wrapper for actual object providing implementation of TransactionPool. /// @@ -49,6 +49,7 @@ where + 'static, Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue; +#[async_trait] impl TransactionPool for TransactionPoolWrapper where Block: BlockT, @@ -68,44 +69,38 @@ where >; type Error = as ChainApi>::Error; - fn submit_at( + async fn submit_at( &self, at: ::Hash, source: TransactionSource, xts: Vec>, - ) -> PoolFuture, Self::Error>>, Self::Error> { - self.0.submit_at(at, source, xts) + ) -> Result, Self::Error>>, Self::Error> { + self.0.submit_at(at, source, xts).await } - fn submit_one( + async fn submit_one( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture, Self::Error> { - self.0.submit_one(at, source, xt) + ) -> Result, Self::Error> { + self.0.submit_one(at, source, xt).await } - fn submit_and_watch( + async fn submit_and_watch( &self, at: ::Hash, source: TransactionSource, xt: TransactionFor, - ) -> PoolFuture>>, Self::Error> { - self.0.submit_and_watch(at, source, xt) + ) -> Result>>, Self::Error> { + self.0.submit_and_watch(at, source, xt).await } - fn ready_at( + async fn ready_at( &self, at: ::Hash, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send, - >, - > { - self.0.ready_at(at) + ) -> ReadyIteratorFor> { + self.0.ready_at(at).await } fn ready(&self) -> Box> + Send> { @@ -140,19 +135,12 @@ where self.0.ready_transaction(hash) } - fn ready_at_with_timeout( + async fn ready_at_with_timeout( &self, at: ::Hash, timeout: std::time::Duration, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send - + '_, - >, - > { - self.0.ready_at_with_timeout(at, timeout) + ) -> ReadyIteratorFor> { + self.0.ready_at_with_timeout(at, timeout).await } } diff --git a/substrate/client/transaction-pool/tests/fatp.rs b/substrate/client/transaction-pool/tests/fatp.rs index 9f343a9bd029..8bf08122995c 100644 --- a/substrate/client/transaction-pool/tests/fatp.rs +++ b/substrate/client/transaction-pool/tests/fatp.rs @@ -30,7 +30,7 @@ use sc_transaction_pool_api::{ }; use sp_runtime::transaction_validity::InvalidTransaction; use std::{sync::Arc, time::Duration}; -use substrate_test_runtime_client::AccountKeyring::*; +use substrate_test_runtime_client::Sr25519Keyring::*; use substrate_test_runtime_transaction_pool::uxt; pub mod fatp_common; @@ -2267,19 +2267,13 @@ fn fatp_avoid_stuck_transaction() { assert_pool_status!(header06.hash(), &pool, 0, 0); - // Import enough blocks to make xt4i revalidated - let mut prev_header = header03; - // wait 10 blocks for revalidation - for n in 7..=11 { - let header = api.push_block(n, vec![], true); - let event = finalized_block_event(&pool, prev_header.hash(), header.hash()); - block_on(pool.maintain(event)); - prev_header = header; - } + let header07 = api.push_block(7, vec![], true); + let event = finalized_block_event(&pool, header03.hash(), header07.hash()); + block_on(pool.maintain(event)); let xt4i_events = futures::executor::block_on_stream(xt4i_watcher).collect::>(); log::debug!("xt4i_events: {:#?}", xt4i_events); - assert_eq!(xt4i_events, vec![TransactionStatus::Future, TransactionStatus::Invalid]); + assert_eq!(xt4i_events, vec![TransactionStatus::Future, TransactionStatus::Dropped]); assert_eq!(pool.mempool_len(), (0, 0)); } diff --git a/substrate/client/transaction-pool/tests/fatp_common/mod.rs b/substrate/client/transaction-pool/tests/fatp_common/mod.rs index 63af729b8b73..aaffebc0db0a 100644 --- a/substrate/client/transaction-pool/tests/fatp_common/mod.rs +++ b/substrate/client/transaction-pool/tests/fatp_common/mod.rs @@ -24,7 +24,7 @@ use sp_runtime::transaction_validity::TransactionSource; use std::sync::Arc; use substrate_test_runtime_client::{ runtime::{Block, Hash, Header}, - AccountKeyring::*, + Sr25519Keyring::*, }; use substrate_test_runtime_transaction_pool::{uxt, TestApi}; pub const LOG_TARGET: &str = "txpool"; @@ -186,9 +186,9 @@ macro_rules! assert_pool_status { #[macro_export] macro_rules! assert_ready_iterator { - ($hash:expr, $pool:expr, [$( $xt:expr ),+]) => {{ + ($hash:expr, $pool:expr, [$( $xt:expr ),*]) => {{ let ready_iterator = $pool.ready_at($hash).now_or_never().unwrap(); - let expected = vec![ $($pool.api().hash_and_length(&$xt).0),+]; + let expected = vec![ $($pool.api().hash_and_length(&$xt).0),*]; let output: Vec<_> = ready_iterator.collect(); log::debug!(target:LOG_TARGET, "expected: {:#?}", expected); log::debug!(target:LOG_TARGET, "output: {:#?}", output); @@ -201,6 +201,20 @@ macro_rules! assert_ready_iterator { }}; } +#[macro_export] +macro_rules! assert_future_iterator { + ($hash:expr, $pool:expr, [$( $xt:expr ),*]) => {{ + let futures = $pool.futures_at($hash).unwrap(); + let expected = vec![ $($pool.api().hash_and_length(&$xt).0),*]; + log::debug!(target:LOG_TARGET, "expected: {:#?}", futures); + log::debug!(target:LOG_TARGET, "output: {:#?}", expected); + assert_eq!(expected.len(), futures.len()); + let hsf = futures.iter().map(|a| a.hash).collect::>(); + let hse = expected.into_iter().collect::>(); + assert_eq!(hse,hsf); + }}; +} + pub const SOURCE: TransactionSource = TransactionSource::External; #[cfg(test)] diff --git a/substrate/client/transaction-pool/tests/fatp_limits.rs b/substrate/client/transaction-pool/tests/fatp_limits.rs index 6fd5f93ed070..fb02b21ebc2b 100644 --- a/substrate/client/transaction-pool/tests/fatp_limits.rs +++ b/substrate/client/transaction-pool/tests/fatp_limits.rs @@ -19,6 +19,7 @@ //! Tests of limits for fork-aware transaction pool. pub mod fatp_common; + use fatp_common::{ finalized_block_event, invalid_hash, new_best_block_event, TestPoolBuilder, LOG_TARGET, SOURCE, }; @@ -27,7 +28,8 @@ use sc_transaction_pool::ChainApi; use sc_transaction_pool_api::{ error::Error as TxPoolError, MaintainedTransactionPool, TransactionPool, TransactionStatus, }; -use substrate_test_runtime_client::AccountKeyring::*; +use std::thread::sleep; +use substrate_test_runtime_client::Sr25519Keyring::*; use substrate_test_runtime_transaction_pool::uxt; #[test] @@ -92,25 +94,103 @@ fn fatp_limits_ready_count_works() { //charlie was not included into view: assert_pool_status!(header01.hash(), &pool, 2, 0); assert_ready_iterator!(header01.hash(), pool, [xt1, xt2]); + //todo: can we do better? We don't have API to check if event was processed internally. + let mut counter = 0; + while pool.mempool_len().0 == 3 { + sleep(std::time::Duration::from_millis(1)); + counter = counter + 1; + if counter > 20 { + assert!(false, "timeout"); + } + } + assert_eq!(pool.mempool_len().0, 2); //branch with alice transactions: let header02b = api.push_block(2, vec![xt1.clone(), xt2.clone()], true); let event = new_best_block_event(&pool, Some(header01.hash()), header02b.hash()); block_on(pool.maintain(event)); - assert_eq!(pool.mempool_len().0, 3); - //charlie was resubmitted from mmepool into the view: - assert_pool_status!(header02b.hash(), &pool, 1, 0); - assert_ready_iterator!(header02b.hash(), pool, [xt0]); + assert_eq!(pool.mempool_len().0, 2); + assert_pool_status!(header02b.hash(), &pool, 0, 0); + assert_ready_iterator!(header02b.hash(), pool, []); //branch with alice/charlie transactions shall also work: let header02a = api.push_block(2, vec![xt0.clone(), xt1.clone()], true); + api.set_nonce(header02a.hash(), Alice.into(), 201); let event = new_best_block_event(&pool, Some(header02b.hash()), header02a.hash()); block_on(pool.maintain(event)); - assert_eq!(pool.mempool_len().0, 3); - assert_pool_status!(header02a.hash(), &pool, 1, 0); + assert_eq!(pool.mempool_len().0, 2); + // assert_pool_status!(header02a.hash(), &pool, 1, 0); assert_ready_iterator!(header02a.hash(), pool, [xt2]); } +#[test] +fn fatp_limits_ready_count_works_for_submit_at() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(2).build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 500); + + let header01 = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Charlie, 500); + let xt1 = uxt(Alice, 200); + let xt2 = uxt(Alice, 201); + + let results = block_on(pool.submit_at( + header01.hash(), + SOURCE, + vec![xt0.clone(), xt1.clone(), xt2.clone()], + )) + .unwrap(); + + assert!(matches!(results[0].as_ref().unwrap_err().0, TxPoolError::ImmediatelyDropped)); + assert!(results[1].as_ref().is_ok()); + assert!(results[2].as_ref().is_ok()); + assert_eq!(pool.mempool_len().0, 2); + //charlie was not included into view: + assert_pool_status!(header01.hash(), &pool, 2, 0); + assert_ready_iterator!(header01.hash(), pool, [xt1, xt2]); +} + +#[test] +fn fatp_limits_ready_count_works_for_submit_and_watch() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(2).build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 300); + api.set_nonce(api.genesis_hash(), Charlie.into(), 500); + + let header01 = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Charlie, 500); + let xt1 = uxt(Alice, 200); + let xt2 = uxt(Bob, 300); + api.set_priority(&xt0, 2); + api.set_priority(&xt1, 2); + api.set_priority(&xt2, 1); + + let result0 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())); + let result1 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())); + let result2 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).map(|_| ()); + + assert!(matches!(result2.unwrap_err().0, TxPoolError::ImmediatelyDropped)); + assert!(result0.is_ok()); + assert!(result1.is_ok()); + assert_eq!(pool.mempool_len().1, 2); + //charlie was not included into view: + assert_pool_status!(header01.hash(), &pool, 2, 0); + assert_ready_iterator!(header01.hash(), pool, [xt0, xt1]); +} + #[test] fn fatp_limits_future_count_works() { sp_tracing::try_init_simple(); @@ -131,29 +211,33 @@ fn fatp_limits_future_count_works() { let xt2 = uxt(Alice, 201); let xt3 = uxt(Alice, 202); - let submissions = vec![ - pool.submit_one(header01.hash(), SOURCE, xt1.clone()), - pool.submit_one(header01.hash(), SOURCE, xt2.clone()), - pool.submit_one(header01.hash(), SOURCE, xt3.clone()), - ]; + block_on(pool.submit_one(header01.hash(), SOURCE, xt1.clone())).unwrap(); + block_on(pool.submit_one(header01.hash(), SOURCE, xt2.clone())).unwrap(); + block_on(pool.submit_one(header01.hash(), SOURCE, xt3.clone())).unwrap(); - let results = block_on(futures::future::join_all(submissions)); - assert!(results.iter().all(Result::is_ok)); //charlie was not included into view due to limits: assert_pool_status!(header01.hash(), &pool, 0, 2); + //todo: can we do better? We don't have API to check if event was processed internally. + let mut counter = 0; + while pool.mempool_len().0 != 2 { + sleep(std::time::Duration::from_millis(1)); + counter = counter + 1; + if counter > 20 { + assert!(false, "timeout"); + } + } let header02 = api.push_block(2, vec![xt0], true); api.set_nonce(header02.hash(), Alice.into(), 201); //redundant let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); block_on(pool.maintain(event)); - //charlie was resubmitted from mmepool into the view: - assert_pool_status!(header02.hash(), &pool, 2, 1); - assert_eq!(pool.mempool_len().0, 3); + assert_pool_status!(header02.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().0, 2); } #[test] -fn fatp_limits_watcher_mempool_prevents_dropping() { +fn fatp_limits_watcher_mempool_doesnt_prevent_dropping() { sp_tracing::try_init_simple(); let builder = TestPoolBuilder::new(); @@ -169,23 +253,15 @@ fn fatp_limits_watcher_mempool_prevents_dropping() { let xt1 = uxt(Bob, 300); let xt2 = uxt(Alice, 200); - let submissions = vec![ - pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone()), - ]; - let mut submissions = block_on(futures::future::join_all(submissions)); - let xt2_watcher = submissions.remove(2).unwrap(); - let xt1_watcher = submissions.remove(1).unwrap(); - let xt0_watcher = submissions.remove(0).unwrap(); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); assert_pool_status!(header01.hash(), &pool, 2, 0); - let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(1).collect::>(); - + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); log::debug!("xt0_status: {:#?}", xt0_status); - - assert_eq!(xt0_status, vec![TransactionStatus::Ready]); + assert_eq!(xt0_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(1).collect::>(); assert_eq!(xt1_status, vec![TransactionStatus::Ready]); @@ -214,28 +290,23 @@ fn fatp_limits_watcher_non_intial_view_drops_transaction() { let xt1 = uxt(Charlie, 400); let xt2 = uxt(Bob, 300); - let submissions = vec![ - pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone()), - ]; - let mut submissions = block_on(futures::future::join_all(submissions)); - let xt2_watcher = submissions.remove(2).unwrap(); - let xt1_watcher = submissions.remove(1).unwrap(); - let xt0_watcher = submissions.remove(0).unwrap(); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + + // make sure tx0 is actually dropped before checking iterator + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!(xt0_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); assert_ready_iterator!(header01.hash(), pool, [xt1, xt2]); let header02 = api.push_block_with_parent(header01.hash(), vec![], true); block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02.hash()))); assert_pool_status!(header02.hash(), &pool, 2, 0); - assert_ready_iterator!(header02.hash(), pool, [xt2, xt0]); - - let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(1).collect::>(); - assert_eq!(xt0_status, vec![TransactionStatus::Ready]); + assert_ready_iterator!(header02.hash(), pool, [xt1, xt2]); - let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); - assert_eq!(xt1_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(1).collect::>(); + assert_eq!(xt1_status, vec![TransactionStatus::Ready]); let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(1).collect::>(); assert_eq!(xt2_status, vec![TransactionStatus::Ready]); @@ -259,32 +330,19 @@ fn fatp_limits_watcher_finalized_transaction_frees_ready_space() { let xt1 = uxt(Charlie, 400); let xt2 = uxt(Bob, 300); - let submissions = vec![ - pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone()), - ]; - let mut submissions = block_on(futures::future::join_all(submissions)); - let xt2_watcher = submissions.remove(2).unwrap(); - let xt1_watcher = submissions.remove(1).unwrap(); - let xt0_watcher = submissions.remove(0).unwrap(); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); assert_ready_iterator!(header01.hash(), pool, [xt1, xt2]); + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!(xt0_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); + let header02 = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02.hash()))); assert_pool_status!(header02.hash(), &pool, 2, 0); assert_ready_iterator!(header02.hash(), pool, [xt1, xt2]); - let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(3).collect::>(); - assert_eq!( - xt0_status, - vec![ - TransactionStatus::Ready, - TransactionStatus::InBlock((header02.hash(), 0)), - TransactionStatus::Finalized((header02.hash(), 0)) - ] - ); - let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(1).collect::>(); assert_eq!(xt1_status, vec![TransactionStatus::Ready]); @@ -311,43 +369,464 @@ fn fatp_limits_watcher_view_can_drop_transcation() { let xt2 = uxt(Bob, 300); let xt3 = uxt(Alice, 200); - let submissions = vec![ - pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone()), - pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone()), - ]; - let mut submissions = block_on(futures::future::join_all(submissions)); - let xt2_watcher = submissions.remove(2).unwrap(); - let xt1_watcher = submissions.remove(1).unwrap(); - let xt0_watcher = submissions.remove(0).unwrap(); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!(xt0_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped,]); assert_ready_iterator!(header01.hash(), pool, [xt1, xt2]); - let header02 = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); + let header02 = api.push_block_with_parent(header01.hash(), vec![], true); block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02.hash()))); - let submission = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())); - let xt3_watcher = submission.unwrap(); + let xt3_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); + assert_eq!(xt1_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); assert_pool_status!(header02.hash(), pool, 2, 0); assert_ready_iterator!(header02.hash(), pool, [xt2, xt3]); - let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(3).collect::>(); - assert_eq!( - xt0_status, - vec![ - TransactionStatus::Ready, - TransactionStatus::InBlock((header02.hash(), 0)), - TransactionStatus::Finalized((header02.hash(), 0)) - ] + let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(1).collect::>(); + assert_eq!(xt2_status, vec![TransactionStatus::Ready]); + + let xt3_status = futures::executor::block_on_stream(xt3_watcher).take(1).collect::>(); + assert_eq!(xt3_status, vec![TransactionStatus::Ready]); +} + +#[test] +fn fatp_limits_watcher_empty_and_full_view_immediately_drops() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(4).with_ready_count(2).build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 300); + api.set_nonce(api.genesis_hash(), Charlie.into(), 400); + api.set_nonce(api.genesis_hash(), Dave.into(), 500); + api.set_nonce(api.genesis_hash(), Eve.into(), 600); + api.set_nonce(api.genesis_hash(), Ferdie.into(), 700); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 300); + let xt2 = uxt(Charlie, 400); + + let xt3 = uxt(Dave, 500); + let xt4 = uxt(Eve, 600); + let xt5 = uxt(Ferdie, 700); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!(xt0_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); + + assert_pool_status!(header01.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().1, 2); + + let header02e = api.push_block_with_parent( + header01.hash(), + vec![xt0.clone(), xt1.clone(), xt2.clone()], + true, ); + api.set_nonce(header02e.hash(), Alice.into(), 201); + api.set_nonce(header02e.hash(), Bob.into(), 301); + api.set_nonce(header02e.hash(), Charlie.into(), 401); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02e.hash()))); + + assert_pool_status!(header02e.hash(), &pool, 0, 0); + + let header02f = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02f.hash()))); + assert_pool_status!(header02f.hash(), &pool, 2, 0); + assert_ready_iterator!(header02f.hash(), pool, [xt1, xt2]); + + let xt3_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + let xt4_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt4.clone())).unwrap(); + let result5 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt5.clone())).map(|_| ()); + + //xt5 hits internal mempool limit + assert!(matches!(result5.unwrap_err().0, TxPoolError::ImmediatelyDropped)); + + assert_pool_status!(header02e.hash(), &pool, 2, 0); + assert_ready_iterator!(header02e.hash(), pool, [xt3, xt4]); + assert_eq!(pool.mempool_len().1, 4); let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); - assert_eq!(xt1_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); + assert_eq!( + xt1_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header02e.hash(), 1))] + ); - let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(1).collect::>(); - assert_eq!(xt2_status, vec![TransactionStatus::Ready]); + let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(2).collect::>(); + assert_eq!( + xt2_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header02e.hash(), 2))] + ); let xt3_status = futures::executor::block_on_stream(xt3_watcher).take(1).collect::>(); assert_eq!(xt3_status, vec![TransactionStatus::Ready]); + let xt4_status = futures::executor::block_on_stream(xt4_watcher).take(1).collect::>(); + assert_eq!(xt4_status, vec![TransactionStatus::Ready]); +} + +#[test] +fn fatp_limits_watcher_empty_and_full_view_drops_with_event() { + // it is almost copy of fatp_limits_watcher_empty_and_full_view_immediately_drops, but the + // mempool_count limit is set to 5 (vs 4). + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(5).with_ready_count(2).build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 300); + api.set_nonce(api.genesis_hash(), Charlie.into(), 400); + api.set_nonce(api.genesis_hash(), Dave.into(), 500); + api.set_nonce(api.genesis_hash(), Eve.into(), 600); + api.set_nonce(api.genesis_hash(), Ferdie.into(), 700); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 300); + let xt2 = uxt(Charlie, 400); + + let xt3 = uxt(Dave, 500); + let xt4 = uxt(Eve, 600); + let xt5 = uxt(Ferdie, 700); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!(xt0_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); + + assert_pool_status!(header01.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().1, 2); + + let header02e = api.push_block_with_parent( + header01.hash(), + vec![xt0.clone(), xt1.clone(), xt2.clone()], + true, + ); + api.set_nonce(header02e.hash(), Alice.into(), 201); + api.set_nonce(header02e.hash(), Bob.into(), 301); + api.set_nonce(header02e.hash(), Charlie.into(), 401); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02e.hash()))); + + assert_pool_status!(header02e.hash(), &pool, 0, 0); + + let header02f = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02f.hash()))); + assert_pool_status!(header02f.hash(), &pool, 2, 0); + assert_ready_iterator!(header02f.hash(), pool, [xt1, xt2]); + + let xt3_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + let xt4_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt4.clone())).unwrap(); + let xt5_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt5.clone())).unwrap(); + + assert_pool_status!(header02e.hash(), &pool, 2, 0); + assert_ready_iterator!(header02e.hash(), pool, [xt4, xt5]); + + let xt3_status = futures::executor::block_on_stream(xt3_watcher).take(2).collect::>(); + assert_eq!(xt3_status, vec![TransactionStatus::Ready, TransactionStatus::Dropped]); + + //xt5 got dropped + assert_eq!(pool.mempool_len().1, 4); + + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); + assert_eq!( + xt1_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header02e.hash(), 1))] + ); + + let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(2).collect::>(); + assert_eq!( + xt2_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header02e.hash(), 2))] + ); + + let xt4_status = futures::executor::block_on_stream(xt4_watcher).take(1).collect::>(); + assert_eq!(xt4_status, vec![TransactionStatus::Ready]); + + let xt5_status = futures::executor::block_on_stream(xt5_watcher).take(1).collect::>(); + assert_eq!(xt5_status, vec![TransactionStatus::Ready]); +} + +fn large_uxt(x: usize) -> substrate_test_runtime::Extrinsic { + substrate_test_runtime::ExtrinsicBuilder::new_include_data(vec![x as u8; 1024]).build() +} + +#[test] +fn fatp_limits_ready_size_works() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_ready_bytes_size(3390).with_future_bytes_size(0).build(); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = large_uxt(0); + let xt1 = large_uxt(1); + let xt2 = large_uxt(2); + + let submissions = vec![ + pool.submit_one(header01.hash(), SOURCE, xt0.clone()), + pool.submit_one(header01.hash(), SOURCE, xt1.clone()), + pool.submit_one(header01.hash(), SOURCE, xt2.clone()), + ]; + + let results = block_on(futures::future::join_all(submissions)); + assert!(results.iter().all(Result::is_ok)); + //charlie was not included into view: + assert_pool_status!(header01.hash(), &pool, 3, 0); + assert_ready_iterator!(header01.hash(), pool, [xt0, xt1, xt2]); + + let xt3 = large_uxt(3); + let result3 = block_on(pool.submit_one(header01.hash(), SOURCE, xt3.clone())); + assert!(matches!(result3.as_ref().unwrap_err().0, TxPoolError::ImmediatelyDropped)); +} + +#[test] +fn fatp_limits_future_size_works() { + sp_tracing::try_init_simple(); + const UXT_SIZE: usize = 137; + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder + .with_ready_bytes_size(UXT_SIZE) + .with_future_bytes_size(3 * UXT_SIZE) + .build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 500); + + let header01 = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Bob, 201); + let xt1 = uxt(Charlie, 501); + let xt2 = uxt(Alice, 201); + let xt3 = uxt(Alice, 202); + assert_eq!(api.hash_and_length(&xt0).1, UXT_SIZE); + assert_eq!(api.hash_and_length(&xt1).1, UXT_SIZE); + assert_eq!(api.hash_and_length(&xt2).1, UXT_SIZE); + assert_eq!(api.hash_and_length(&xt3).1, UXT_SIZE); + + let _ = block_on(pool.submit_one(header01.hash(), SOURCE, xt0.clone())).unwrap(); + let _ = block_on(pool.submit_one(header01.hash(), SOURCE, xt1.clone())).unwrap(); + let _ = block_on(pool.submit_one(header01.hash(), SOURCE, xt2.clone())).unwrap(); + let _ = block_on(pool.submit_one(header01.hash(), SOURCE, xt3.clone())).unwrap(); + + //todo: can we do better? We don't have API to check if event was processed internally. + let mut counter = 0; + while pool.mempool_len().0 == 4 { + sleep(std::time::Duration::from_millis(1)); + counter = counter + 1; + if counter > 20 { + assert!(false, "timeout"); + } + } + assert_pool_status!(header01.hash(), &pool, 0, 3); + assert_eq!(pool.mempool_len().0, 3); +} + +#[test] +fn fatp_limits_watcher_ready_transactions_are_not_droped_when_view_is_dropped() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(6).with_ready_count(2).build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 300); + api.set_nonce(api.genesis_hash(), Charlie.into(), 400); + api.set_nonce(api.genesis_hash(), Dave.into(), 500); + api.set_nonce(api.genesis_hash(), Eve.into(), 600); + api.set_nonce(api.genesis_hash(), Ferdie.into(), 700); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 300); + let xt2 = uxt(Charlie, 400); + + let xt3 = uxt(Dave, 500); + let xt4 = uxt(Eve, 600); + let xt5 = uxt(Ferdie, 700); + + let _xt0_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let _xt1_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().1, 2); + + let header02 = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02.hash()))); + + let _xt2_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + let _xt3_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + + assert_pool_status!(header02.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().1, 4); + + let header03 = api.push_block_with_parent(header02.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header02.hash()), header03.hash()))); + + let _xt4_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt4.clone())).unwrap(); + let _xt5_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt5.clone())).unwrap(); + + assert_pool_status!(header03.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().1, 6); + + let header04 = + api.push_block_with_parent(header03.hash(), vec![xt4.clone(), xt5.clone()], true); + api.set_nonce(header04.hash(), Alice.into(), 201); + api.set_nonce(header04.hash(), Bob.into(), 301); + api.set_nonce(header04.hash(), Charlie.into(), 401); + api.set_nonce(header04.hash(), Dave.into(), 501); + api.set_nonce(header04.hash(), Eve.into(), 601); + api.set_nonce(header04.hash(), Ferdie.into(), 701); + block_on(pool.maintain(new_best_block_event(&pool, Some(header03.hash()), header04.hash()))); + + assert_ready_iterator!(header01.hash(), pool, [xt0, xt1]); + assert_ready_iterator!(header02.hash(), pool, [xt2, xt3]); + assert_ready_iterator!(header03.hash(), pool, [xt4, xt5]); + assert_ready_iterator!(header04.hash(), pool, []); + + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header01.hash()))); + assert!(!pool.status_all().contains_key(&header01.hash())); + + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header02.hash()))); + assert!(!pool.status_all().contains_key(&header02.hash())); + + //view 01 was dropped + assert!(pool.ready_at(header01.hash()).now_or_never().is_none()); + assert_eq!(pool.mempool_len().1, 6); + + block_on(pool.maintain(finalized_block_event(&pool, header02.hash(), header03.hash()))); + + //no revalidation has happened yet, all txs are kept + assert_eq!(pool.mempool_len().1, 6); + + //view 03 is still there + assert!(!pool.status_all().contains_key(&header03.hash())); + + //view 02 was dropped + assert!(pool.ready_at(header02.hash()).now_or_never().is_none()); + + let mut prev_header = header03; + for n in 5..=11 { + let header = api.push_block(n, vec![], true); + let event = finalized_block_event(&pool, prev_header.hash(), header.hash()); + block_on(pool.maintain(event)); + prev_header = header; + } + + //now revalidation has happened, all txs are dropped + assert_eq!(pool.mempool_len().1, 0); +} + +#[test] +fn fatp_limits_watcher_future_transactions_are_droped_when_view_is_dropped() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(6).with_future_count(2).build(); + api.set_nonce(api.genesis_hash(), Bob.into(), 300); + api.set_nonce(api.genesis_hash(), Charlie.into(), 400); + api.set_nonce(api.genesis_hash(), Dave.into(), 500); + api.set_nonce(api.genesis_hash(), Eve.into(), 600); + api.set_nonce(api.genesis_hash(), Ferdie.into(), 700); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 201); + let xt1 = uxt(Bob, 301); + let xt2 = uxt(Charlie, 401); + + let xt3 = uxt(Dave, 501); + let xt4 = uxt(Eve, 601); + let xt5 = uxt(Ferdie, 701); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 0, 2); + assert_eq!(pool.mempool_len().1, 2); + assert_future_iterator!(header01.hash(), pool, [xt0, xt1]); + + let header02 = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02.hash()))); + + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + let xt3_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + + assert_pool_status!(header02.hash(), &pool, 0, 2); + assert_eq!(pool.mempool_len().1, 4); + assert_future_iterator!(header02.hash(), pool, [xt2, xt3]); + + let header03 = api.push_block_with_parent(header02.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header02.hash()), header03.hash()))); + + let xt4_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt4.clone())).unwrap(); + let xt5_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt5.clone())).unwrap(); + + assert_pool_status!(header03.hash(), &pool, 0, 2); + assert_eq!(pool.mempool_len().1, 6); + assert_future_iterator!(header03.hash(), pool, [xt4, xt5]); + + let header04 = api.push_block_with_parent(header03.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header03.hash()), header04.hash()))); + + assert_pool_status!(header04.hash(), &pool, 0, 2); + assert_eq!(pool.futures().len(), 2); + assert_future_iterator!(header04.hash(), pool, [xt4, xt5]); + + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header04.hash()))); + assert_eq!(pool.active_views_count(), 1); + assert_eq!(pool.inactive_views_count(), 0); + //todo: can we do better? We don't have API to check if event was processed internally. + let mut counter = 0; + while pool.mempool_len().1 != 2 { + sleep(std::time::Duration::from_millis(1)); + counter = counter + 1; + if counter > 20 { + assert!(false, "timeout {}", pool.mempool_len().1); + } + } + assert_eq!(pool.mempool_len().1, 2); + assert_pool_status!(header04.hash(), &pool, 0, 2); + assert_eq!(pool.futures().len(), 2); + + let to_be_checked = vec![xt0_watcher, xt1_watcher, xt2_watcher, xt3_watcher]; + for x in to_be_checked { + let x_status = futures::executor::block_on_stream(x).take(2).collect::>(); + assert_eq!(x_status, vec![TransactionStatus::Future, TransactionStatus::Dropped]); + } + + let to_be_checked = vec![xt4_watcher, xt5_watcher]; + for x in to_be_checked { + let x_status = futures::executor::block_on_stream(x).take(1).collect::>(); + assert_eq!(x_status, vec![TransactionStatus::Future]); + } } diff --git a/substrate/client/transaction-pool/tests/fatp_prios.rs b/substrate/client/transaction-pool/tests/fatp_prios.rs new file mode 100644 index 000000000000..4ed9b4503861 --- /dev/null +++ b/substrate/client/transaction-pool/tests/fatp_prios.rs @@ -0,0 +1,249 @@ +// 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 . + +//! Tests of priorities for fork-aware transaction pool. + +pub mod fatp_common; + +use fatp_common::{new_best_block_event, TestPoolBuilder, LOG_TARGET, SOURCE}; +use futures::{executor::block_on, FutureExt}; +use sc_transaction_pool::ChainApi; +use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionStatus}; +use substrate_test_runtime_client::Sr25519Keyring::*; +use substrate_test_runtime_transaction_pool::uxt; + +#[test] +fn fatp_prio_ready_higher_evicts_lower() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(2).build(); + + let header01 = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 200); + + api.set_priority(&xt0, 2); + api.set_priority(&xt1, 3); + + let result0 = block_on(pool.submit_one(header01.hash(), SOURCE, xt0.clone())); + let result1 = block_on(pool.submit_one(header01.hash(), SOURCE, xt1.clone())); + + log::info!("r0 => {:?}", result0); + log::info!("r1 => {:?}", result1); + log::info!("len: {:?}", pool.mempool_len()); + log::info!("len: {:?}", pool.status_all()[&header01.hash()]); + assert_ready_iterator!(header01.hash(), pool, [xt1]); + assert_pool_status!(header01.hash(), &pool, 1, 0); +} + +#[test] +fn fatp_prio_watcher_ready_higher_evicts_lower() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(2).build(); + + let header01 = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 200); + + api.set_priority(&xt0, 2); + api.set_priority(&xt1, 3); + + let xt0_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt1.clone())).unwrap(); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!( + xt0_status, + vec![TransactionStatus::Ready, TransactionStatus::Usurped(api.hash_and_length(&xt1).0)] + ); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(1).collect::>(); + assert_eq!(xt1_status, vec![TransactionStatus::Ready]); + + log::info!("len: {:?}", pool.mempool_len()); + log::info!("len: {:?}", pool.status_all()[&header01.hash()]); + assert_ready_iterator!(header01.hash(), pool, [xt1]); + assert_pool_status!(header01.hash(), &pool, 1, 0); +} + +#[test] +fn fatp_prio_watcher_future_higher_evicts_lower() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(3).build(); + + let header01 = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 201); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Alice, 200); + + api.set_priority(&xt0, 2); + api.set_priority(&xt1, 3); + + let xt0_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt0.clone())).unwrap(); + let xt1_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt1.clone())).unwrap(); + let xt2_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt2.clone())).unwrap(); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + + assert_eq!( + xt0_status, + vec![TransactionStatus::Future, TransactionStatus::Usurped(api.hash_and_length(&xt2).0)] + ); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); + assert_eq!(xt1_status, vec![TransactionStatus::Future, TransactionStatus::Ready]); + let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(1).collect::>(); + assert_eq!(xt2_status, vec![TransactionStatus::Ready]); + + assert_eq!(pool.mempool_len().1, 2); + assert_ready_iterator!(header01.hash(), pool, [xt2, xt1]); + assert_pool_status!(header01.hash(), &pool, 2, 0); +} + +#[test] +fn fatp_prio_watcher_ready_lower_prio_gets_dropped_from_all_views() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(2).build(); + + let header01 = api.push_block(1, vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 200); + + api.set_priority(&xt0, 2); + api.set_priority(&xt1, 3); + + let xt0_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt0.clone())).unwrap(); + + let header02 = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02.hash()))); + + let header03a = api.push_block_with_parent(header02.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header03a.hash()))); + + let header03b = api.push_block_with_parent(header02.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header03a.hash()), header03b.hash()))); + + assert_pool_status!(header03a.hash(), &pool, 1, 0); + assert_ready_iterator!(header03a.hash(), pool, [xt0]); + assert_pool_status!(header03b.hash(), &pool, 1, 0); + assert_ready_iterator!(header03b.hash(), pool, [xt0]); + assert_ready_iterator!(header01.hash(), pool, [xt0]); + assert_ready_iterator!(header02.hash(), pool, [xt0]); + + let xt1_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt1.clone())).unwrap(); + + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(1).collect::>(); + assert_eq!(xt1_status, vec![TransactionStatus::Ready]); + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!( + xt0_status, + vec![TransactionStatus::Ready, TransactionStatus::Usurped(api.hash_and_length(&xt1).0)] + ); + assert_ready_iterator!(header03a.hash(), pool, [xt1]); + assert_ready_iterator!(header03b.hash(), pool, [xt1]); + assert_ready_iterator!(header01.hash(), pool, [xt1]); + assert_ready_iterator!(header02.hash(), pool, [xt1]); +} + +#[test] +fn fatp_prio_watcher_future_lower_prio_gets_dropped_from_all_views() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_ready_count(2).build(); + + let header01 = api.push_block(1, vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + + let xt0 = uxt(Alice, 201); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Alice, 200); + + api.set_priority(&xt0, 2); + api.set_priority(&xt1, 3); + + let xt0_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt0.clone())).unwrap(); + + let xt1_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt1.clone())).unwrap(); + + let header02 = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02.hash()))); + + let header03a = api.push_block_with_parent(header02.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header03a.hash()))); + + let header03b = api.push_block_with_parent(header02.hash(), vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header03a.hash()), header03b.hash()))); + + assert_pool_status!(header03a.hash(), &pool, 0, 2); + assert_future_iterator!(header03a.hash(), pool, [xt0, xt1]); + assert_pool_status!(header03b.hash(), &pool, 0, 2); + assert_future_iterator!(header03b.hash(), pool, [xt0, xt1]); + assert_future_iterator!(header01.hash(), pool, [xt0, xt1]); + assert_future_iterator!(header02.hash(), pool, [xt0, xt1]); + + let xt2_watcher = + block_on(pool.submit_and_watch(header01.hash(), SOURCE, xt2.clone())).unwrap(); + + let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(1).collect::>(); + assert_eq!(xt2_status, vec![TransactionStatus::Ready]); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(1).collect::>(); + assert_eq!(xt1_status, vec![TransactionStatus::Future]); + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + assert_eq!( + xt0_status, + vec![TransactionStatus::Future, TransactionStatus::Usurped(api.hash_and_length(&xt2).0)] + ); + assert_future_iterator!(header03a.hash(), pool, []); + assert_future_iterator!(header03b.hash(), pool, []); + assert_future_iterator!(header01.hash(), pool, []); + assert_future_iterator!(header02.hash(), pool, []); + + assert_ready_iterator!(header03a.hash(), pool, [xt2, xt1]); + assert_ready_iterator!(header03b.hash(), pool, [xt2, xt1]); + assert_ready_iterator!(header01.hash(), pool, [xt2, xt1]); + assert_ready_iterator!(header02.hash(), pool, [xt2, xt1]); +} diff --git a/substrate/client/transaction-pool/tests/pool.rs b/substrate/client/transaction-pool/tests/pool.rs index ed0fd7d4e655..20997606c607 100644 --- a/substrate/client/transaction-pool/tests/pool.rs +++ b/substrate/client/transaction-pool/tests/pool.rs @@ -40,8 +40,8 @@ use sp_runtime::{ use std::{collections::BTreeSet, pin::Pin, sync::Arc}; use substrate_test_runtime_client::{ runtime::{Block, Extrinsic, ExtrinsicBuilder, Hash, Header, Nonce, Transfer, TransferData}, - AccountKeyring::*, ClientBlockImportExt, + Sr25519Keyring::*, }; use substrate_test_runtime_transaction_pool::{uxt, TestApi}; @@ -80,12 +80,14 @@ fn create_basic_pool(test_api: TestApi) -> BasicPool { create_basic_pool_with_genesis(Arc::from(test_api)).0 } +const TSOURCE: TimedTransactionSource = + TimedTransactionSource { source: TransactionSource::External, timestamp: None }; const SOURCE: TransactionSource = TransactionSource::External; #[test] fn submission_should_work() { let (pool, api) = pool(); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 209).into())) .unwrap(); let pending: Vec<_> = pool @@ -99,9 +101,9 @@ fn submission_should_work() { #[test] fn multiple_submission_should_work() { let (pool, api) = pool(); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 209).into())) .unwrap(); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 210).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 210).into())) .unwrap(); let pending: Vec<_> = pool @@ -116,7 +118,7 @@ fn multiple_submission_should_work() { fn early_nonce_should_be_culled() { sp_tracing::try_init_simple(); let (pool, api) = pool(); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 208).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 208).into())) .unwrap(); log::debug!("-> {:?}", pool.validated_pool().status()); @@ -132,7 +134,7 @@ fn early_nonce_should_be_culled() { fn late_nonce_should_be_queued() { let (pool, api) = pool(); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 210).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 210).into())) .unwrap(); let pending: Vec<_> = pool .validated_pool() @@ -141,7 +143,7 @@ fn late_nonce_should_be_queued() { .collect(); assert_eq!(pending, Vec::::new()); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 209).into())) .unwrap(); let pending: Vec<_> = pool .validated_pool() @@ -155,9 +157,9 @@ fn late_nonce_should_be_queued() { fn prune_tags_should_work() { let (pool, api) = pool(); let hash209 = - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 209).into())) .unwrap(); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 210).into())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt(Alice, 210).into())) .unwrap(); let pending: Vec<_> = pool @@ -183,9 +185,9 @@ fn should_ban_invalid_transactions() { let (pool, api) = pool(); let uxt = Arc::from(uxt(Alice, 209)); let hash = - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.clone())).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt.clone())).unwrap(); pool.validated_pool().remove_invalid(&[hash]); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.clone())).unwrap_err(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt.clone())).unwrap_err(); // when let pending: Vec<_> = pool @@ -196,7 +198,7 @@ fn should_ban_invalid_transactions() { assert_eq!(pending, Vec::::new()); // then - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.clone())).unwrap_err(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, uxt.clone())).unwrap_err(); } #[test] @@ -224,7 +226,7 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() { })); let pool = Pool::new(Default::default(), true.into(), api.clone()); let xt0 = Arc::from(uxt(Alice, 209)); - block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, xt0.clone())) + block_on(pool.submit_one(&api.expect_hash_and_number(0), TSOURCE, xt0.clone())) .expect("1. Imported"); assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(api.validation_requests().len(), 1); @@ -242,7 +244,7 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() { api.increment_nonce(Alice.into()); api.push_block(2, Vec::new(), true); let xt1 = uxt(Alice, 211); - block_on(pool.submit_one(&api.expect_hash_and_number(2), SOURCE, xt1.clone().into())) + block_on(pool.submit_one(&api.expect_hash_and_number(2), TSOURCE, xt1.clone().into())) .expect("2. Imported"); assert_eq!(api.validation_requests().len(), 3); assert_eq!(pool.validated_pool().status().ready, 1); diff --git a/substrate/docs/Upgrading-2.0-to-3.0.md b/substrate/docs/Upgrading-2.0-to-3.0.md index 1be41a34ef34..f6fc5cf4b079 100644 --- a/substrate/docs/Upgrading-2.0-to-3.0.md +++ b/substrate/docs/Upgrading-2.0-to-3.0.md @@ -1003,7 +1003,7 @@ modified your chain you should probably try to apply these patches: }; use sp_timestamp; - use sp_finality_tracker; - use sp_keyring::AccountKeyring; + use sp_keyring::Sr25519Keyring; use sc_service_test::TestNetNode; use crate::service::{new_full_base, new_light_base, NewFullBase}; - use sp_runtime::traits::IdentifyAccount; @@ -1034,7 +1034,7 @@ modified your chain you should probably try to apply these patches: + let mut slot = 1u64; // For the extrinsics factory - let bob = Arc::new(AccountKeyring::Bob.pair()); + let bob = Arc::new(Sr25519Keyring::Bob.pair()); @@ -528,14 +539,13 @@ mod tests { Ok((node, (inherent_data_providers, setup_handles.unwrap()))) }, diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 2d0daf82997d..8fc0d8468430 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -26,28 +26,28 @@ scale-info = { features = [ ], workspace = true } # primitive deps, used for developing FRAME pallets. -sp-runtime = { workspace = true } -sp-io = { workspace = true } -sp-core = { workspace = true } sp-arithmetic = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } # frame deps, for developing FRAME pallets. frame-support = { workspace = true } frame-system = { workspace = true } # primitive types used for developing FRAME runtimes. -sp-version = { optional = true, workspace = true } sp-api = { optional = true, workspace = true } sp-block-builder = { optional = true, workspace = true } -sp-transaction-pool = { optional = true, workspace = true } -sp-offchain = { optional = true, workspace = true } -sp-session = { optional = true, workspace = true } sp-consensus-aura = { optional = true, workspace = true } sp-consensus-grandpa = { optional = true, workspace = true } sp-genesis-builder = { optional = true, workspace = true } sp-inherents = { optional = true, workspace = true } -sp-storage = { optional = true, workspace = true } sp-keyring = { optional = true, workspace = true } +sp-offchain = { optional = true, workspace = true } +sp-session = { optional = true, workspace = true } +sp-storage = { optional = true, workspace = true } +sp-transaction-pool = { optional = true, workspace = true } +sp-version = { optional = true, workspace = true } frame-executive = { optional = true, workspace = true } frame-system-rpc-runtime-api = { optional = true, workspace = true } diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index 451b86b35dde..9d21b9e964c9 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -31,14 +31,14 @@ frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -pallet-identity = { workspace = true } pallet-collective = { optional = true, workspace = true } +pallet-identity = { workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } -sp-crypto-hashing = { workspace = true } pallet-balances = { workspace = true, default-features = true } pallet-collective = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/alliance/src/weights.rs b/substrate/frame/alliance/src/weights.rs index 0184ac91107c..dff60ec20cde 100644 --- a/substrate/frame/alliance/src/weights.rs +++ b/substrate/frame/alliance/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_alliance` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -91,16 +91,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `688 + m * (32 ±0) + p * (36 ±0)` + // Measured: `721 + m * (32 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 31_545_000 picoseconds. - Weight::from_parts(33_432_774, 6676) - // Standard Error: 121 - .saturating_add(Weight::from_parts(232, 0).saturating_mul(b.into())) - // Standard Error: 1_263 - .saturating_add(Weight::from_parts(47_800, 0).saturating_mul(m.into())) - // Standard Error: 1_247 - .saturating_add(Weight::from_parts(188_655, 0).saturating_mul(p.into())) + // Minimum execution time: 36_770_000 picoseconds. + Weight::from_parts(39_685_981, 6676) + // Standard Error: 156 + .saturating_add(Weight::from_parts(588, 0).saturating_mul(b.into())) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(31_314, 0).saturating_mul(m.into())) + // Standard Error: 1_616 + .saturating_add(Weight::from_parts(158_254, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -113,12 +113,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1147 + m * (64 ±0)` + // Measured: `1180 + m * (64 ±0)` // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 30_462_000 picoseconds. - Weight::from_parts(31_639_466, 6676) - // Standard Error: 980 - .saturating_add(Weight::from_parts(60_075, 0).saturating_mul(m.into())) + // Minimum execution time: 36_851_000 picoseconds. + Weight::from_parts(38_427_277, 6676) + // Standard Error: 1_877 + .saturating_add(Weight::from_parts(50_131, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -137,14 +137,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `674 + m * (96 ±0) + p * (36 ±0)` + // Measured: `707 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 40_765_000 picoseconds. - Weight::from_parts(37_690_472, 6676) - // Standard Error: 1_372 - .saturating_add(Weight::from_parts(69_441, 0).saturating_mul(m.into())) - // Standard Error: 1_338 - .saturating_add(Weight::from_parts(152_833, 0).saturating_mul(p.into())) + // Minimum execution time: 43_572_000 picoseconds. + Weight::from_parts(40_836_679, 6676) + // Standard Error: 1_764 + .saturating_add(Weight::from_parts(59_213, 0).saturating_mul(m.into())) + // Standard Error: 1_720 + .saturating_add(Weight::from_parts(171_689, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -169,16 +169,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1254 + m * (96 ±0) + p * (39 ±0)` + // Measured: `1287 + m * (96 ±0) + p * (39 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 57_367_000 picoseconds. - Weight::from_parts(57_264_486, 6676) - // Standard Error: 141 - .saturating_add(Weight::from_parts(884, 0).saturating_mul(b.into())) - // Standard Error: 1_495 - .saturating_add(Weight::from_parts(57_869, 0).saturating_mul(m.into())) - // Standard Error: 1_458 - .saturating_add(Weight::from_parts(158_784, 0).saturating_mul(p.into())) + // Minimum execution time: 62_758_000 picoseconds. + Weight::from_parts(63_400_227, 6676) + // Standard Error: 233 + .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(b.into())) + // Standard Error: 2_470 + .saturating_add(Weight::from_parts(42_858, 0).saturating_mul(m.into())) + // Standard Error: 2_408 + .saturating_add(Weight::from_parts(185_822, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -200,14 +200,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `675 + m * (96 ±0) + p * (36 ±0)` + // Measured: `708 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 41_253_000 picoseconds. - Weight::from_parts(37_550_833, 6676) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(77_359, 0).saturating_mul(m.into())) - // Standard Error: 1_148 - .saturating_add(Weight::from_parts(153_523, 0).saturating_mul(p.into())) + // Minimum execution time: 45_287_000 picoseconds. + Weight::from_parts(44_144_056, 6676) + // Standard Error: 1_553 + .saturating_add(Weight::from_parts(50_224, 0).saturating_mul(m.into())) + // Standard Error: 1_534 + .saturating_add(Weight::from_parts(154_551, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -230,16 +230,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + m * (96 ±0) + p * (35 ±0)` + // Measured: `761 + m * (96 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 42_385_000 picoseconds. - Weight::from_parts(37_222_159, 6676) - // Standard Error: 118 - .saturating_add(Weight::from_parts(1_743, 0).saturating_mul(b.into())) - // Standard Error: 1_268 - .saturating_add(Weight::from_parts(59_743, 0).saturating_mul(m.into())) - // Standard Error: 1_222 - .saturating_add(Weight::from_parts(159_606, 0).saturating_mul(p.into())) + // Minimum execution time: 45_943_000 picoseconds. + Weight::from_parts(43_665_317, 6676) + // Standard Error: 164 + .saturating_add(Weight::from_parts(1_296, 0).saturating_mul(b.into())) + // Standard Error: 1_757 + .saturating_add(Weight::from_parts(35_145, 0).saturating_mul(m.into())) + // Standard Error: 1_694 + .saturating_add(Weight::from_parts(164_507, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -253,14 +253,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `284` + // Measured: `317` // Estimated: `12362` - // Minimum execution time: 31_184_000 picoseconds. - Weight::from_parts(22_860_208, 12362) - // Standard Error: 1_096 - .saturating_add(Weight::from_parts(129_834, 0).saturating_mul(m.into())) - // Standard Error: 1_083 - .saturating_add(Weight::from_parts(97_546, 0).saturating_mul(z.into())) + // Minimum execution time: 34_959_000 picoseconds. + Weight::from_parts(25_620_911, 12362) + // Standard Error: 1_457 + .saturating_add(Weight::from_parts(130_068, 0).saturating_mul(m.into())) + // Standard Error: 1_440 + .saturating_add(Weight::from_parts(113_433, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -281,16 +281,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` + // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (252 ±0)` // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 359_308_000 picoseconds. - Weight::from_parts(361_696_000, 12362) - // Standard Error: 30_917 - .saturating_add(Weight::from_parts(657_166, 0).saturating_mul(x.into())) - // Standard Error: 30_768 - .saturating_add(Weight::from_parts(670_249, 0).saturating_mul(y.into())) - // Standard Error: 61_480 - .saturating_add(Weight::from_parts(14_340_554, 0).saturating_mul(z.into())) + // Minimum execution time: 384_385_000 picoseconds. + Weight::from_parts(390_301_000, 12362) + // Standard Error: 32_391 + .saturating_add(Weight::from_parts(745_632, 0).saturating_mul(x.into())) + // Standard Error: 32_235 + .saturating_add(Weight::from_parts(758_118, 0).saturating_mul(y.into())) + // Standard Error: 64_412 + .saturating_add(Weight::from_parts(14_822_486, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) @@ -307,18 +307,18 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_146_000 picoseconds. - Weight::from_parts(6_540_000, 0) + // Minimum execution time: 6_042_000 picoseconds. + Weight::from_parts(6_385_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Alliance::Announcements` (r:1 w:1) /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) fn announce() -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `312` // Estimated: `10187` - // Minimum execution time: 9_008_000 picoseconds. - Weight::from_parts(9_835_000, 10187) + // Minimum execution time: 10_152_000 picoseconds. + Weight::from_parts(10_728_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -326,10 +326,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) fn remove_announcement() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `385` // Estimated: `10187` - // Minimum execution time: 10_308_000 picoseconds. - Weight::from_parts(10_602_000, 10187) + // Minimum execution time: 11_540_000 picoseconds. + Weight::from_parts(12_160_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -343,10 +343,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `501` + // Measured: `534` // Estimated: `18048` - // Minimum execution time: 40_731_000 picoseconds. - Weight::from_parts(42_453_000, 18048) + // Minimum execution time: 46_932_000 picoseconds. + Weight::from_parts(48_549_000, 18048) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -356,10 +356,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) fn nominate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `400` + // Measured: `433` // Estimated: `18048` - // Minimum execution time: 24_198_000 picoseconds. - Weight::from_parts(25_258_000, 18048) + // Minimum execution time: 29_716_000 picoseconds. + Weight::from_parts(30_911_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -373,10 +373,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `510` + // Measured: `543` // Estimated: `12362` - // Minimum execution time: 24_509_000 picoseconds. - Weight::from_parts(25_490_000, 12362) + // Minimum execution time: 29_323_000 picoseconds. + Weight::from_parts(30_702_000, 12362) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -392,10 +392,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: - // Measured: `510` + // Measured: `543` // Estimated: `23734` - // Minimum execution time: 30_889_000 picoseconds. - Weight::from_parts(31_930_000, 23734) + // Minimum execution time: 35_317_000 picoseconds. + Weight::from_parts(37_017_000, 23734) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -409,10 +409,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `753` // Estimated: `6676` - // Minimum execution time: 38_363_000 picoseconds. - Weight::from_parts(39_428_000, 6676) + // Minimum execution time: 43_741_000 picoseconds. + Weight::from_parts(45_035_000, 6676) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -430,10 +430,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `774` + // Measured: `807` // Estimated: `18048` - // Minimum execution time: 60_717_000 picoseconds. - Weight::from_parts(61_785_000, 18048) + // Minimum execution time: 61_064_000 picoseconds. + Weight::from_parts(63_267_000, 18048) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -445,14 +445,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `312` // Estimated: `27187` - // Minimum execution time: 5_393_000 picoseconds. - Weight::from_parts(5_577_000, 27187) - // Standard Error: 3_099 - .saturating_add(Weight::from_parts(1_043_175, 0).saturating_mul(n.into())) - // Standard Error: 1_213 - .saturating_add(Weight::from_parts(71_633, 0).saturating_mul(l.into())) + // Minimum execution time: 5_117_000 picoseconds. + Weight::from_parts(5_371_000, 27187) + // Standard Error: 3_341 + .saturating_add(Weight::from_parts(1_210_414, 0).saturating_mul(n.into())) + // Standard Error: 1_308 + .saturating_add(Weight::from_parts(72_982, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -466,12 +466,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + l * (100 ±0) + n * (289 ±0)` // Estimated: `27187` - // Minimum execution time: 5_318_000 picoseconds. - Weight::from_parts(5_581_000, 27187) - // Standard Error: 188_914 - .saturating_add(Weight::from_parts(17_878_267, 0).saturating_mul(n.into())) - // Standard Error: 73_987 - .saturating_add(Weight::from_parts(258_754, 0).saturating_mul(l.into())) + // Minimum execution time: 5_433_000 picoseconds. + Weight::from_parts(5_574_000, 27187) + // Standard Error: 193_236 + .saturating_add(Weight::from_parts(18_613_954, 0).saturating_mul(n.into())) + // Standard Error: 75_679 + .saturating_add(Weight::from_parts(221_928, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -485,10 +485,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `510` + // Measured: `543` // Estimated: `18048` - // Minimum execution time: 29_423_000 picoseconds. - Weight::from_parts(30_141_000, 18048) + // Minimum execution time: 34_613_000 picoseconds. + Weight::from_parts(35_866_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -511,16 +511,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `688 + m * (32 ±0) + p * (36 ±0)` + // Measured: `721 + m * (32 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 31_545_000 picoseconds. - Weight::from_parts(33_432_774, 6676) - // Standard Error: 121 - .saturating_add(Weight::from_parts(232, 0).saturating_mul(b.into())) - // Standard Error: 1_263 - .saturating_add(Weight::from_parts(47_800, 0).saturating_mul(m.into())) - // Standard Error: 1_247 - .saturating_add(Weight::from_parts(188_655, 0).saturating_mul(p.into())) + // Minimum execution time: 36_770_000 picoseconds. + Weight::from_parts(39_685_981, 6676) + // Standard Error: 156 + .saturating_add(Weight::from_parts(588, 0).saturating_mul(b.into())) + // Standard Error: 1_636 + .saturating_add(Weight::from_parts(31_314, 0).saturating_mul(m.into())) + // Standard Error: 1_616 + .saturating_add(Weight::from_parts(158_254, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -533,12 +533,12 @@ impl WeightInfo for () { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1147 + m * (64 ±0)` + // Measured: `1180 + m * (64 ±0)` // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 30_462_000 picoseconds. - Weight::from_parts(31_639_466, 6676) - // Standard Error: 980 - .saturating_add(Weight::from_parts(60_075, 0).saturating_mul(m.into())) + // Minimum execution time: 36_851_000 picoseconds. + Weight::from_parts(38_427_277, 6676) + // Standard Error: 1_877 + .saturating_add(Weight::from_parts(50_131, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -557,14 +557,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `674 + m * (96 ±0) + p * (36 ±0)` + // Measured: `707 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 40_765_000 picoseconds. - Weight::from_parts(37_690_472, 6676) - // Standard Error: 1_372 - .saturating_add(Weight::from_parts(69_441, 0).saturating_mul(m.into())) - // Standard Error: 1_338 - .saturating_add(Weight::from_parts(152_833, 0).saturating_mul(p.into())) + // Minimum execution time: 43_572_000 picoseconds. + Weight::from_parts(40_836_679, 6676) + // Standard Error: 1_764 + .saturating_add(Weight::from_parts(59_213, 0).saturating_mul(m.into())) + // Standard Error: 1_720 + .saturating_add(Weight::from_parts(171_689, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -589,16 +589,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1254 + m * (96 ±0) + p * (39 ±0)` + // Measured: `1287 + m * (96 ±0) + p * (39 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 57_367_000 picoseconds. - Weight::from_parts(57_264_486, 6676) - // Standard Error: 141 - .saturating_add(Weight::from_parts(884, 0).saturating_mul(b.into())) - // Standard Error: 1_495 - .saturating_add(Weight::from_parts(57_869, 0).saturating_mul(m.into())) - // Standard Error: 1_458 - .saturating_add(Weight::from_parts(158_784, 0).saturating_mul(p.into())) + // Minimum execution time: 62_758_000 picoseconds. + Weight::from_parts(63_400_227, 6676) + // Standard Error: 233 + .saturating_add(Weight::from_parts(1_156, 0).saturating_mul(b.into())) + // Standard Error: 2_470 + .saturating_add(Weight::from_parts(42_858, 0).saturating_mul(m.into())) + // Standard Error: 2_408 + .saturating_add(Weight::from_parts(185_822, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -620,14 +620,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `675 + m * (96 ±0) + p * (36 ±0)` + // Measured: `708 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 41_253_000 picoseconds. - Weight::from_parts(37_550_833, 6676) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(77_359, 0).saturating_mul(m.into())) - // Standard Error: 1_148 - .saturating_add(Weight::from_parts(153_523, 0).saturating_mul(p.into())) + // Minimum execution time: 45_287_000 picoseconds. + Weight::from_parts(44_144_056, 6676) + // Standard Error: 1_553 + .saturating_add(Weight::from_parts(50_224, 0).saturating_mul(m.into())) + // Standard Error: 1_534 + .saturating_add(Weight::from_parts(154_551, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -650,16 +650,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `728 + m * (96 ±0) + p * (35 ±0)` + // Measured: `761 + m * (96 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 42_385_000 picoseconds. - Weight::from_parts(37_222_159, 6676) - // Standard Error: 118 - .saturating_add(Weight::from_parts(1_743, 0).saturating_mul(b.into())) - // Standard Error: 1_268 - .saturating_add(Weight::from_parts(59_743, 0).saturating_mul(m.into())) - // Standard Error: 1_222 - .saturating_add(Weight::from_parts(159_606, 0).saturating_mul(p.into())) + // Minimum execution time: 45_943_000 picoseconds. + Weight::from_parts(43_665_317, 6676) + // Standard Error: 164 + .saturating_add(Weight::from_parts(1_296, 0).saturating_mul(b.into())) + // Standard Error: 1_757 + .saturating_add(Weight::from_parts(35_145, 0).saturating_mul(m.into())) + // Standard Error: 1_694 + .saturating_add(Weight::from_parts(164_507, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) @@ -673,14 +673,14 @@ impl WeightInfo for () { /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `284` + // Measured: `317` // Estimated: `12362` - // Minimum execution time: 31_184_000 picoseconds. - Weight::from_parts(22_860_208, 12362) - // Standard Error: 1_096 - .saturating_add(Weight::from_parts(129_834, 0).saturating_mul(m.into())) - // Standard Error: 1_083 - .saturating_add(Weight::from_parts(97_546, 0).saturating_mul(z.into())) + // Minimum execution time: 34_959_000 picoseconds. + Weight::from_parts(25_620_911, 12362) + // Standard Error: 1_457 + .saturating_add(Weight::from_parts(130_068, 0).saturating_mul(m.into())) + // Standard Error: 1_440 + .saturating_add(Weight::from_parts(113_433, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -701,16 +701,16 @@ impl WeightInfo for () { /// The range of component `z` is `[0, 50]`. fn disband(x: u32, y: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` + // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (252 ±0)` // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 359_308_000 picoseconds. - Weight::from_parts(361_696_000, 12362) - // Standard Error: 30_917 - .saturating_add(Weight::from_parts(657_166, 0).saturating_mul(x.into())) - // Standard Error: 30_768 - .saturating_add(Weight::from_parts(670_249, 0).saturating_mul(y.into())) - // Standard Error: 61_480 - .saturating_add(Weight::from_parts(14_340_554, 0).saturating_mul(z.into())) + // Minimum execution time: 384_385_000 picoseconds. + Weight::from_parts(390_301_000, 12362) + // Standard Error: 32_391 + .saturating_add(Weight::from_parts(745_632, 0).saturating_mul(x.into())) + // Standard Error: 32_235 + .saturating_add(Weight::from_parts(758_118, 0).saturating_mul(y.into())) + // Standard Error: 64_412 + .saturating_add(Weight::from_parts(14_822_486, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) @@ -727,18 +727,18 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_146_000 picoseconds. - Weight::from_parts(6_540_000, 0) + // Minimum execution time: 6_042_000 picoseconds. + Weight::from_parts(6_385_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Alliance::Announcements` (r:1 w:1) /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) fn announce() -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `312` // Estimated: `10187` - // Minimum execution time: 9_008_000 picoseconds. - Weight::from_parts(9_835_000, 10187) + // Minimum execution time: 10_152_000 picoseconds. + Weight::from_parts(10_728_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -746,10 +746,10 @@ impl WeightInfo for () { /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) fn remove_announcement() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `385` // Estimated: `10187` - // Minimum execution time: 10_308_000 picoseconds. - Weight::from_parts(10_602_000, 10187) + // Minimum execution time: 11_540_000 picoseconds. + Weight::from_parts(12_160_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -763,10 +763,10 @@ impl WeightInfo for () { /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `501` + // Measured: `534` // Estimated: `18048` - // Minimum execution time: 40_731_000 picoseconds. - Weight::from_parts(42_453_000, 18048) + // Minimum execution time: 46_932_000 picoseconds. + Weight::from_parts(48_549_000, 18048) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -776,10 +776,10 @@ impl WeightInfo for () { /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) fn nominate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `400` + // Measured: `433` // Estimated: `18048` - // Minimum execution time: 24_198_000 picoseconds. - Weight::from_parts(25_258_000, 18048) + // Minimum execution time: 29_716_000 picoseconds. + Weight::from_parts(30_911_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -793,10 +793,10 @@ impl WeightInfo for () { /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `510` + // Measured: `543` // Estimated: `12362` - // Minimum execution time: 24_509_000 picoseconds. - Weight::from_parts(25_490_000, 12362) + // Minimum execution time: 29_323_000 picoseconds. + Weight::from_parts(30_702_000, 12362) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -812,10 +812,10 @@ impl WeightInfo for () { /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: - // Measured: `510` + // Measured: `543` // Estimated: `23734` - // Minimum execution time: 30_889_000 picoseconds. - Weight::from_parts(31_930_000, 23734) + // Minimum execution time: 35_317_000 picoseconds. + Weight::from_parts(37_017_000, 23734) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -829,10 +829,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `753` // Estimated: `6676` - // Minimum execution time: 38_363_000 picoseconds. - Weight::from_parts(39_428_000, 6676) + // Minimum execution time: 43_741_000 picoseconds. + Weight::from_parts(45_035_000, 6676) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -850,10 +850,10 @@ impl WeightInfo for () { /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `774` + // Measured: `807` // Estimated: `18048` - // Minimum execution time: 60_717_000 picoseconds. - Weight::from_parts(61_785_000, 18048) + // Minimum execution time: 61_064_000 picoseconds. + Weight::from_parts(63_267_000, 18048) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -865,14 +865,14 @@ impl WeightInfo for () { /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `312` // Estimated: `27187` - // Minimum execution time: 5_393_000 picoseconds. - Weight::from_parts(5_577_000, 27187) - // Standard Error: 3_099 - .saturating_add(Weight::from_parts(1_043_175, 0).saturating_mul(n.into())) - // Standard Error: 1_213 - .saturating_add(Weight::from_parts(71_633, 0).saturating_mul(l.into())) + // Minimum execution time: 5_117_000 picoseconds. + Weight::from_parts(5_371_000, 27187) + // Standard Error: 3_341 + .saturating_add(Weight::from_parts(1_210_414, 0).saturating_mul(n.into())) + // Standard Error: 1_308 + .saturating_add(Weight::from_parts(72_982, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -886,12 +886,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + l * (100 ±0) + n * (289 ±0)` // Estimated: `27187` - // Minimum execution time: 5_318_000 picoseconds. - Weight::from_parts(5_581_000, 27187) - // Standard Error: 188_914 - .saturating_add(Weight::from_parts(17_878_267, 0).saturating_mul(n.into())) - // Standard Error: 73_987 - .saturating_add(Weight::from_parts(258_754, 0).saturating_mul(l.into())) + // Minimum execution time: 5_433_000 picoseconds. + Weight::from_parts(5_574_000, 27187) + // Standard Error: 193_236 + .saturating_add(Weight::from_parts(18_613_954, 0).saturating_mul(n.into())) + // Standard Error: 75_679 + .saturating_add(Weight::from_parts(221_928, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -905,10 +905,10 @@ impl WeightInfo for () { /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `510` + // Measured: `543` // Estimated: `18048` - // Minimum execution time: 29_423_000 picoseconds. - Weight::from_parts(30_141_000, 18048) + // Minimum execution time: 34_613_000 picoseconds. + Weight::from_parts(35_866_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 10a118e95639..8987e44ee000 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -17,20 +17,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } +log = { workspace = true } scale-info = { features = ["derive"], workspace = true } sp-api = { workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-arithmetic = { workspace = true } [dev-dependencies] -pallet-balances = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } [features] diff --git a/substrate/frame/asset-conversion/ops/Cargo.toml b/substrate/frame/asset-conversion/ops/Cargo.toml index 66333f973d7f..ebd31bd296de 100644 --- a/substrate/frame/asset-conversion/ops/Cargo.toml +++ b/substrate/frame/asset-conversion/ops/Cargo.toml @@ -16,20 +16,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } +log = { workspace = true } pallet-asset-conversion = { workspace = true } scale-info = { features = ["derive"], workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-arithmetic = { workspace = true } [dev-dependencies] -pallet-balances = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } [features] diff --git a/substrate/frame/asset-conversion/ops/src/weights.rs b/substrate/frame/asset-conversion/ops/src/weights.rs index 9e7379c50156..65762bed72e2 100644 --- a/substrate/frame/asset-conversion/ops/src/weights.rs +++ b/substrate/frame/asset-conversion/ops/src/weights.rs @@ -18,25 +18,27 @@ //! Autogenerated weights for `pallet_asset_conversion_ops` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_asset_conversion_ops +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_asset_conversion_ops -// --chain=dev +// --output=./substrate/frame/asset-conversion/ops/src/weights.rs // --header=./substrate/HEADER-APACHE2 -// --output=./substrate/frame/asset-conversion-ops/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,10 +71,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn migrate_to_new_account() -> Weight { // Proof Size summary in bytes: - // Measured: `1762` + // Measured: `1796` // Estimated: `11426` - // Minimum execution time: 223_850_000 picoseconds. - Weight::from_parts(231_676_000, 11426) + // Minimum execution time: 235_181_000 picoseconds. + Weight::from_parts(243_965_000, 11426) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) } @@ -94,10 +96,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn migrate_to_new_account() -> Weight { // Proof Size summary in bytes: - // Measured: `1762` + // Measured: `1796` // Estimated: `11426` - // Minimum execution time: 223_850_000 picoseconds. - Weight::from_parts(231_676_000, 11426) + // Minimum execution time: 235_181_000 picoseconds. + Weight::from_parts(243_965_000, 11426) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) } diff --git a/substrate/frame/asset-conversion/src/weights.rs b/substrate/frame/asset-conversion/src/weights.rs index f6e025520d71..dd7feb08f9f4 100644 --- a/substrate/frame/asset-conversion/src/weights.rs +++ b/substrate/frame/asset-conversion/src/weights.rs @@ -18,24 +18,25 @@ //! Autogenerated weights for `pallet_asset_conversion` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-p5qp1txx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_asset_conversion +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_asset_conversion -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/asset-conversion/src/weights.rs // --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs @@ -71,15 +72,17 @@ impl WeightInfo for SubstrateWeight { /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::NextAssetId` (r:1 w:0) + /// Proof: `PoolAssets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:1 w:1) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `910` + // Measured: `949` // Estimated: `6360` - // Minimum execution time: 95_080_000 picoseconds. - Weight::from_parts(97_241_000, 6360) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 97_276_000 picoseconds. + Weight::from_parts(99_380_000, 6360) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) @@ -96,10 +99,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn add_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1507` + // Measured: `1546` // Estimated: `11426` - // Minimum execution time: 147_652_000 picoseconds. - Weight::from_parts(153_331_000, 11426) + // Minimum execution time: 153_723_000 picoseconds. + Weight::from_parts(155_774_000, 11426) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -117,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `11426` - // Minimum execution time: 130_738_000 picoseconds. - Weight::from_parts(134_350_000, 11426) + // Minimum execution time: 138_643_000 picoseconds. + Weight::from_parts(140_518_000, 11426) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -131,10 +134,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 79_681_000 picoseconds. - Weight::from_parts(81_461_000, 990) - // Standard Error: 320_959 - .saturating_add(Weight::from_parts(11_223_703, 0).saturating_mul(n.into())) + // Minimum execution time: 93_760_000 picoseconds. + Weight::from_parts(6_225_956, 990) + // Standard Error: 70_327 + .saturating_add(Weight::from_parts(45_209_796, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -148,10 +151,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 78_988_000 picoseconds. - Weight::from_parts(81_025_000, 990) - // Standard Error: 320_021 - .saturating_add(Weight::from_parts(11_040_712, 0).saturating_mul(n.into())) + // Minimum execution time: 93_972_000 picoseconds. + Weight::from_parts(4_882_727, 990) + // Standard Error: 69_974 + .saturating_add(Weight::from_parts(45_961_057, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -171,12 +174,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 3]`. fn touch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1571` + // Measured: `1610` // Estimated: `6360` - // Minimum execution time: 45_757_000 picoseconds. - Weight::from_parts(48_502_032, 6360) - // Standard Error: 62_850 - .saturating_add(Weight::from_parts(19_450_978, 0).saturating_mul(n.into())) + // Minimum execution time: 56_011_000 picoseconds. + Weight::from_parts(59_515_373, 6360) + // Standard Error: 81_340 + .saturating_add(Weight::from_parts(19_186_821, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) } @@ -194,15 +197,17 @@ impl WeightInfo for () { /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::NextAssetId` (r:1 w:0) + /// Proof: `PoolAssets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:1 w:1) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `910` + // Measured: `949` // Estimated: `6360` - // Minimum execution time: 95_080_000 picoseconds. - Weight::from_parts(97_241_000, 6360) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 97_276_000 picoseconds. + Weight::from_parts(99_380_000, 6360) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) @@ -219,10 +224,10 @@ impl WeightInfo for () { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn add_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1507` + // Measured: `1546` // Estimated: `11426` - // Minimum execution time: 147_652_000 picoseconds. - Weight::from_parts(153_331_000, 11426) + // Minimum execution time: 153_723_000 picoseconds. + Weight::from_parts(155_774_000, 11426) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -240,8 +245,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `11426` - // Minimum execution time: 130_738_000 picoseconds. - Weight::from_parts(134_350_000, 11426) + // Minimum execution time: 138_643_000 picoseconds. + Weight::from_parts(140_518_000, 11426) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -254,10 +259,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 79_681_000 picoseconds. - Weight::from_parts(81_461_000, 990) - // Standard Error: 320_959 - .saturating_add(Weight::from_parts(11_223_703, 0).saturating_mul(n.into())) + // Minimum execution time: 93_760_000 picoseconds. + Weight::from_parts(6_225_956, 990) + // Standard Error: 70_327 + .saturating_add(Weight::from_parts(45_209_796, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -271,10 +276,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 78_988_000 picoseconds. - Weight::from_parts(81_025_000, 990) - // Standard Error: 320_021 - .saturating_add(Weight::from_parts(11_040_712, 0).saturating_mul(n.into())) + // Minimum execution time: 93_972_000 picoseconds. + Weight::from_parts(4_882_727, 990) + // Standard Error: 69_974 + .saturating_add(Weight::from_parts(45_961_057, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -294,12 +299,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 3]`. fn touch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1571` + // Measured: `1610` // Estimated: `6360` - // Minimum execution time: 45_757_000 picoseconds. - Weight::from_parts(48_502_032, 6360) - // Standard Error: 62_850 - .saturating_add(Weight::from_parts(19_450_978, 0).saturating_mul(n.into())) + // Minimum execution time: 56_011_000 picoseconds. + Weight::from_parts(59_515_373, 6360) + // Standard Error: 81_340 + .saturating_add(Weight::from_parts(19_186_821, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) } diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 514b6fa40c2b..01a5ca21b199 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -18,17 +18,17 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-runtime = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { optional = true, workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } sp-core = { workspace = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/asset-rate/src/weights.rs b/substrate/frame/asset-rate/src/weights.rs index fb577b618b33..c1991dc4ebb2 100644 --- a/substrate/frame/asset-rate/src/weights.rs +++ b/substrate/frame/asset-rate/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_asset_rate` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -60,35 +60,35 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `3501` - // Minimum execution time: 9_816_000 picoseconds. - Weight::from_parts(10_076_000, 3501) + // Estimated: `3502` + // Minimum execution time: 10_361_000 picoseconds. + Weight::from_parts(10_757_000, 3502) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) fn update() -> Weight { // Proof Size summary in bytes: - // Measured: `137` - // Estimated: `3501` - // Minimum execution time: 10_164_000 picoseconds. - Weight::from_parts(10_598_000, 3501) + // Measured: `134` + // Estimated: `3502` + // Minimum execution time: 11_193_000 picoseconds. + Weight::from_parts(11_625_000, 3502) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) fn remove() -> Weight { // Proof Size summary in bytes: - // Measured: `137` - // Estimated: `3501` - // Minimum execution time: 10_837_000 picoseconds. - Weight::from_parts(11_050_000, 3501) + // Measured: `134` + // Estimated: `3502` + // Minimum execution time: 11_941_000 picoseconds. + Weight::from_parts(12_440_000, 3502) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -97,35 +97,35 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests. impl WeightInfo for () { /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `3501` - // Minimum execution time: 9_816_000 picoseconds. - Weight::from_parts(10_076_000, 3501) + // Estimated: `3502` + // Minimum execution time: 10_361_000 picoseconds. + Weight::from_parts(10_757_000, 3502) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) fn update() -> Weight { // Proof Size summary in bytes: - // Measured: `137` - // Estimated: `3501` - // Minimum execution time: 10_164_000 picoseconds. - Weight::from_parts(10_598_000, 3501) + // Measured: `134` + // Estimated: `3502` + // Minimum execution time: 11_193_000 picoseconds. + Weight::from_parts(11_625_000, 3502) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) fn remove() -> Weight { // Proof Size summary in bytes: - // Measured: `137` - // Estimated: `3501` - // Minimum execution time: 10_837_000 picoseconds. - Weight::from_parts(11_050_000, 3501) + // Measured: `134` + // Estimated: `3502` + // Minimum execution time: 11_941_000 picoseconds. + Weight::from_parts(12_440_000, 3502) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/assets-freezer/Cargo.toml b/substrate/frame/assets-freezer/Cargo.toml index 68bfdd7cfb62..3fffa4d0627f 100644 --- a/substrate/frame/assets-freezer/Cargo.toml +++ b/substrate/frame/assets-freezer/Cargo.toml @@ -16,18 +16,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-assets = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] -sp-io = { workspace = true } -sp-core = { workspace = true } pallet-balances = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index e20b576d0836..a062a68d4220 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -25,13 +25,13 @@ sp-runtime = { workspace = true } # Needed for type-safe access to storage DB. frame-support = { workspace = true } # `system` module provides us with all sorts of useful stuff and macros depend on it being around. -frame-system = { workspace = true } frame-benchmarking = { optional = true, workspace = true } +frame-system = { workspace = true } sp-core = { workspace = true } [dev-dependencies] -sp-io = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index e909932bfc82..a9b0dc950a61 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -275,7 +275,7 @@ pub mod pallet { /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::*; - use frame_support::{derive_impl, traits::ConstU64}; + use frame_support::derive_impl; pub struct TestDefaultConfig; #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] @@ -289,11 +289,11 @@ pub mod pallet { type RemoveItemsLimit = ConstU32<5>; type AssetId = u32; type AssetIdParameter = u32; - type AssetDeposit = ConstU64<1>; - type AssetAccountDeposit = ConstU64<10>; - type MetadataDepositBase = ConstU64<1>; - type MetadataDepositPerByte = ConstU64<1>; - type ApprovalDeposit = ConstU64<1>; + type AssetDeposit = ConstUint<1>; + type AssetAccountDeposit = ConstUint<10>; + type MetadataDepositBase = ConstUint<1>; + type MetadataDepositPerByte = ConstUint<1>; + type ApprovalDeposit = ConstUint<1>; type StringLimit = ConstU32<50>; type Extra = (); type CallbackHandle = (); diff --git a/substrate/frame/assets/src/weights.rs b/substrate/frame/assets/src/weights.rs index 57f7e951b73c..09997bc9d719 100644 --- a/substrate/frame/assets/src/weights.rs +++ b/substrate/frame/assets/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_assets` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -91,26 +91,30 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::NextAssetId` (r:1 w:0) + /// Proof: `Assets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3675` - // Minimum execution time: 26_165_000 picoseconds. - Weight::from_parts(26_838_000, 3675) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 33_908_000 picoseconds. + Weight::from_parts(37_126_000, 3675) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::NextAssetId` (r:1 w:0) + /// Proof: `Assets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 11_152_000 picoseconds. - Weight::from_parts(11_624_000, 3675) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 13_105_000 picoseconds. + Weight::from_parts(13_348_000, 3675) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Assets::Asset` (r:1 w:1) @@ -119,8 +123,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_961_000 picoseconds. - Weight::from_parts(12_408_000, 3675) + // Minimum execution time: 17_478_000 picoseconds. + Weight::from_parts(17_964_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -133,12 +137,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + c * (208 ±0)` + // Measured: `71 + c * (208 ±0)` // Estimated: `3675 + c * (2609 ±0)` - // Minimum execution time: 15_815_000 picoseconds. - Weight::from_parts(16_370_000, 3675) - // Standard Error: 7_448 - .saturating_add(Weight::from_parts(13_217_179, 0).saturating_mul(c.into())) + // Minimum execution time: 20_846_000 picoseconds. + Weight::from_parts(21_195_000, 3675) + // Standard Error: 13_008 + .saturating_add(Weight::from_parts(15_076_064, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -154,10 +158,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 16_791_000 picoseconds. - Weight::from_parts(17_066_000, 3675) - // Standard Error: 7_163 - .saturating_add(Weight::from_parts(14_436_592, 0).saturating_mul(a.into())) + // Minimum execution time: 21_340_000 picoseconds. + Weight::from_parts(21_916_000, 3675) + // Standard Error: 8_545 + .saturating_add(Weight::from_parts(15_868_375, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -172,8 +176,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 12_769_000 picoseconds. - Weight::from_parts(13_097_000, 3675) + // Minimum execution time: 18_110_000 picoseconds. + Weight::from_parts(18_512_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -185,8 +189,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 22_539_000 picoseconds. - Weight::from_parts(23_273_000, 3675) + // Minimum execution time: 27_639_000 picoseconds. + Weight::from_parts(28_680_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -198,8 +202,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 30_885_000 picoseconds. - Weight::from_parts(31_800_000, 3675) + // Minimum execution time: 36_011_000 picoseconds. + Weight::from_parts(37_095_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -213,8 +217,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 43_618_000 picoseconds. - Weight::from_parts(44_794_000, 6208) + // Minimum execution time: 48_531_000 picoseconds. + Weight::from_parts(50_508_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -228,8 +232,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 39_174_000 picoseconds. - Weight::from_parts(40_059_000, 6208) + // Minimum execution time: 44_754_000 picoseconds. + Weight::from_parts(45_999_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -243,8 +247,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 43_963_000 picoseconds. - Weight::from_parts(44_995_000, 6208) + // Minimum execution time: 48_407_000 picoseconds. + Weight::from_parts(49_737_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -256,8 +260,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_853_000 picoseconds. - Weight::from_parts(16_414_000, 3675) + // Minimum execution time: 21_827_000 picoseconds. + Weight::from_parts(22_616_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -269,8 +273,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_925_000 picoseconds. - Weight::from_parts(16_449_000, 3675) + // Minimum execution time: 21_579_000 picoseconds. + Weight::from_parts(22_406_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -280,8 +284,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_629_000 picoseconds. - Weight::from_parts(12_138_000, 3675) + // Minimum execution time: 16_754_000 picoseconds. + Weight::from_parts(17_556_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -291,8 +295,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_653_000 picoseconds. - Weight::from_parts(12_058_000, 3675) + // Minimum execution time: 16_602_000 picoseconds. + Weight::from_parts(17_551_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -304,8 +308,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 13_292_000 picoseconds. - Weight::from_parts(13_686_000, 3675) + // Minimum execution time: 18_231_000 picoseconds. + Weight::from_parts(18_899_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -315,8 +319,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_805_000 picoseconds. - Weight::from_parts(12_060_000, 3675) + // Minimum execution time: 16_396_000 picoseconds. + Weight::from_parts(16_937_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -326,16 +330,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 26_289_000 picoseconds. - Weight::from_parts(27_543_545, 3675) - // Standard Error: 939 - .saturating_add(Weight::from_parts(4_967, 0).saturating_mul(n.into())) - // Standard Error: 939 - .saturating_add(Weight::from_parts(3_698, 0).saturating_mul(s.into())) + // Minimum execution time: 31_604_000 picoseconds. + Weight::from_parts(33_443_707, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -347,8 +347,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 27_560_000 picoseconds. - Weight::from_parts(28_541_000, 3675) + // Minimum execution time: 32_152_000 picoseconds. + Weight::from_parts(32_893_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -362,12 +362,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 12_378_000 picoseconds. - Weight::from_parts(13_057_891, 3675) - // Standard Error: 474 - .saturating_add(Weight::from_parts(1_831, 0).saturating_mul(n.into())) - // Standard Error: 474 - .saturating_add(Weight::from_parts(2_387, 0).saturating_mul(s.into())) + // Minimum execution time: 13_637_000 picoseconds. + Weight::from_parts(14_385_881, 3675) + // Standard Error: 375 + .saturating_add(Weight::from_parts(1_821, 0).saturating_mul(n.into())) + // Standard Error: 375 + .saturating_add(Weight::from_parts(147, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -379,8 +379,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 27_134_000 picoseconds. - Weight::from_parts(28_333_000, 3675) + // Minimum execution time: 31_587_000 picoseconds. + Weight::from_parts(32_438_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -390,8 +390,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_524_000 picoseconds. - Weight::from_parts(11_934_000, 3675) + // Minimum execution time: 16_006_000 picoseconds. + Weight::from_parts(16_623_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -403,8 +403,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 30_206_000 picoseconds. - Weight::from_parts(31_624_000, 3675) + // Minimum execution time: 36_026_000 picoseconds. + Weight::from_parts(37_023_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -420,8 +420,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `6208` - // Minimum execution time: 64_074_000 picoseconds. - Weight::from_parts(66_145_000, 6208) + // Minimum execution time: 68_731_000 picoseconds. + Weight::from_parts(70_171_000, 6208) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -433,8 +433,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 32_790_000 picoseconds. - Weight::from_parts(33_634_000, 3675) + // Minimum execution time: 38_039_000 picoseconds. + Weight::from_parts(39_018_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -446,8 +446,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 33_150_000 picoseconds. - Weight::from_parts(34_440_000, 3675) + // Minimum execution time: 38_056_000 picoseconds. + Weight::from_parts(39_228_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -457,8 +457,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 12_365_000 picoseconds. - Weight::from_parts(12_870_000, 3675) + // Minimum execution time: 16_653_000 picoseconds. + Weight::from_parts(17_240_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -472,8 +472,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3675` - // Minimum execution time: 32_308_000 picoseconds. - Weight::from_parts(33_080_000, 3675) + // Minimum execution time: 37_938_000 picoseconds. + Weight::from_parts(38_960_000, 3675) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -485,8 +485,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 29_870_000 picoseconds. - Weight::from_parts(30_562_000, 3675) + // Minimum execution time: 35_210_000 picoseconds. + Weight::from_parts(36_222_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -500,8 +500,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `3675` - // Minimum execution time: 31_980_000 picoseconds. - Weight::from_parts(33_747_000, 3675) + // Minimum execution time: 36_787_000 picoseconds. + Weight::from_parts(38_229_000, 3675) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -513,8 +513,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3675` - // Minimum execution time: 29_599_000 picoseconds. - Weight::from_parts(30_919_000, 3675) + // Minimum execution time: 34_185_000 picoseconds. + Weight::from_parts(35_456_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -526,20 +526,25 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_741_000 picoseconds. - Weight::from_parts(16_558_000, 3675) + // Minimum execution time: 21_482_000 picoseconds. + Weight::from_parts(22_135_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 46_573_000 picoseconds. - Weight::from_parts(47_385_000, 3593) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `498` + // Estimated: `6208` + // Minimum execution time: 58_108_000 picoseconds. + Weight::from_parts(59_959_000, 6208) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } } @@ -547,26 +552,30 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::NextAssetId` (r:1 w:0) + /// Proof: `Assets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3675` - // Minimum execution time: 26_165_000 picoseconds. - Weight::from_parts(26_838_000, 3675) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 33_908_000 picoseconds. + Weight::from_parts(37_126_000, 3675) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::NextAssetId` (r:1 w:0) + /// Proof: `Assets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 11_152_000 picoseconds. - Weight::from_parts(11_624_000, 3675) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 13_105_000 picoseconds. + Weight::from_parts(13_348_000, 3675) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Assets::Asset` (r:1 w:1) @@ -575,8 +584,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_961_000 picoseconds. - Weight::from_parts(12_408_000, 3675) + // Minimum execution time: 17_478_000 picoseconds. + Weight::from_parts(17_964_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -589,12 +598,12 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + c * (208 ±0)` + // Measured: `71 + c * (208 ±0)` // Estimated: `3675 + c * (2609 ±0)` - // Minimum execution time: 15_815_000 picoseconds. - Weight::from_parts(16_370_000, 3675) - // Standard Error: 7_448 - .saturating_add(Weight::from_parts(13_217_179, 0).saturating_mul(c.into())) + // Minimum execution time: 20_846_000 picoseconds. + Weight::from_parts(21_195_000, 3675) + // Standard Error: 13_008 + .saturating_add(Weight::from_parts(15_076_064, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -610,10 +619,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 16_791_000 picoseconds. - Weight::from_parts(17_066_000, 3675) - // Standard Error: 7_163 - .saturating_add(Weight::from_parts(14_436_592, 0).saturating_mul(a.into())) + // Minimum execution time: 21_340_000 picoseconds. + Weight::from_parts(21_916_000, 3675) + // Standard Error: 8_545 + .saturating_add(Weight::from_parts(15_868_375, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -628,8 +637,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 12_769_000 picoseconds. - Weight::from_parts(13_097_000, 3675) + // Minimum execution time: 18_110_000 picoseconds. + Weight::from_parts(18_512_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -641,8 +650,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 22_539_000 picoseconds. - Weight::from_parts(23_273_000, 3675) + // Minimum execution time: 27_639_000 picoseconds. + Weight::from_parts(28_680_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -654,8 +663,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 30_885_000 picoseconds. - Weight::from_parts(31_800_000, 3675) + // Minimum execution time: 36_011_000 picoseconds. + Weight::from_parts(37_095_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -669,8 +678,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 43_618_000 picoseconds. - Weight::from_parts(44_794_000, 6208) + // Minimum execution time: 48_531_000 picoseconds. + Weight::from_parts(50_508_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -684,8 +693,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 39_174_000 picoseconds. - Weight::from_parts(40_059_000, 6208) + // Minimum execution time: 44_754_000 picoseconds. + Weight::from_parts(45_999_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -699,8 +708,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 43_963_000 picoseconds. - Weight::from_parts(44_995_000, 6208) + // Minimum execution time: 48_407_000 picoseconds. + Weight::from_parts(49_737_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -712,8 +721,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_853_000 picoseconds. - Weight::from_parts(16_414_000, 3675) + // Minimum execution time: 21_827_000 picoseconds. + Weight::from_parts(22_616_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -725,8 +734,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_925_000 picoseconds. - Weight::from_parts(16_449_000, 3675) + // Minimum execution time: 21_579_000 picoseconds. + Weight::from_parts(22_406_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -736,8 +745,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_629_000 picoseconds. - Weight::from_parts(12_138_000, 3675) + // Minimum execution time: 16_754_000 picoseconds. + Weight::from_parts(17_556_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -747,8 +756,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_653_000 picoseconds. - Weight::from_parts(12_058_000, 3675) + // Minimum execution time: 16_602_000 picoseconds. + Weight::from_parts(17_551_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -760,8 +769,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 13_292_000 picoseconds. - Weight::from_parts(13_686_000, 3675) + // Minimum execution time: 18_231_000 picoseconds. + Weight::from_parts(18_899_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -771,8 +780,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_805_000 picoseconds. - Weight::from_parts(12_060_000, 3675) + // Minimum execution time: 16_396_000 picoseconds. + Weight::from_parts(16_937_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -782,16 +791,12 @@ impl WeightInfo for () { /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 26_289_000 picoseconds. - Weight::from_parts(27_543_545, 3675) - // Standard Error: 939 - .saturating_add(Weight::from_parts(4_967, 0).saturating_mul(n.into())) - // Standard Error: 939 - .saturating_add(Weight::from_parts(3_698, 0).saturating_mul(s.into())) + // Minimum execution time: 31_604_000 picoseconds. + Weight::from_parts(33_443_707, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -803,8 +808,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 27_560_000 picoseconds. - Weight::from_parts(28_541_000, 3675) + // Minimum execution time: 32_152_000 picoseconds. + Weight::from_parts(32_893_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -818,12 +823,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 12_378_000 picoseconds. - Weight::from_parts(13_057_891, 3675) - // Standard Error: 474 - .saturating_add(Weight::from_parts(1_831, 0).saturating_mul(n.into())) - // Standard Error: 474 - .saturating_add(Weight::from_parts(2_387, 0).saturating_mul(s.into())) + // Minimum execution time: 13_637_000 picoseconds. + Weight::from_parts(14_385_881, 3675) + // Standard Error: 375 + .saturating_add(Weight::from_parts(1_821, 0).saturating_mul(n.into())) + // Standard Error: 375 + .saturating_add(Weight::from_parts(147, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -835,8 +840,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 27_134_000 picoseconds. - Weight::from_parts(28_333_000, 3675) + // Minimum execution time: 31_587_000 picoseconds. + Weight::from_parts(32_438_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -846,8 +851,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_524_000 picoseconds. - Weight::from_parts(11_934_000, 3675) + // Minimum execution time: 16_006_000 picoseconds. + Weight::from_parts(16_623_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -859,8 +864,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 30_206_000 picoseconds. - Weight::from_parts(31_624_000, 3675) + // Minimum execution time: 36_026_000 picoseconds. + Weight::from_parts(37_023_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -876,8 +881,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `668` // Estimated: `6208` - // Minimum execution time: 64_074_000 picoseconds. - Weight::from_parts(66_145_000, 6208) + // Minimum execution time: 68_731_000 picoseconds. + Weight::from_parts(70_171_000, 6208) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -889,8 +894,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 32_790_000 picoseconds. - Weight::from_parts(33_634_000, 3675) + // Minimum execution time: 38_039_000 picoseconds. + Weight::from_parts(39_018_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -902,8 +907,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 33_150_000 picoseconds. - Weight::from_parts(34_440_000, 3675) + // Minimum execution time: 38_056_000 picoseconds. + Weight::from_parts(39_228_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -913,8 +918,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 12_365_000 picoseconds. - Weight::from_parts(12_870_000, 3675) + // Minimum execution time: 16_653_000 picoseconds. + Weight::from_parts(17_240_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -928,8 +933,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3675` - // Minimum execution time: 32_308_000 picoseconds. - Weight::from_parts(33_080_000, 3675) + // Minimum execution time: 37_938_000 picoseconds. + Weight::from_parts(38_960_000, 3675) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -941,8 +946,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 29_870_000 picoseconds. - Weight::from_parts(30_562_000, 3675) + // Minimum execution time: 35_210_000 picoseconds. + Weight::from_parts(36_222_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -956,8 +961,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `579` // Estimated: `3675` - // Minimum execution time: 31_980_000 picoseconds. - Weight::from_parts(33_747_000, 3675) + // Minimum execution time: 36_787_000 picoseconds. + Weight::from_parts(38_229_000, 3675) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -969,8 +974,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3675` - // Minimum execution time: 29_599_000 picoseconds. - Weight::from_parts(30_919_000, 3675) + // Minimum execution time: 34_185_000 picoseconds. + Weight::from_parts(35_456_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -982,19 +987,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_741_000 picoseconds. - Weight::from_parts(16_558_000, 3675) + // Minimum execution time: 21_482_000 picoseconds. + Weight::from_parts(22_135_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 46_573_000 picoseconds. - Weight::from_parts(47_385_000, 3593) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `498` + // Estimated: `6208` + // Minimum execution time: 58_108_000 picoseconds. + Weight::from_parts(59_959_000, 6208) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } } diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index db89a58da8f0..785bfee71b68 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -17,12 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } scale-info = { features = ["derive"], workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -sp-core = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } @@ -31,17 +27,11 @@ pallet-balances = { workspace = true, default-features = true } default = ["std"] std = [ "codec/std", - "frame-support/std", - "frame-system/std", + "frame/std", "pallet-balances/std", "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", + "frame/try-runtime", "pallet-balances/try-runtime", - "sp-runtime/try-runtime", ] diff --git a/substrate/frame/atomic-swap/src/lib.rs b/substrate/frame/atomic-swap/src/lib.rs index c3010f5c9c03..9521f20fe009 100644 --- a/substrate/frame/atomic-swap/src/lib.rs +++ b/substrate/frame/atomic-swap/src/lib.rs @@ -50,17 +50,11 @@ use core::{ marker::PhantomData, ops::{Deref, DerefMut}, }; -use frame_support::{ - dispatch::DispatchResult, - pallet_prelude::MaxEncodedLen, - traits::{BalanceStatus, Currency, Get, ReservableCurrency}, - weights::Weight, - RuntimeDebugNoBound, +use frame::{ + prelude::*, + traits::{BalanceStatus, Currency, ReservableCurrency}, }; -use frame_system::pallet_prelude::BlockNumberFor; use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::RuntimeDebug; /// Pending atomic swap operation. #[derive(Clone, Eq, PartialEq, RuntimeDebugNoBound, Encode, Decode, TypeInfo, MaxEncodedLen)] @@ -159,11 +153,9 @@ where pub use pallet::*; -#[frame_support::pallet] +#[frame::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; /// Atomic swap's pallet configuration trait. #[pallet::config] diff --git a/substrate/frame/atomic-swap/src/tests.rs b/substrate/frame/atomic-swap/src/tests.rs index 47ebe6a8f0ac..6fcc5571a523 100644 --- a/substrate/frame/atomic-swap/src/tests.rs +++ b/substrate/frame/atomic-swap/src/tests.rs @@ -19,13 +19,11 @@ use super::*; use crate as pallet_atomic_swap; - -use frame_support::{derive_impl, traits::ConstU32}; -use sp_runtime::BuildStorage; +use frame::testing_prelude::*; type Block = frame_system::mocking::MockBlock; -frame_support::construct_runtime!( +construct_runtime!( pub enum Test { System: frame_system, @@ -54,7 +52,7 @@ impl Config for Test { const A: u64 = 1; const B: u64 = 2; -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); let genesis = pallet_balances::GenesisConfig:: { balances: vec![(A, 100), (B, 200)] }; genesis.assimilate_storage(&mut t).unwrap(); diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index 94b057d665d4..94a47e4d96cd 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive", "max-encoded-len"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-timestamp = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-application-crypto = { workspace = true } sp-consensus-aura = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index 01f574a262ad..506c292c837b 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -19,12 +19,12 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-session = { features = [ "historical", ], workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-application-crypto = { workspace = true } sp-authority-discovery = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index 74a4a93147a8..f8b587d44909 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -19,10 +19,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -impl-trait-for-tuples = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +impl-trait-for-tuples = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/authorship/src/lib.rs b/substrate/frame/authorship/src/lib.rs index 1de2262a2014..5c969a3480d4 100644 --- a/substrate/frame/authorship/src/lib.rs +++ b/substrate/frame/authorship/src/lib.rs @@ -67,6 +67,7 @@ pub mod pallet { } #[pallet::storage] + #[pallet::whitelist_storage] /// Author of current block. pub(super) type Author = StorageValue<_, T::AccountId, OptionQuery>; } diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index f0a7f4648c0a..8673e08472eb 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -17,14 +17,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-authorship = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } sp-application-crypto = { features = ["serde"], workspace = true } sp-consensus-babe = { features = ["serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } diff --git a/substrate/frame/babe/src/benchmarking.rs b/substrate/frame/babe/src/benchmarking.rs index 6b0e31e84718..33e275fcb5e3 100644 --- a/substrate/frame/babe/src/benchmarking.rs +++ b/substrate/frame/babe/src/benchmarking.rs @@ -20,14 +20,16 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v2::*; type Header = sp_runtime::generic::Header; -benchmarks! { - check_equivocation_proof { - let x in 0 .. 1; +#[benchmarks] +mod benchmarks { + use super::*; + #[benchmark] + fn check_equivocation_proof(x: Linear<0, 1>) { // NOTE: generated with the test below `test_generate_equivocation_report_blob`. // the output is not deterministic since keys are generated randomly (and therefore // signature content changes). it should not affect the benchmark. @@ -53,22 +55,21 @@ benchmarks! { 124, 11, 167, 227, 103, 88, 78, 23, 228, 33, 96, 41, 207, 183, 227, 189, 114, 70, 254, 30, 128, 243, 233, 83, 214, 45, 74, 182, 120, 119, 64, 243, 219, 119, 63, 240, 205, 123, 231, 82, 205, 174, 143, 70, 2, 86, 182, 20, 16, 141, 145, 91, 116, 195, 58, 223, - 175, 145, 255, 7, 121, 133 + 175, 145, 255, 7, 121, 133, ]; let equivocation_proof1: sp_consensus_babe::EquivocationProof

= Decode::decode(&mut &EQUIVOCATION_PROOF_BLOB[..]).unwrap(); let equivocation_proof2 = equivocation_proof1.clone(); - }: { - sp_consensus_babe::check_equivocation_proof::
(equivocation_proof1); - } verify { + + #[block] + { + sp_consensus_babe::check_equivocation_proof::
(equivocation_proof1); + } + assert!(sp_consensus_babe::check_equivocation_proof::
(equivocation_proof2)); } - impl_benchmark_test_suite!( - Pallet, - crate::mock::new_test_ext(3), - crate::mock::Test, - ) + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(3), crate::mock::Test,); } diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index c2e24c73a7bd..23857470adc4 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -239,7 +239,7 @@ pub fn start_session(session_index: SessionIndex) { /// Progress to the first block at the given era pub fn start_era(era_index: EraIndex) { start_session((era_index * 3).into()); - assert_eq!(Staking::current_era(), Some(era_index)); + assert_eq!(pallet_staking::CurrentEra::::get(), Some(era_index)); } pub fn make_primary_pre_digest( diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index eca958160239..5210d9289bcd 100644 --- a/substrate/frame/babe/src/tests.rs +++ b/substrate/frame/babe/src/tests.rs @@ -414,7 +414,7 @@ fn disabled_validators_cannot_author_blocks() { // so we should still be able to author blocks start_era(2); - assert_eq!(Staking::current_era().unwrap(), 2); + assert_eq!(pallet_staking::CurrentEra::::get().unwrap(), 2); // let's disable the validator at index 0 Session::disable_index(0); diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 647f5d26686a..6b1c4809f773 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -27,14 +27,14 @@ scale-info = { features = [ sp-runtime = { workspace = true } # FRAME +frame-election-provider-support = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -frame-election-provider-support = { workspace = true } # third party -log = { workspace = true } -docify = { workspace = true } aquamarine = { workspace = true } +docify = { workspace = true } +log = { workspace = true } # Optional imports for benchmarking frame-benchmarking = { optional = true, workspace = true } @@ -44,12 +44,12 @@ sp-io = { optional = true, workspace = true } sp-tracing = { optional = true, workspace = true } [dev-dependencies] +frame-benchmarking = { workspace = true, default-features = true } +frame-election-provider-support = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -frame-election-provider-support = { workspace = true, default-features = true } -frame-benchmarking = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/bags-list/fuzzer/Cargo.toml b/substrate/frame/bags-list/fuzzer/Cargo.toml index b52fc8848237..db46bc6fe446 100644 --- a/substrate/frame/bags-list/fuzzer/Cargo.toml +++ b/substrate/frame/bags-list/fuzzer/Cargo.toml @@ -13,10 +13,10 @@ publish = false workspace = true [dependencies] -honggfuzz = { workspace = true } -rand = { features = ["small_rng", "std"], workspace = true, default-features = true } frame-election-provider-support = { features = ["fuzz"], workspace = true, default-features = true } +honggfuzz = { workspace = true } pallet-bags-list = { features = ["fuzz"], workspace = true, default-features = true } +rand = { features = ["small_rng", "std"], workspace = true, default-features = true } [[bin]] name = "bags-list" diff --git a/substrate/frame/bags-list/remote-tests/Cargo.toml b/substrate/frame/bags-list/remote-tests/Cargo.toml index 12d61b61c06d..99b203e73fb0 100644 --- a/substrate/frame/bags-list/remote-tests/Cargo.toml +++ b/substrate/frame/bags-list/remote-tests/Cargo.toml @@ -17,18 +17,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # frame -pallet-staking = { workspace = true, default-features = true } -pallet-bags-list = { features = ["fuzz"], workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +pallet-bags-list = { features = ["fuzz"], workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } # core -sp-storage = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-std = { workspace = true, default-features = true } +sp-storage = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } # utils remote-externalities = { workspace = true, default-features = true } diff --git a/substrate/frame/bags-list/src/weights.rs b/substrate/frame/bags-list/src/weights.rs index 8a5424881e97..52218277a795 100644 --- a/substrate/frame/bags-list/src/weights.rs +++ b/substrate/frame/bags-list/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_bags_list` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -69,10 +69,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1719` + // Measured: `1785` // Estimated: `11506` - // Minimum execution time: 60_062_000 picoseconds. - Weight::from_parts(62_341_000, 11506) + // Minimum execution time: 69_033_000 picoseconds. + Weight::from_parts(71_551_000, 11506) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -86,10 +86,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1613` + // Measured: `1679` // Estimated: `8877` - // Minimum execution time: 57_585_000 picoseconds. - Weight::from_parts(59_480_000, 8877) + // Minimum execution time: 66_157_000 picoseconds. + Weight::from_parts(69_215_000, 8877) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -105,10 +105,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn put_in_front_of() -> Weight { // Proof Size summary in bytes: - // Measured: `1925` + // Measured: `1991` // Estimated: `11506` - // Minimum execution time: 69_552_000 picoseconds. - Weight::from_parts(71_211_000, 11506) + // Minimum execution time: 79_581_000 picoseconds. + Weight::from_parts(81_999_000, 11506) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -126,10 +126,10 @@ impl WeightInfo for () { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1719` + // Measured: `1785` // Estimated: `11506` - // Minimum execution time: 60_062_000 picoseconds. - Weight::from_parts(62_341_000, 11506) + // Minimum execution time: 69_033_000 picoseconds. + Weight::from_parts(71_551_000, 11506) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -143,10 +143,10 @@ impl WeightInfo for () { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1613` + // Measured: `1679` // Estimated: `8877` - // Minimum execution time: 57_585_000 picoseconds. - Weight::from_parts(59_480_000, 8877) + // Minimum execution time: 66_157_000 picoseconds. + Weight::from_parts(69_215_000, 8877) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -162,10 +162,10 @@ impl WeightInfo for () { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn put_in_front_of() -> Weight { // Proof Size summary in bytes: - // Measured: `1925` + // Measured: `1991` // Estimated: `11506` - // Minimum execution time: 69_552_000 picoseconds. - Weight::from_parts(71_211_000, 11506) + // Minimum execution time: 79_581_000 picoseconds. + Weight::from_parts(81_999_000, 11506) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index f0117555c37e..03bc7fcb3fcc 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -17,20 +17,20 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive", "max-encoded-len"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } +docify = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } -docify = { workspace = true } [dev-dependencies] -pallet-transaction-payment = { workspace = true, default-features = true } frame-support = { features = ["experimental"], workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +paste = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -paste = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 65e594a904f9..9d7401452101 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -205,7 +205,7 @@ pub mod pallet { /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::*; - use frame_support::{derive_impl, traits::ConstU64}; + use frame_support::derive_impl; pub struct TestDefaultConfig; @@ -222,7 +222,7 @@ pub mod pallet { type RuntimeFreezeReason = (); type Balance = u64; - type ExistentialDeposit = ConstU64<1>; + type ExistentialDeposit = ConstUint<1>; type ReserveIdentifier = (); type FreezeIdentifier = Self::RuntimeFreezeReason; diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 7fcc49d50aa5..5ad818e5bfa2 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -265,6 +265,7 @@ fn lock_should_work_reserve() { CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); assert!(ChargeTransactionPayment::::validate_and_prepare( @@ -273,6 +274,7 @@ fn lock_should_work_reserve() { CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); }); @@ -296,6 +298,7 @@ fn lock_should_work_tx_fee() { CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); assert!(ChargeTransactionPayment::::validate_and_prepare( @@ -304,6 +307,7 @@ fn lock_should_work_tx_fee() { CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); }); diff --git a/substrate/frame/balances/src/weights.rs b/substrate/frame/balances/src/weights.rs index 55decef273f6..0c7a1354cda0 100644 --- a/substrate/frame/balances/src/weights.rs +++ b/substrate/frame/balances/src/weights.rs @@ -17,27 +17,29 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 42.0.0 -//! DATE: 2024-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `8f4ffe8f7785`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// frame-omni-bencher -// v1 +// ./target/production/substrate-node // benchmark // pallet -// --extrinsic=* -// --runtime=target/release/wbuild/kitchensink-runtime/kitchensink_runtime.wasm -// --pallet=pallet_balances -// --header=/__w/polkadot-sdk/polkadot-sdk/substrate/HEADER-APACHE2 -// --output=/__w/polkadot-sdk/polkadot-sdk/substrate/frame/balances/src/weights.rs -// --wasm-execution=compiled +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_balances +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled // --heap-pages=4096 -// --template=substrate/.maintain/frame-weight-template.hbs +// --output=./substrate/frame/balances/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -69,10 +71,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_allow_death() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `52` // Estimated: `3593` - // Minimum execution time: 75_624_000 picoseconds. - Weight::from_parts(77_290_000, 3593) + // Minimum execution time: 50_023_000 picoseconds. + Weight::from_parts(51_105_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -80,10 +82,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `52` // Estimated: `3593` - // Minimum execution time: 60_398_000 picoseconds. - Weight::from_parts(61_290_000, 3593) + // Minimum execution time: 39_923_000 picoseconds. + Weight::from_parts(40_655_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -91,10 +93,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_creating() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_963_000 picoseconds. - Weight::from_parts(19_802_000, 3593) + // Minimum execution time: 15_062_000 picoseconds. + Weight::from_parts(15_772_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -102,10 +104,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_killing() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 30_517_000 picoseconds. - Weight::from_parts(31_293_000, 3593) + // Minimum execution time: 21_797_000 picoseconds. + Weight::from_parts(22_287_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -113,10 +115,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `155` // Estimated: `6196` - // Minimum execution time: 77_017_000 picoseconds. - Weight::from_parts(78_184_000, 6196) + // Minimum execution time: 51_425_000 picoseconds. + Weight::from_parts(52_600_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,10 +126,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `52` // Estimated: `3593` - // Minimum execution time: 75_600_000 picoseconds. - Weight::from_parts(76_817_000, 3593) + // Minimum execution time: 49_399_000 picoseconds. + Weight::from_parts(51_205_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -135,10 +137,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 24_503_000 picoseconds. - Weight::from_parts(25_026_000, 3593) + // Minimum execution time: 18_119_000 picoseconds. + Weight::from_parts(18_749_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,10 +151,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 24_077_000 picoseconds. - Weight::from_parts(24_339_000, 990) - // Standard Error: 18_669 - .saturating_add(Weight::from_parts(21_570_294, 0).saturating_mul(u.into())) + // Minimum execution time: 16_783_000 picoseconds. + Weight::from_parts(17_076_000, 990) + // Standard Error: 15_126 + .saturating_add(Weight::from_parts(14_834_157, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -161,22 +163,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_070_000 picoseconds. - Weight::from_parts(8_727_000, 0) + // Minimum execution time: 6_048_000 picoseconds. + Weight::from_parts(6_346_000, 0) } fn burn_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 46_978_000 picoseconds. - Weight::from_parts(47_917_000, 0) + // Minimum execution time: 30_215_000 picoseconds. + Weight::from_parts(30_848_000, 0) } fn burn_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 31_141_000 picoseconds. - Weight::from_parts(31_917_000, 0) + // Minimum execution time: 20_813_000 picoseconds. + Weight::from_parts(21_553_000, 0) } } @@ -186,10 +188,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_allow_death() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `52` // Estimated: `3593` - // Minimum execution time: 75_624_000 picoseconds. - Weight::from_parts(77_290_000, 3593) + // Minimum execution time: 50_023_000 picoseconds. + Weight::from_parts(51_105_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -197,10 +199,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `52` // Estimated: `3593` - // Minimum execution time: 60_398_000 picoseconds. - Weight::from_parts(61_290_000, 3593) + // Minimum execution time: 39_923_000 picoseconds. + Weight::from_parts(40_655_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -208,10 +210,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_creating() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_963_000 picoseconds. - Weight::from_parts(19_802_000, 3593) + // Minimum execution time: 15_062_000 picoseconds. + Weight::from_parts(15_772_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -219,10 +221,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_killing() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 30_517_000 picoseconds. - Weight::from_parts(31_293_000, 3593) + // Minimum execution time: 21_797_000 picoseconds. + Weight::from_parts(22_287_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -230,10 +232,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `155` // Estimated: `6196` - // Minimum execution time: 77_017_000 picoseconds. - Weight::from_parts(78_184_000, 6196) + // Minimum execution time: 51_425_000 picoseconds. + Weight::from_parts(52_600_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -241,10 +243,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `52` // Estimated: `3593` - // Minimum execution time: 75_600_000 picoseconds. - Weight::from_parts(76_817_000, 3593) + // Minimum execution time: 49_399_000 picoseconds. + Weight::from_parts(51_205_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -252,10 +254,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `52` + // Measured: `174` // Estimated: `3593` - // Minimum execution time: 24_503_000 picoseconds. - Weight::from_parts(25_026_000, 3593) + // Minimum execution time: 18_119_000 picoseconds. + Weight::from_parts(18_749_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -266,10 +268,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 24_077_000 picoseconds. - Weight::from_parts(24_339_000, 990) - // Standard Error: 18_669 - .saturating_add(Weight::from_parts(21_570_294, 0).saturating_mul(u.into())) + // Minimum execution time: 16_783_000 picoseconds. + Weight::from_parts(17_076_000, 990) + // Standard Error: 15_126 + .saturating_add(Weight::from_parts(14_834_157, 0).saturating_mul(u.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -278,21 +280,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_070_000 picoseconds. - Weight::from_parts(8_727_000, 0) + // Minimum execution time: 6_048_000 picoseconds. + Weight::from_parts(6_346_000, 0) } fn burn_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 46_978_000 picoseconds. - Weight::from_parts(47_917_000, 0) + // Minimum execution time: 30_215_000 picoseconds. + Weight::from_parts(30_848_000, 0) } fn burn_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 31_141_000 picoseconds. - Weight::from_parts(31_917_000, 0) + // Minimum execution time: 20_813_000 picoseconds. + Weight::from_parts(21_553_000, 0) } } diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index d67ac20ee922..54343bb9ce51 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -13,22 +13,22 @@ workspace = true [dependencies] array-bytes = { optional = true, workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } binary-merkle-tree = { workspace = true } +codec = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-beefy = { workspace = true } pallet-mmr = { workspace = true } pallet-session = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } +sp-api = { workspace = true } sp-consensus-beefy = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-api = { workspace = true } sp-state-machine = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/beefy-mmr/src/weights.rs b/substrate/frame/beefy-mmr/src/weights.rs index c292f25400cc..dcfdb560ee94 100644 --- a/substrate/frame/beefy-mmr/src/weights.rs +++ b/substrate/frame/beefy-mmr/src/weights.rs @@ -18,25 +18,27 @@ //! Autogenerated weights for `pallet_beefy_mmr` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-696hpswk-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_beefy_mmr +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_beefy_mmr -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/beefy-mmr/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -61,20 +63,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn extract_validation_context() -> Weight { // Proof Size summary in bytes: - // Measured: `92` + // Measured: `68` // Estimated: `3509` - // Minimum execution time: 7_461_000 picoseconds. - Weight::from_parts(7_669_000, 3509) + // Minimum execution time: 6_687_000 picoseconds. + Weight::from_parts(6_939_000, 3509) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Mmr::Nodes` (r:1 w:0) /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) fn read_peak() -> Weight { // Proof Size summary in bytes: - // Measured: `333` + // Measured: `386` // Estimated: `3505` - // Minimum execution time: 6_137_000 picoseconds. - Weight::from_parts(6_423_000, 3505) + // Minimum execution time: 10_409_000 picoseconds. + Weight::from_parts(10_795_000, 3505) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Mmr::RootHash` (r:1 w:0) @@ -84,12 +86,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[2, 512]`. fn n_items_proof_is_non_canonical(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `378` // Estimated: `1517` - // Minimum execution time: 10_687_000 picoseconds. - Weight::from_parts(14_851_626, 1517) - // Standard Error: 1_455 - .saturating_add(Weight::from_parts(961_703, 0).saturating_mul(n.into())) + // Minimum execution time: 15_459_000 picoseconds. + Weight::from_parts(21_963_366, 1517) + // Standard Error: 1_528 + .saturating_add(Weight::from_parts(984_907, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } } @@ -100,20 +102,20 @@ impl WeightInfo for () { /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn extract_validation_context() -> Weight { // Proof Size summary in bytes: - // Measured: `92` + // Measured: `68` // Estimated: `3509` - // Minimum execution time: 7_461_000 picoseconds. - Weight::from_parts(7_669_000, 3509) + // Minimum execution time: 6_687_000 picoseconds. + Weight::from_parts(6_939_000, 3509) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Mmr::Nodes` (r:1 w:0) /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) fn read_peak() -> Weight { // Proof Size summary in bytes: - // Measured: `333` + // Measured: `386` // Estimated: `3505` - // Minimum execution time: 6_137_000 picoseconds. - Weight::from_parts(6_423_000, 3505) + // Minimum execution time: 10_409_000 picoseconds. + Weight::from_parts(10_795_000, 3505) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Mmr::RootHash` (r:1 w:0) @@ -123,12 +125,12 @@ impl WeightInfo for () { /// The range of component `n` is `[2, 512]`. fn n_items_proof_is_non_canonical(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `325` + // Measured: `378` // Estimated: `1517` - // Minimum execution time: 10_687_000 picoseconds. - Weight::from_parts(14_851_626, 1517) - // Standard Error: 1_455 - .saturating_add(Weight::from_parts(961_703, 0).saturating_mul(n.into())) + // Minimum execution time: 15_459_000 picoseconds. + Weight::from_parts(21_963_366, 1517) + // Standard Error: 1_528 + .saturating_add(Weight::from_parts(984_907, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } } diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index 05af974e89a7..b8e952dfbd66 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -13,13 +13,13 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-authorship = { workspace = true } pallet-session = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } sp-consensus-beefy = { features = ["serde"], workspace = true } sp-runtime = { features = ["serde"], workspace = true } sp-session = { workspace = true } diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 2b75c4107414..7ae41c609180 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -366,5 +366,5 @@ pub fn start_session(session_index: SessionIndex) { pub fn start_era(era_index: EraIndex) { start_session((era_index * 3).into()); - assert_eq!(Staking::current_era(), Some(era_index)); + assert_eq!(pallet_staking::CurrentEra::::get(), Some(era_index)); } diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index d75237205cac..89645d21f6ba 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -313,7 +313,7 @@ fn report_equivocation_current_set_works(mut f: impl ReportEquivocationFn) { let authorities = test_authorities(); ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { - assert_eq!(Staking::current_era(), Some(0)); + assert_eq!(pallet_staking::CurrentEra::::get(), Some(0)); assert_eq!(Session::current_index(), 0); start_era(1); @@ -906,7 +906,7 @@ fn report_fork_voting_invalid_context() { let mut era = 1; let block_num = ext.execute_with(|| { - assert_eq!(Staking::current_era(), Some(0)); + assert_eq!(pallet_staking::CurrentEra::::get(), Some(0)); assert_eq!(Session::current_index(), 0); start_era(era); diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 9ea350a1d290..fabeb9a03195 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -17,14 +17,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } +frame-support = { workspace = true } +frame-support-procedural = { workspace = true } +frame-system = { workspace = true } linregress = { optional = true, workspace = true } log = { workspace = true } paste = { workspace = true, default-features = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, workspace = true, default-features = true } -frame-support = { workspace = true } -frame-support-procedural = { workspace = true } -frame-system = { workspace = true } sp-api = { workspace = true } sp-application-crypto = { workspace = true } sp-core = { workspace = true } @@ -37,7 +37,10 @@ static_assertions = { workspace = true, default-features = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } rusty-fork = { workspace = true } +sc-client-db = { workspace = true } +sp-externalities = { workspace = true } sp-keystore = { workspace = true, default-features = true } +sp-state-machine = { workspace = true } [features] default = ["std"] @@ -53,14 +56,17 @@ std = [ "sp-api/std", "sp-application-crypto/std", "sp-core/std", + "sp-externalities/std", "sp-io/std", "sp-keystore/std", "sp-runtime-interface/std", "sp-runtime/std", + "sp-state-machine/std", "sp-storage/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "sc-client-db/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index ce89dceed3c3..47c6d6e5e4bc 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/benchmarking/src/tests_instance.rs b/substrate/frame/benchmarking/src/tests_instance.rs index ecffbd1a018f..428f29e2bc16 100644 --- a/substrate/frame/benchmarking/src/tests_instance.rs +++ b/substrate/frame/benchmarking/src/tests_instance.rs @@ -61,6 +61,7 @@ mod pallet_test { #[pallet::weight({0})] pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { let _sender = ensure_signed(origin)?; + assert!(n >= T::LowerBound::get()); Value::::put(n); Ok(()) } @@ -81,6 +82,7 @@ frame_support::construct_runtime!( { System: frame_system, TestPallet: pallet_test, + TestPallet2: pallet_test::, } ); @@ -117,6 +119,12 @@ impl pallet_test::Config for Test { type UpperBound = ConstU32<100>; } +impl pallet_test::Config for Test { + type RuntimeEvent = RuntimeEvent; + type LowerBound = ConstU32<50>; + type UpperBound = ConstU32<100>; +} + impl pallet_test::OtherConfig for Test { type OtherEvent = RuntimeEvent; } @@ -130,6 +138,7 @@ mod benchmarks { use crate::account; use frame_support::ensure; use frame_system::RawOrigin; + use sp_core::Get; // Additional used internally by the benchmark macro. use super::pallet_test::{Call, Config, Pallet}; @@ -143,7 +152,7 @@ mod benchmarks { } set_value { - let b in 1 .. 1000; + let b in ( >::LowerBound::get() ) .. ( >::UpperBound::get() ); let caller = account::("caller", 0, 0); }: _ (RawOrigin::Signed(caller), b.into()) verify { @@ -173,3 +182,53 @@ mod benchmarks { ) } } + +#[test] +fn ensure_correct_instance_is_selected() { + use crate::utils::Benchmarking; + + crate::define_benchmarks!( + [pallet_test, TestPallet] + [pallet_test, TestPallet2] + ); + + let whitelist = vec![]; + + let mut batches = Vec::::new(); + let config = crate::BenchmarkConfig { + pallet: "pallet_test".bytes().collect::>(), + // We only want that this `instance` is used. + // Otherwise the wrong components are used. + instance: "TestPallet".bytes().collect::>(), + benchmark: "set_value".bytes().collect::>(), + selected_components: TestPallet::benchmarks(false) + .into_iter() + .find_map(|b| { + if b.name == "set_value".as_bytes() { + Some(b.components.into_iter().map(|c| (c.0, c.1)).collect::>()) + } else { + None + } + }) + .unwrap(), + verify: false, + internal_repeats: 1, + }; + let params = (&config, &whitelist); + + let state = sc_client_db::BenchmarkingState::::new( + Default::default(), + None, + false, + false, + ) + .unwrap(); + + let mut overlay = Default::default(); + let mut ext = sp_state_machine::Ext::new(&mut overlay, &state, None); + sp_externalities::set_and_run_with_externalities(&mut ext, || { + add_benchmarks!(params, batches); + Ok::<_, crate::BenchmarkError>(()) + }) + .unwrap(); +} diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index ca362f7aa7ef..3a10e43d83b8 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -200,6 +200,8 @@ impl From for BenchmarkError { pub struct BenchmarkConfig { /// The encoded name of the pallet to benchmark. pub pallet: Vec, + /// The encoded name of the pallet instance to benchmark. + pub instance: Vec, /// The encoded name of the benchmark/extrinsic to run. pub benchmark: Vec, /// The selected component values to use when running the benchmark. @@ -229,6 +231,7 @@ pub struct BenchmarkMetadata { sp_api::decl_runtime_apis! { /// Runtime api for benchmarking a FRAME runtime. + #[api_version(2)] pub trait Benchmark { /// Get the benchmark metadata available for this runtime. /// @@ -238,7 +241,7 @@ sp_api::decl_runtime_apis! { fn benchmark_metadata(extra: bool) -> (Vec, Vec); /// Dispatch the given benchmark. - fn dispatch_benchmark(config: BenchmarkConfig) -> Result, sp_runtime::RuntimeString>; + fn dispatch_benchmark(config: BenchmarkConfig) -> Result, alloc::string::String>; } } diff --git a/substrate/frame/benchmarking/src/v1.rs b/substrate/frame/benchmarking/src/v1.rs index d687f9fdfa10..64f93b22cf1b 100644 --- a/substrate/frame/benchmarking/src/v1.rs +++ b/substrate/frame/benchmarking/src/v1.rs @@ -1734,8 +1734,8 @@ pub fn show_benchmark_debug_info( components: &[(BenchmarkParameter, u32)], verify: &bool, error_message: &str, -) -> sp_runtime::RuntimeString { - sp_runtime::format_runtime_string!( +) -> alloc::string::String { + alloc::format!( "\n* Pallet: {}\n\ * Benchmark: {}\n\ * Components: {:?}\n\ @@ -1821,12 +1821,13 @@ macro_rules! add_benchmark { let (config, whitelist) = $params; let $crate::BenchmarkConfig { pallet, + instance, benchmark, selected_components, verify, internal_repeats, } = config; - if &pallet[..] == &name_string[..] { + if &pallet[..] == &name_string[..] && &instance[..] == &instance_string[..] { let benchmark_result = <$location>::run_benchmark( &benchmark[..], &selected_components[..], diff --git a/substrate/frame/benchmarking/src/weights.rs b/substrate/frame/benchmarking/src/weights.rs index ea9ef6eb5c6d..e3c4df0bf72a 100644 --- a/substrate/frame/benchmarking/src/weights.rs +++ b/substrate/frame/benchmarking/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `frame_benchmarking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -67,49 +67,49 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 132_000 picoseconds. - Weight::from_parts(160_546, 0) + // Minimum execution time: 157_000 picoseconds. + Weight::from_parts(207_660, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 133_000 picoseconds. - Weight::from_parts(171_395, 0) + // Minimum execution time: 162_000 picoseconds. + Weight::from_parts(211_047, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 126_000 picoseconds. - Weight::from_parts(166_417, 0) + // Minimum execution time: 158_000 picoseconds. + Weight::from_parts(221_118, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 131_000 picoseconds. - Weight::from_parts(166_348, 0) + // Minimum execution time: 160_000 picoseconds. + Weight::from_parts(211_723, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 26_583_601_000 picoseconds. - Weight::from_parts(26_795_212_000, 0) + // Minimum execution time: 24_426_716_000 picoseconds. + Weight::from_parts(24_453_973_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 158_000 picoseconds. - Weight::from_parts(5_277_102, 0) - // Standard Error: 6_279 - .saturating_add(Weight::from_parts(40_610_511, 0).saturating_mul(i.into())) + // Minimum execution time: 210_000 picoseconds. + Weight::from_parts(3_898_542, 0) + // Standard Error: 9_136 + .saturating_add(Weight::from_parts(40_574_115, 0).saturating_mul(i.into())) } } @@ -120,48 +120,48 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 132_000 picoseconds. - Weight::from_parts(160_546, 0) + // Minimum execution time: 157_000 picoseconds. + Weight::from_parts(207_660, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 133_000 picoseconds. - Weight::from_parts(171_395, 0) + // Minimum execution time: 162_000 picoseconds. + Weight::from_parts(211_047, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 126_000 picoseconds. - Weight::from_parts(166_417, 0) + // Minimum execution time: 158_000 picoseconds. + Weight::from_parts(221_118, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 131_000 picoseconds. - Weight::from_parts(166_348, 0) + // Minimum execution time: 160_000 picoseconds. + Weight::from_parts(211_723, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 26_583_601_000 picoseconds. - Weight::from_parts(26_795_212_000, 0) + // Minimum execution time: 24_426_716_000 picoseconds. + Weight::from_parts(24_453_973_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 158_000 picoseconds. - Weight::from_parts(5_277_102, 0) - // Standard Error: 6_279 - .saturating_add(Weight::from_parts(40_610_511, 0).saturating_mul(i.into())) + // Minimum execution time: 210_000 picoseconds. + Weight::from_parts(3_898_542, 0) + // Standard Error: 9_136 + .saturating_add(Weight::from_parts(40_574_115, 0).saturating_mul(i.into())) } } diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index a272153fed07..926af60d1acb 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -19,12 +19,12 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-treasury = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/bounties/src/benchmarking.rs b/substrate/frame/bounties/src/benchmarking.rs index 6fa60e6938b6..b5155909e3cd 100644 --- a/substrate/frame/bounties/src/benchmarking.rs +++ b/substrate/frame/bounties/src/benchmarking.rs @@ -15,9 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! bounties pallet benchmarking. - -#![cfg(feature = "runtime-benchmarks")] +//! Bounties pallet benchmarking. use super::*; @@ -25,7 +23,7 @@ use alloc::{vec, vec::Vec}; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, }; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use frame_system::{pallet_prelude::BlockNumberFor as SystemBlockNumberFor, RawOrigin}; use sp_runtime::traits::{BlockNumberProvider, Bounded}; use crate::Pallet as Bounties; @@ -33,10 +31,20 @@ use pallet_treasury::Pallet as Treasury; const SEED: u32 = 0; -fn set_block_number, I: 'static>(n: BlockNumberFor) { +fn set_block_number, I: 'static>(n: BlockNumberFor) { >::BlockNumberProvider::set_block_number(n); } +fn minimum_balance, I: 'static>() -> BalanceOf { + let minimum_balance = T::Currency::minimum_balance(); + + if minimum_balance.is_zero() { + 1u32.into() + } else { + minimum_balance + } +} + // Create bounties that are approved for use in `on_initialize`. fn create_approved_bounties, I: 'static>(n: u32) -> Result<(), BenchmarkError> { for i in 0..n { @@ -62,12 +70,10 @@ fn setup_bounty, I: 'static>( let fee = value / 2u32.into(); let deposit = T::BountyDepositBase::get() + T::DataDepositPerByte::get() * T::MaximumReasonLength::get().into(); - let _ = T::Currency::make_free_balance_be(&caller, deposit + T::Currency::minimum_balance()); + let _ = T::Currency::make_free_balance_be(&caller, deposit + minimum_balance::()); let curator = account("curator", u, SEED); - let _ = T::Currency::make_free_balance_be( - &curator, - fee / 2u32.into() + T::Currency::minimum_balance(), - ); + let _ = + T::Currency::make_free_balance_be(&curator, fee / 2u32.into() + minimum_balance::()); let reason = vec![0; d as usize]; (caller, curator, fee, value, reason) } @@ -91,7 +97,7 @@ fn create_bounty, I: 'static>( fn setup_pot_account, I: 'static>() { let pot_account = Bounties::::account_id(); - let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into()); + let value = minimum_balance::().saturating_mul(1_000_000_000u32.into()); let _ = T::Currency::make_free_balance_be(&pot_account, value); } @@ -125,6 +131,21 @@ benchmarks_instance_pallet! { Treasury::::on_initialize(frame_system::Pallet::::block_number()); }: _(approve_origin, bounty_id, curator_lookup, fee) + approve_bounty_with_curator { + setup_pot_account::(); + let (caller, curator, fee, value, reason) = setup_bounty::(0, T::MaximumReasonLength::get()); + let curator_lookup = T::Lookup::unlookup(curator.clone()); + Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; + let bounty_id = BountyCount::::get() - 1; + let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + Treasury::::on_initialize(SystemBlockNumberFor::::zero()); + }: _(approve_origin, bounty_id, curator_lookup, fee) + verify { + assert_last_event::( + Event::CuratorProposed { bounty_id, curator }.into() + ); + } + // Worst case when curator is inactive and any sender unassigns the curator. unassign_curator { setup_pot_account::(); diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs index 9d5931f4a608..d9accc5061cf 100644 --- a/substrate/frame/bounties/src/lib.rs +++ b/substrate/frame/bounties/src/lib.rs @@ -73,6 +73,8 @@ //! - `approve_bounty` - Accept a specific treasury amount to be earmarked for a predefined body of //! work. //! - `propose_curator` - Assign an account to a bounty as candidate curator. +//! - `approve_bounty_with_curator` - Accept a specific treasury amount for a predefined body of +//! work with assigned candidate curator account. //! - `accept_curator` - Accept a bounty assignment from the Council, setting a curator deposit. //! - `extend_bounty_expiry` - Extend the expiry block number of the bounty and stay active. //! - `award_bounty` - Close and pay out the specified amount for the completed work. @@ -82,6 +84,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "runtime-benchmarks")] mod benchmarking; pub mod migrations; mod tests; @@ -103,7 +106,9 @@ use sp_runtime::{ use frame_support::{dispatch::DispatchResultWithPostInfo, traits::EnsureOrigin}; use frame_support::pallet_prelude::*; -use frame_system::pallet_prelude::*; +use frame_system::pallet_prelude::{ + ensure_signed, BlockNumberFor as SystemBlockNumberFor, OriginFor, +}; use scale_info::TypeInfo; pub use weights::WeightInfo; @@ -118,6 +123,9 @@ pub type BountyIndex = u32; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type BlockNumberFor = + <>::BlockNumberProvider as BlockNumberProvider>::BlockNumber; + /// A bounty proposal. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Bounty { @@ -174,6 +182,11 @@ pub enum BountyStatus { /// When the bounty can be claimed. unlock_at: BlockNumber, }, + /// The bounty is approved with curator assigned. + ApprovedWithCurator { + /// The assigned curator of this bounty. + curator: AccountId, + }, } /// The child bounty manager. @@ -181,8 +194,11 @@ pub trait ChildBountyManager { /// Get the active child bounties for a parent bounty. fn child_bounties_count(bounty_id: BountyIndex) -> BountyIndex; - /// Get total curator fees of children-bounty curators. + /// Take total curator fees of children-bounty curators. fn children_curator_fees(bounty_id: BountyIndex) -> Balance; + + /// Hook called when a parent bounty is removed. + fn bounty_removed(bounty_id: BountyIndex); } #[frame_support::pallet] @@ -203,11 +219,11 @@ pub mod pallet { /// The delay period for which a bounty beneficiary need to wait before claim the payout. #[pallet::constant] - type BountyDepositPayoutDelay: Get>; + type BountyDepositPayoutDelay: Get>; /// Bounty duration in blocks. #[pallet::constant] - type BountyUpdatePeriod: Get>; + type BountyUpdatePeriod: Get>; /// The curator deposit is calculated as a percentage of the curator fee. /// @@ -316,7 +332,7 @@ pub mod pallet { _, Twox64Concat, BountyIndex, - Bounty, BlockNumberFor>, + Bounty, BlockNumberFor>, >; /// The description of each bounty. @@ -326,6 +342,7 @@ pub mod pallet { /// Bounty indices that have been approved but not yet funded. #[pallet::storage] + #[allow(deprecated)] pub type BountyApprovals, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; @@ -471,6 +488,15 @@ pub mod pallet { // No curator to unassign at this point. return Err(Error::::UnexpectedStatus.into()) }, + BountyStatus::ApprovedWithCurator { ref curator } => { + // Bounty not yet funded, but bounty was approved with curator. + // `RejectOrigin` or curator himself can unassign from this bounty. + ensure!(maybe_sender.map_or(true, |sender| sender == *curator), BadOrigin); + // This state can only be while the bounty is not yet funded so we return + // bounty to the `Approved` state without curator + bounty.status = BountyStatus::Approved; + return Ok(()); + }, BountyStatus::CuratorProposed { ref curator } => { // A curator has been proposed, but not accepted yet. // Either `RejectOrigin` or the proposed curator can unassign the curator. @@ -662,6 +688,7 @@ pub mod pallet { *maybe_bounty = None; BountyDescriptions::::remove(bounty_id); + T::ChildBountyManager::bounty_removed(bounty_id); Self::deposit_event(Event::::BountyClaimed { index: bounty_id, @@ -723,7 +750,7 @@ pub mod pallet { Some(>::WeightInfo::close_bounty_proposed()).into() ) }, - BountyStatus::Approved => { + BountyStatus::Approved | BountyStatus::ApprovedWithCurator { .. } => { // For weight reasons, we don't allow a council to cancel in this phase. // We ask for them to wait until it is funded before they can cancel. return Err(Error::::UnexpectedStatus.into()) @@ -759,7 +786,9 @@ pub mod pallet { AllowDeath, ); // should not fail debug_assert!(res.is_ok()); + *maybe_bounty = None; + T::ChildBountyManager::bounty_removed(bounty_id); Self::deposit_event(Event::::BountyCanceled { index: bounty_id }); Ok(Some(>::WeightInfo::close_bounty_active()).into()) @@ -804,12 +833,58 @@ pub mod pallet { Self::deposit_event(Event::::BountyExtended { index: bounty_id }); Ok(()) } + + /// Approve bountry and propose a curator simultaneously. + /// This call is a shortcut to calling `approve_bounty` and `propose_curator` separately. + /// + /// May only be called from `T::SpendOrigin`. + /// + /// - `bounty_id`: Bounty ID to approve. + /// - `curator`: The curator account whom will manage this bounty. + /// - `fee`: The curator fee. + /// + /// ## Complexity + /// - O(1). + #[pallet::call_index(9)] + #[pallet::weight(>::WeightInfo::approve_bounty_with_curator())] + pub fn approve_bounty_with_curator( + origin: OriginFor, + #[pallet::compact] bounty_id: BountyIndex, + curator: AccountIdLookupOf, + #[pallet::compact] fee: BalanceOf, + ) -> DispatchResult { + let max_amount = T::SpendOrigin::ensure_origin(origin)?; + let curator = T::Lookup::lookup(curator)?; + Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { + // approve bounty + let bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; + ensure!( + bounty.value <= max_amount, + pallet_treasury::Error::::InsufficientPermission + ); + ensure!(bounty.status == BountyStatus::Proposed, Error::::UnexpectedStatus); + ensure!(fee < bounty.value, Error::::InvalidFee); + + BountyApprovals::::try_append(bounty_id) + .map_err(|()| Error::::TooManyQueued)?; + + bounty.status = BountyStatus::ApprovedWithCurator { curator: curator.clone() }; + bounty.fee = fee; + + Ok(()) + })?; + + Self::deposit_event(Event::::BountyApproved { index: bounty_id }); + Self::deposit_event(Event::::CuratorProposed { bounty_id, curator }); + + Ok(()) + } } #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet { + impl, I: 'static> Hooks> for Pallet { #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + fn try_state(_n: SystemBlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { Self::do_try_state() } } @@ -859,7 +934,7 @@ impl, I: 'static> Pallet { /// Get the block number used in the treasury pallet. /// /// It may be configured to use the relay chain block number on a parachain. - pub fn treasury_block_number() -> BlockNumberFor { + pub fn treasury_block_number() -> BlockNumberFor { >::BlockNumberProvider::current_block_number() } @@ -946,7 +1021,13 @@ impl, I: 'static> pallet_treasury::SpendFunds for Pallet ChildBountyManager for () { fn children_curator_fees(_bounty_id: BountyIndex) -> Balance { Zero::zero() } + + fn bounty_removed(_bounty_id: BountyIndex) {} } diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index 37bcadddae5b..447d0edb4122 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -209,16 +209,29 @@ impl ExtBuilder { } } -fn last_event() -> BountiesEvent { - System::events() +fn last_events(n: usize) -> Vec> { + let mut res = System::events() .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Bounties(inner) = e { Some(inner) } else { None }) - .last() - .unwrap() + .rev() + .filter_map( + |e| if let RuntimeEvent::Bounties(inner) = e.event { Some(inner) } else { None }, + ) + .take(n) + .collect::>(); + res.reverse(); + res +} + +fn last_event() -> BountiesEvent { + last_events(1).into_iter().next().unwrap() +} + +fn expect_events(e: Vec>) { + assert_eq!(last_events(e.len()), e); } #[test] +#[allow(deprecated)] fn genesis_config_works() { ExtBuilder::default().build_and_execute(|| { assert_eq!(Treasury::pot(), 0); @@ -236,6 +249,7 @@ fn minting_works() { } #[test] +#[allow(deprecated)] fn accepted_spend_proposal_ignored_outside_spend_period() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -262,6 +276,7 @@ fn unused_pot_should_diminish() { } #[test] +#[allow(deprecated)] fn accepted_spend_proposal_enacted_on_spend_period() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -276,6 +291,7 @@ fn accepted_spend_proposal_enacted_on_spend_period() { } #[test] +#[allow(deprecated)] fn pot_underflow_should_not_diminish() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -296,6 +312,7 @@ fn pot_underflow_should_not_diminish() { // Treasury account doesn't get deleted if amount approved to spend is all its free balance. // i.e. pot should not include existential deposit needed for account survival. #[test] +#[allow(deprecated)] fn treasury_account_doesnt_get_deleted() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -318,6 +335,7 @@ fn treasury_account_doesnt_get_deleted() { // In case treasury account is not existing then it works fine. // This is useful for chain that will just update runtime. #[test] +#[allow(deprecated)] fn inexistent_account_works() { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(0, 100), (1, 99), (2, 1)] } @@ -411,6 +429,7 @@ fn propose_bounty_validation_works() { } #[test] +#[allow(deprecated)] fn close_bounty_works() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -1181,3 +1200,212 @@ fn propose_curator_instance1_insufficient_spend_limit_errors() { ); }); } + +#[test] +fn approve_bounty_with_curator_works() { + ExtBuilder::default().build_and_execute(|| { + let fee = 10; + let curator = 4; + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_noop!( + Bounties::approve_bounty_with_curator(RuntimeOrigin::signed(1), 0, curator, 10), + BadOrigin + ); + + SpendLimit::set(1); + assert_noop!( + Bounties::approve_bounty_with_curator(RuntimeOrigin::root(), 0, curator, 10), + TreasuryError::InsufficientPermission + ); + SpendLimit::set(u64::MAX); + + assert_noop!( + Bounties::approve_bounty_with_curator(RuntimeOrigin::root(), 0, curator, 51), + Error::::InvalidFee + ); + + assert_eq!(pallet_bounties::BountyApprovals::::get().len(), 0); + assert_ok!(Bounties::approve_bounty_with_curator(RuntimeOrigin::root(), 0, curator, 10)); + assert_eq!(pallet_bounties::BountyApprovals::::get().len(), 1); + + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::ApprovedWithCurator { curator }, + } + ); + + expect_events(vec![ + BountiesEvent::BountyApproved { index: 0 }, + BountiesEvent::CuratorProposed { bounty_id: 0, curator }, + ]); + + assert_noop!( + Bounties::approve_bounty_with_curator(RuntimeOrigin::root(), 0, curator, 10), + Error::::UnexpectedStatus + ); + + System::set_block_number(2); + >::on_initialize(2); + assert_eq!(pallet_bounties::BountyApprovals::::get().len(), 0); + + expect_events(vec![BountiesEvent::BountyBecameActive { index: 0 }]); + + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::CuratorProposed { curator }, + } + ); + + assert_noop!( + Bounties::accept_curator(RuntimeOrigin::signed(curator), 0), + pallet_balances::Error::::InsufficientBalance + ); + Balances::make_free_balance_be(&curator, 6); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(curator), 0)); + + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 5, + value: 50, + bond: 85, + status: BountyStatus::Active { curator, update_due: 22 }, + } + ); + + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(curator), 0, 5)); + System::set_block_number(5); + >::on_initialize(5); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(curator), 0)); + assert_eq!( + last_event(), + BountiesEvent::BountyClaimed { index: 0, payout: 40, beneficiary: 5 } + ); + assert_eq!(Balances::free_balance(5), 40); // 50 - 10 + }); +} + +#[test] +fn approve_bounty_with_curator_early_unassign_works() { + ExtBuilder::default().build_and_execute(|| { + let fee = 10; + let curator = 4; + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty_with_curator(RuntimeOrigin::root(), 0, curator, 10)); + + // unassign curator while bounty is not yet funded + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); + + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::Approved, + } + ); + + assert_eq!(last_event(), BountiesEvent::CuratorUnassigned { bounty_id: 0 }); + + System::set_block_number(2); + >::on_initialize(2); + assert_eq!(last_event(), BountiesEvent::BountyBecameActive { index: 0 }); + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::Funded, + } + ); + + // assign curator again through separate process + let new_fee = 15; + let new_curator = 5; + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, new_curator, new_fee)); + + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee: new_fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::CuratorProposed { curator: new_curator }, + } + ); + assert_eq!( + last_event(), + BountiesEvent::CuratorProposed { bounty_id: 0, curator: new_curator } + ); + }); +} + +#[test] +fn approve_bounty_with_curator_proposed_unassign_works() { + ExtBuilder::default().build_and_execute(|| { + let fee = 10; + let curator = 4; + System::set_block_number(1); + Balances::make_free_balance_be(&Treasury::account_id(), 101); + + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty_with_curator(RuntimeOrigin::root(), 0, curator, 10)); + + System::set_block_number(2); + >::on_initialize(2); + + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::CuratorProposed { curator }, + } + ); + + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(curator), 0)); + assert_eq!( + pallet_bounties::Bounties::::get(0).unwrap(), + Bounty { + proposer: 0, + fee, + curator_deposit: 0, + value: 50, + bond: 85, + status: BountyStatus::Funded, + } + ); + assert_eq!(last_event(), BountiesEvent::CuratorUnassigned { bounty_id: 0 }); + }); +} diff --git a/substrate/frame/bounties/src/weights.rs b/substrate/frame/bounties/src/weights.rs index c9f551ec9bb2..1df6d3143edb 100644 --- a/substrate/frame/bounties/src/weights.rs +++ b/substrate/frame/bounties/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_bounties` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -54,6 +54,7 @@ pub trait WeightInfo { fn propose_bounty(d: u32, ) -> Weight; fn approve_bounty() -> Weight; fn propose_curator() -> Weight; + fn approve_bounty_with_curator() -> Weight; fn unassign_curator() -> Weight; fn accept_curator() -> Weight; fn award_bounty() -> Weight; @@ -78,12 +79,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `309` + // Measured: `342` // Estimated: `3593` - // Minimum execution time: 25_206_000 picoseconds. - Weight::from_parts(26_925_800, 3593) - // Standard Error: 239 - .saturating_add(Weight::from_parts(501, 0).saturating_mul(d.into())) + // Minimum execution time: 27_112_000 picoseconds. + Weight::from_parts(28_480_264, 3593) + // Standard Error: 167 + .saturating_add(Weight::from_parts(755, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -93,10 +94,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `401` + // Measured: `434` // Estimated: `3642` - // Minimum execution time: 13_150_000 picoseconds. - Weight::from_parts(13_708_000, 3642) + // Minimum execution time: 14_400_000 picoseconds. + Weight::from_parts(14_955_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -104,23 +105,36 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `454` // Estimated: `3642` - // Minimum execution time: 12_277_000 picoseconds. - Weight::from_parts(12_769_000, 3642) + // Minimum execution time: 17_380_000 picoseconds. + Weight::from_parts(18_234_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyApprovals` (r:1 w:1) + /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn approve_bounty_with_curator() -> Weight { + // Proof Size summary in bytes: + // Measured: `434` + // Estimated: `3642` + // Minimum execution time: 19_733_000 picoseconds. + Weight::from_parts(21_051_000, 3642) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `630` // Estimated: `3642` - // Minimum execution time: 29_041_000 picoseconds. - Weight::from_parts(29_979_000, 3642) + // Minimum execution time: 44_620_000 picoseconds. + Weight::from_parts(45_529_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -130,10 +144,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `593` + // Measured: `626` // Estimated: `3642` - // Minimum execution time: 27_936_000 picoseconds. - Weight::from_parts(28_925_000, 3642) + // Minimum execution time: 34_825_000 picoseconds. + Weight::from_parts(36_092_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -143,10 +157,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `638` // Estimated: `3642` - // Minimum execution time: 16_759_000 picoseconds. - Weight::from_parts(17_699_000, 3642) + // Minimum execution time: 22_985_000 picoseconds. + Weight::from_parts(23_657_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -158,14 +172,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentTotalChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `1036` // Estimated: `8799` - // Minimum execution time: 112_056_000 picoseconds. - Weight::from_parts(114_275_000, 8799) + // Minimum execution time: 119_682_000 picoseconds. + Weight::from_parts(122_515_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) @@ -177,38 +195,40 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `649` + // Measured: `682` // Estimated: `3642` - // Minimum execution time: 32_625_000 picoseconds. - Weight::from_parts(33_719_000, 3642) + // Minimum execution time: 47_430_000 picoseconds. + Weight::from_parts(48_592_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentTotalChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `885` + // Measured: `952` // Estimated: `6196` - // Minimum execution time: 76_895_000 picoseconds. - Weight::from_parts(79_161_000, 6196) + // Minimum execution time: 85_520_000 picoseconds. + Weight::from_parts(87_644_000, 6196) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `457` + // Measured: `490` // Estimated: `3642` - // Minimum execution time: 12_635_000 picoseconds. - Weight::from_parts(13_423_000, 3642) + // Minimum execution time: 18_145_000 picoseconds. + Weight::from_parts(18_727_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -221,12 +241,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `37 + b * (297 ±0)` + // Measured: `71 + b * (298 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 2_840_000 picoseconds. - Weight::from_parts(6_076_743, 1887) - // Standard Error: 18_569 - .saturating_add(Weight::from_parts(34_771_846, 0).saturating_mul(b.into())) + // Minimum execution time: 3_649_000 picoseconds. + Weight::from_parts(3_727_000, 1887) + // Standard Error: 8_881 + .saturating_add(Weight::from_parts(35_199_034, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -248,12 +268,12 @@ impl WeightInfo for () { /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `309` + // Measured: `342` // Estimated: `3593` - // Minimum execution time: 25_206_000 picoseconds. - Weight::from_parts(26_925_800, 3593) - // Standard Error: 239 - .saturating_add(Weight::from_parts(501, 0).saturating_mul(d.into())) + // Minimum execution time: 27_112_000 picoseconds. + Weight::from_parts(28_480_264, 3593) + // Standard Error: 167 + .saturating_add(Weight::from_parts(755, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -263,10 +283,10 @@ impl WeightInfo for () { /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `401` + // Measured: `434` // Estimated: `3642` - // Minimum execution time: 13_150_000 picoseconds. - Weight::from_parts(13_708_000, 3642) + // Minimum execution time: 14_400_000 picoseconds. + Weight::from_parts(14_955_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -274,23 +294,36 @@ impl WeightInfo for () { /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `454` // Estimated: `3642` - // Minimum execution time: 12_277_000 picoseconds. - Weight::from_parts(12_769_000, 3642) + // Minimum execution time: 17_380_000 picoseconds. + Weight::from_parts(18_234_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyApprovals` (r:1 w:1) + /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn approve_bounty_with_curator() -> Weight { + // Proof Size summary in bytes: + // Measured: `434` + // Estimated: `3642` + // Minimum execution time: 19_733_000 picoseconds. + Weight::from_parts(21_051_000, 3642) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `630` // Estimated: `3642` - // Minimum execution time: 29_041_000 picoseconds. - Weight::from_parts(29_979_000, 3642) + // Minimum execution time: 44_620_000 picoseconds. + Weight::from_parts(45_529_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -300,10 +333,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `593` + // Measured: `626` // Estimated: `3642` - // Minimum execution time: 27_936_000 picoseconds. - Weight::from_parts(28_925_000, 3642) + // Minimum execution time: 34_825_000 picoseconds. + Weight::from_parts(36_092_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -313,10 +346,10 @@ impl WeightInfo for () { /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `638` // Estimated: `3642` - // Minimum execution time: 16_759_000 picoseconds. - Weight::from_parts(17_699_000, 3642) + // Minimum execution time: 22_985_000 picoseconds. + Weight::from_parts(23_657_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -328,14 +361,18 @@ impl WeightInfo for () { /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentTotalChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `1036` // Estimated: `8799` - // Minimum execution time: 112_056_000 picoseconds. - Weight::from_parts(114_275_000, 8799) + // Minimum execution time: 119_682_000 picoseconds. + Weight::from_parts(122_515_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) @@ -347,38 +384,40 @@ impl WeightInfo for () { /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `649` + // Measured: `682` // Estimated: `3642` - // Minimum execution time: 32_625_000 picoseconds. - Weight::from_parts(33_719_000, 3642) + // Minimum execution time: 47_430_000 picoseconds. + Weight::from_parts(48_592_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentTotalChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `885` + // Measured: `952` // Estimated: `6196` - // Minimum execution time: 76_895_000 picoseconds. - Weight::from_parts(79_161_000, 6196) + // Minimum execution time: 85_520_000 picoseconds. + Weight::from_parts(87_644_000, 6196) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Bounties::Bounties` (r:1 w:1) /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `457` + // Measured: `490` // Estimated: `3642` - // Minimum execution time: 12_635_000 picoseconds. - Weight::from_parts(13_423_000, 3642) + // Minimum execution time: 18_145_000 picoseconds. + Weight::from_parts(18_727_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -391,12 +430,12 @@ impl WeightInfo for () { /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `37 + b * (297 ±0)` + // Measured: `71 + b * (298 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 2_840_000 picoseconds. - Weight::from_parts(6_076_743, 1887) - // Standard Error: 18_569 - .saturating_add(Weight::from_parts(34_771_846, 0).saturating_mul(b.into())) + // Minimum execution time: 3_649_000 picoseconds. + Weight::from_parts(3_727_000, 1887) + // Standard Error: 8_881 + .saturating_add(Weight::from_parts(35_199_034, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index aead49013ef0..a4cfe49d3b35 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -15,22 +15,22 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = { workspace = true } +bitvec = { workspace = true } codec = { features = ["derive"], workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +log = { workspace = true } scale-info = { features = ["derive"], workspace = true } -bitvec = { workspace = true } sp-api = { workspace = true } sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } [dev-dependencies] +pretty_assertions = { workspace = true } sp-io = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -pretty_assertions = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/broker/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs index 595bf564f7e1..516518740f7d 100644 --- a/substrate/frame/broker/src/benchmarking.rs +++ b/substrate/frame/broker/src/benchmarking.rs @@ -30,11 +30,11 @@ use frame_support::{ }, }; use frame_system::{Pallet as System, RawOrigin}; -use sp_arithmetic::{traits::Zero, Perbill}; +use sp_arithmetic::Perbill; use sp_core::Get; use sp_runtime::{ traits::{BlockNumberProvider, MaybeConvert}, - SaturatedConversion, Saturating, + Saturating, }; const SEED: u32 = 0; @@ -217,9 +217,11 @@ mod benches { _(origin as T::RuntimeOrigin, initial_price, extra_cores.try_into().unwrap()); assert!(SaleInfo::::get().is_some()); + let sale_start = RCBlockNumberProviderOf::::current_block_number() + + config.interlude_length; assert_last_event::( Event::SaleInitialized { - sale_start: 2u32.into(), + sale_start, leadin_length: 1u32.into(), start_price: 1_000_000_000u32.into(), end_price: 10_000_000u32.into(), @@ -285,7 +287,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); Broker::::do_assign(region, None, 1001, Final) .map_err(|_| BenchmarkError::Weightless)?; @@ -314,7 +316,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); let recipient: T::AccountId = account("recipient", 0, SEED); @@ -347,7 +349,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); #[extrinsic_call] _(RawOrigin::Signed(caller), region, 2); @@ -379,7 +381,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); #[extrinsic_call] _(RawOrigin::Signed(caller), region, 0x00000_fffff_fffff_00000.into()); @@ -415,7 +417,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); #[extrinsic_call] _(RawOrigin::Signed(caller), region, 1000, Provisional); @@ -450,7 +452,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); let recipient: T::AccountId = account("recipient", 0, SEED); @@ -490,7 +492,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); let recipient: T::AccountId = account("recipient", 0, SEED); T::Currency::set_balance(&recipient.clone(), T::Currency::minimum_balance()); @@ -546,7 +548,7 @@ mod benches { T::Currency::set_balance(&Broker::::account_id(), T::Currency::minimum_balance()); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); let recipient: T::AccountId = account("recipient", 0, SEED); @@ -580,7 +582,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); advance_to::( (T::TimeslicePeriod::get() * (region_len * 4).into()).try_into().ok().unwrap(), @@ -614,7 +616,7 @@ mod benches { ); let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + .expect("Offer not high enough for configuration."); let recipient: T::AccountId = account("recipient", 0, SEED); @@ -784,78 +786,97 @@ mod benches { #[benchmark] fn rotate_sale(n: Linear<0, { MAX_CORE_COUNT.into() }>) -> Result<(), BenchmarkError> { - let core_count = n.try_into().unwrap(); let config = new_config_record::(); + Configuration::::put(config.clone()); - let now = frame_system::Pallet::::block_number(); - let end_price = 10_000_000u32.into(); - let commit_timeslice = Broker::::latest_timeslice_ready_to_commit(&config); - let sale = SaleInfoRecordOf:: { - sale_start: now, - leadin_length: Zero::zero(), - end_price, - sellout_price: None, - region_begin: commit_timeslice, - region_end: commit_timeslice.saturating_add(config.region_length), - first_core: 0, - ideal_cores_sold: 0, - cores_offered: 0, - cores_sold: 0, - }; - - let status = StatusRecord { - core_count, - private_pool_size: 0, - system_pool_size: 0, - last_committed_timeslice: commit_timeslice.saturating_sub(1), - last_timeslice: Broker::::current_timeslice(), - }; + // Ensure there is one buyable core then use the rest to max out reservations and leases, if + // possible for worst case. + + // First allocate up to MaxReservedCores for reservations + let n_reservations = T::MaxReservedCores::get().min(n.saturating_sub(1)); + setup_reservations::(n_reservations); + // Then allocate remaining cores to leases, up to MaxLeasedCores + let n_leases = + T::MaxLeasedCores::get().min(n.saturating_sub(1).saturating_sub(n_reservations)); + setup_leases::(n_leases, 1, 20); + + // Start sales so we can test the auto-renewals. + Broker::::do_start_sales( + 10_000_000u32.into(), + n.saturating_sub(n_reservations) + .saturating_sub(n_leases) + .try_into() + .expect("Upper limit of n is a u16."), + ) + .expect("Configuration was initialized before; qed"); + + // Advance to the fixed price period. + advance_to::(2); - // Assume Reservations to be filled for worst case - setup_reservations::(T::MaxReservedCores::get()); + // Assume max auto renewals for worst case. This is between 1 and the value of + // MaxAutoRenewals. + let n_renewable = T::MaxAutoRenewals::get() + .min(n.saturating_sub(n_leases).saturating_sub(n_reservations)); - // Assume Leases to be filled for worst case - setup_leases::(T::MaxLeasedCores::get(), 1, 10); + let timeslice_period: u32 = T::TimeslicePeriod::get().try_into().ok().unwrap(); + let sale = SaleInfo::::get().expect("Sale has started."); - // Assume max auto renewals for worst case. - (0..T::MaxAutoRenewals::get()).try_for_each(|indx| -> Result<(), BenchmarkError> { + (0..n_renewable.into()).try_for_each(|indx| -> Result<(), BenchmarkError> { let task = 1000 + indx; let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(task) .expect("Failed to get sovereign account"); T::Currency::set_balance( &caller.clone(), - T::Currency::minimum_balance().saturating_add(100u32.into()), + T::Currency::minimum_balance().saturating_add(100_000_000u32.into()), ); - let region = Broker::::do_purchase(caller.clone(), 10u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) + .expect("Offer not high enough for configuration."); Broker::::do_assign(region, None, task, Final) .map_err(|_| BenchmarkError::Weightless)?; - Broker::::do_enable_auto_renew(caller, region.core, task, None)?; + Broker::::do_enable_auto_renew(caller, region.core, task, Some(sale.region_end))?; Ok(()) })?; + // Advance to the block before the rotate_sale in which the auto-renewals will take place. + let rotate_block = timeslice_period.saturating_mul(config.region_length) - 2; + advance_to::(rotate_block - 1); + + // Advance one block and manually tick so we can isolate the `rotate_sale` call. + System::::set_block_number(rotate_block.into()); + RCBlockNumberProviderOf::::set_block_number(rotate_block.into()); + let mut status = Status::::get().expect("Sale has started."); + let sale = SaleInfo::::get().expect("Sale has started."); + Broker::::process_core_count(&mut status); + Broker::::process_revenue(); + status.last_committed_timeslice = config.region_length; + #[block] { Broker::::rotate_sale(sale.clone(), &config, &status); } - assert!(SaleInfo::::get().is_some()); - assert_last_event::( + // Get prices from the actual price adapter. + let new_prices = T::PriceAdapter::adapt_price(SalePerformance::from_sale(&sale)); + let new_sale = SaleInfo::::get().expect("Sale has started."); + let now = RCBlockNumberProviderOf::::current_block_number(); + let sale_start = config.interlude_length.saturating_add(rotate_block.into()); + + assert_has_event::( Event::SaleInitialized { - sale_start: 2u32.into(), + sale_start, leadin_length: 1u32.into(), - start_price: 1_000_000_000u32.into(), - end_price: 10_000_000u32.into(), + start_price: Broker::::sale_price(&new_sale, now), + end_price: new_prices.end_price, region_begin: sale.region_begin + config.region_length, region_end: sale.region_end + config.region_length, ideal_cores_sold: 0, cores_offered: n - .saturating_sub(T::MaxReservedCores::get()) - .saturating_sub(T::MaxLeasedCores::get()) + .saturating_sub(n_reservations) + .saturating_sub(n_leases) .try_into() .unwrap(), } @@ -863,18 +884,18 @@ mod benches { ); // Make sure all cores got renewed: - (0..T::MaxAutoRenewals::get()).for_each(|indx| { + (0..n_renewable).for_each(|indx| { let task = 1000 + indx; let who = T::SovereignAccountOf::maybe_convert(task) .expect("Failed to get sovereign account"); assert_has_event::( Event::Renewed { who, - old_core: 10 + indx as u16, // first ten cores are allocated to leases. - core: 10 + indx as u16, - price: 10u32.saturated_into(), - begin: 7, - duration: 3, + old_core: n_reservations as u16 + n_leases as u16 + indx as u16, + core: n_reservations as u16 + n_leases as u16 + indx as u16, + price: 10_000_000u32.into(), + begin: new_sale.region_begin, + duration: config.region_length, workload: Schedule::truncate_from(vec![ScheduleItem { assignment: Task(task), mask: CoreMask::complete(), @@ -995,6 +1016,47 @@ mod benches { Ok(()) } + #[benchmark] + fn force_reserve() -> Result<(), BenchmarkError> { + Configuration::::put(new_config_record::()); + // Assume Reservations to be almost filled for worst case. + let reservation_count = T::MaxReservedCores::get().saturating_sub(1); + setup_reservations::(reservation_count); + + // Assume leases to be filled for worst case + setup_leases::(T::MaxLeasedCores::get(), 1, 10); + + let origin = + T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + // Sales must be started. + Broker::::do_start_sales(100u32.into(), CoreIndex::try_from(reservation_count).unwrap()) + .map_err(|_| BenchmarkError::Weightless)?; + + // Add a core. + let status = Status::::get().unwrap(); + Broker::::do_request_core_count(status.core_count + 1).unwrap(); + + advance_to::(T::TimeslicePeriod::get().try_into().ok().unwrap()); + let schedule = new_schedule(); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, schedule.clone(), status.core_count); + + assert_eq!(Reservations::::decode_len().unwrap(), T::MaxReservedCores::get() as usize); + + let sale_info = SaleInfo::::get().unwrap(); + assert_eq!( + Workplan::::get((sale_info.region_begin, status.core_count)), + Some(schedule.clone()) + ); + // We called at timeslice 1, therefore 2 was already processed and 3 is the next possible + // assignment point. + assert_eq!(Workplan::::get((3, status.core_count)), Some(schedule)); + + Ok(()) + } + #[benchmark] fn swap_leases() -> Result<(), BenchmarkError> { let admin_origin = @@ -1014,56 +1076,62 @@ mod benches { #[benchmark] fn enable_auto_renew() -> Result<(), BenchmarkError> { - let _core = setup_and_start_sale::()?; + let _core_id = setup_and_start_sale::()?; advance_to::(2); + let sale = SaleInfo::::get().expect("Sale has already started."); // We assume max auto renewals for worst case. (0..T::MaxAutoRenewals::get() - 1).try_for_each(|indx| -> Result<(), BenchmarkError> { let task = 1000 + indx; let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(task) .expect("Failed to get sovereign account"); + // Sovereign account needs sufficient funds to purchase and renew. T::Currency::set_balance( &caller.clone(), - T::Currency::minimum_balance().saturating_add(100u32.into()), + T::Currency::minimum_balance().saturating_add(100_000_000u32.into()), ); - let region = Broker::::do_purchase(caller.clone(), 10u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) + .expect("Offer not high enough for configuration."); Broker::::do_assign(region, None, task, Final) .map_err(|_| BenchmarkError::Weightless)?; - Broker::::do_enable_auto_renew(caller, region.core, task, Some(7))?; + Broker::::do_enable_auto_renew(caller, region.core, task, Some(sale.region_end))?; Ok(()) })?; let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(2001).expect("Failed to get sovereign account"); + // Sovereign account needs sufficient funds to purchase and renew. T::Currency::set_balance( &caller.clone(), - T::Currency::minimum_balance().saturating_add(100u32.into()), + T::Currency::minimum_balance().saturating_add(100_000_000u32.into()), ); // The region for which we benchmark enable auto renew. - let region = Broker::::do_purchase(caller.clone(), 10u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) + .expect("Offer not high enough for configuration."); Broker::::do_assign(region, None, 2001, Final) .map_err(|_| BenchmarkError::Weightless)?; // The most 'intensive' path is when we renew the core upon enabling auto-renewal. // Therefore, we advance to next bulk sale: - advance_to::(6); + let timeslice_period: u32 = T::TimeslicePeriod::get().try_into().ok().unwrap(); + let config = Configuration::::get().expect("Already configured."); + advance_to::(config.region_length * timeslice_period); #[extrinsic_call] _(RawOrigin::Signed(caller), region.core, 2001, None); assert_last_event::(Event::AutoRenewalEnabled { core: region.core, task: 2001 }.into()); // Make sure we indeed renewed: + let sale = SaleInfo::::get().expect("Sales have started."); assert!(PotentialRenewals::::get(PotentialRenewalId { core: region.core, - when: 10 // region end after renewal + when: sale.region_end, }) .is_some()); @@ -1072,37 +1140,41 @@ mod benches { #[benchmark] fn disable_auto_renew() -> Result<(), BenchmarkError> { - let _core = setup_and_start_sale::()?; + let core_id = setup_and_start_sale::()?; advance_to::(2); + let sale = SaleInfo::::get().expect("Sale has already started."); // We assume max auto renewals for worst case. - (0..T::MaxAutoRenewals::get() - 1).try_for_each(|indx| -> Result<(), BenchmarkError> { + (0..T::MaxAutoRenewals::get()).try_for_each(|indx| -> Result<(), BenchmarkError> { let task = 1000 + indx; let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(task) .expect("Failed to get sovereign account"); T::Currency::set_balance( &caller.clone(), - T::Currency::minimum_balance().saturating_add(100u32.into()), + T::Currency::minimum_balance().saturating_add(10_000_000u32.into()), ); - let region = Broker::::do_purchase(caller.clone(), 10u32.into()) - .map_err(|_| BenchmarkError::Weightless)?; + let region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) + .expect("Offer not high enough for configuration."); Broker::::do_assign(region, None, task, Final) .map_err(|_| BenchmarkError::Weightless)?; - Broker::::do_enable_auto_renew(caller, region.core, task, Some(7))?; + Broker::::do_enable_auto_renew(caller, region.core, task, Some(sale.region_end))?; Ok(()) })?; + let task = 1000; + let caller: T::AccountId = - T::SovereignAccountOf::maybe_convert(1000).expect("Failed to get sovereign account"); + T::SovereignAccountOf::maybe_convert(task).expect("Failed to get sovereign account"); + #[extrinsic_call] - _(RawOrigin::Signed(caller), _core, 1000); + _(RawOrigin::Signed(caller), core_id, task); - assert_last_event::(Event::AutoRenewalDisabled { core: _core, task: 1000 }.into()); + assert_last_event::(Event::AutoRenewalDisabled { core: core_id, task }.into()); Ok(()) } @@ -1116,11 +1188,11 @@ mod benches { let caller: T::AccountId = whitelisted_caller(); T::Currency::set_balance( &caller.clone(), - T::Currency::minimum_balance().saturating_add(u32::MAX.into()), + T::Currency::minimum_balance().saturating_add(10_000_000u32.into()), ); - let _region = Broker::::do_purchase(caller.clone(), (u32::MAX / 2).into()) - .map_err(|_| BenchmarkError::Weightless)?; + let _region = Broker::::do_purchase(caller.clone(), 10_000_000u32.into()) + .expect("Offer not high enough for configuration."); let timeslice = Broker::::current_timeslice(); diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index 5fbd957d7908..489be12bdd15 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -21,7 +21,7 @@ use frame_support::{ traits::{fungible::Mutate, tokens::Preservation::Expendable, DefensiveResult}, }; use sp_arithmetic::traits::{CheckedDiv, Saturating, Zero}; -use sp_runtime::traits::Convert; +use sp_runtime::traits::{BlockNumberProvider, Convert}; use CompletionStatus::{Complete, Partial}; impl Pallet { @@ -60,6 +60,27 @@ impl Pallet { Ok(()) } + pub(crate) fn do_force_reserve(workload: Schedule, core: CoreIndex) -> DispatchResult { + // Sales must have started, otherwise reserve is equivalent. + let sale = SaleInfo::::get().ok_or(Error::::NoSales)?; + + // Reserve - starts at second sale period boundary from now. + Self::do_reserve(workload.clone())?; + + // Add to workload - grants one region from the next sale boundary. + Workplan::::insert((sale.region_begin, core), &workload); + + // Assign now until the next sale boundary unless the next timeslice is already the sale + // boundary. + let status = Status::::get().ok_or(Error::::Uninitialized)?; + let timeslice = status.last_committed_timeslice.saturating_add(1); + if timeslice < sale.region_begin { + Workplan::::insert((timeslice, core), &workload); + } + + Ok(()) + } + pub(crate) fn do_set_lease(task: TaskId, until: Timeslice) -> DispatchResult { let mut r = Leases::::get(); ensure!(until > Self::current_timeslice(), Error::::AlreadyExpired); @@ -91,7 +112,7 @@ impl Pallet { last_committed_timeslice: commit_timeslice.saturating_sub(1), last_timeslice: Self::current_timeslice(), }; - let now = frame_system::Pallet::::block_number(); + let now = RCBlockNumberProviderOf::::current_block_number(); // Imaginary old sale for bootstrapping the first actual sale: let old_sale = SaleInfoRecord { sale_start: now, @@ -119,7 +140,7 @@ impl Pallet { let mut sale = SaleInfo::::get().ok_or(Error::::NoSales)?; Self::ensure_cores_for_sale(&status, &sale)?; - let now = frame_system::Pallet::::block_number(); + let now = RCBlockNumberProviderOf::::current_block_number(); ensure!(now > sale.sale_start, Error::::TooEarly); let price = Self::sale_price(&sale, now); ensure!(price_limit >= price, Error::::Overpriced); @@ -171,7 +192,7 @@ impl Pallet { let begin = sale.region_end; let price_cap = record.price + config.renewal_bump * record.price; - let now = frame_system::Pallet::::block_number(); + let now = RCBlockNumberProviderOf::::current_block_number(); let price = Self::sale_price(&sale, now).min(price_cap); log::debug!( "Renew with: sale price: {:?}, price cap: {:?}, old price: {:?}", @@ -569,7 +590,7 @@ impl Pallet { Self::ensure_cores_for_sale(&status, &sale)?; - let now = frame_system::Pallet::::block_number(); + let now = RCBlockNumberProviderOf::::current_block_number(); Ok(Self::sale_price(&sale, now)) } } diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs index 10745544fadf..01368fd6404d 100644 --- a/substrate/frame/broker/src/lib.rs +++ b/substrate/frame/broker/src/lib.rs @@ -67,7 +67,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; use sp_runtime::traits::{Convert, ConvertBack, MaybeConvert}; - const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -305,10 +305,11 @@ pub mod pallet { }, /// A new sale has been initialized. SaleInitialized { - /// The local block number at which the sale will/did start. - sale_start: BlockNumberFor, - /// The length in blocks of the Leadin Period (where the price is decreasing). - leadin_length: BlockNumberFor, + /// The relay block number at which the sale will/did start. + sale_start: RelayBlockNumberOf, + /// The length in relay chain blocks of the Leadin Period (where the price is + /// decreasing). + leadin_length: RelayBlockNumberOf, /// The price of Bulk Coretime at the beginning of the Leadin Period. start_price: BalanceOf, /// The price of Bulk Coretime after the Leadin Period. @@ -584,6 +585,9 @@ pub mod pallet { /// Reserve a core for a workload. /// + /// The workload will be given a reservation, but two sale period boundaries must pass + /// before the core is actually assigned. + /// /// - `origin`: Must be Root or pass `AdminOrigin`. /// - `workload`: The workload which should be permanently placed on a core. #[pallet::call_index(1)] @@ -942,6 +946,29 @@ pub mod pallet { Ok(()) } + /// Reserve a core for a workload immediately. + /// + /// - `origin`: Must be Root or pass `AdminOrigin`. + /// - `workload`: The workload which should be permanently placed on a core starting + /// immediately. + /// - `core`: The core to which the assignment should be made until the reservation takes + /// effect. It is left to the caller to either add this new core or reassign any other + /// tasks to this existing core. + /// + /// This reserves the workload and then injects the workload into the Workplan for the next + /// two sale periods. This overwrites any existing assignments for this core at the start of + /// the next sale period. + #[pallet::call_index(23)] + pub fn force_reserve( + origin: OriginFor, + workload: Schedule, + core: CoreIndex, + ) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin_or_root(origin)?; + Self::do_force_reserve(workload, core)?; + Ok(Pays::No.into()) + } + #[pallet::call_index(99)] #[pallet::weight(T::WeightInfo::swap_leases())] pub fn swap_leases(origin: OriginFor, id: TaskId, other: TaskId) -> DispatchResult { diff --git a/substrate/frame/broker/src/migration.rs b/substrate/frame/broker/src/migration.rs index c2a243d6f0e8..f19b1e19bdd1 100644 --- a/substrate/frame/broker/src/migration.rs +++ b/substrate/frame/broker/src/migration.rs @@ -130,7 +130,13 @@ mod v2 { mod v3 { use super::*; + use codec::MaxEncodedLen; + use frame_support::{ + pallet_prelude::{OptionQuery, RuntimeDebug, TypeInfo}, + storage_alias, + }; use frame_system::Pallet as System; + use sp_arithmetic::Perbill; pub struct MigrateToV3Impl(PhantomData); @@ -156,6 +162,244 @@ mod v3 { Ok(()) } } + + #[storage_alias] + pub type Configuration = StorageValue, ConfigRecordOf, OptionQuery>; + pub type ConfigRecordOf = + ConfigRecord, RelayBlockNumberOf>; + + // types added here for v4 migration + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct ConfigRecord { + /// The number of Relay-chain blocks in advance which scheduling should be fixed and the + /// `Coretime::assign` API used to inform the Relay-chain. + pub advance_notice: RelayBlockNumber, + /// The length in blocks of the Interlude Period for forthcoming sales. + pub interlude_length: BlockNumber, + /// The length in blocks of the Leadin Period for forthcoming sales. + pub leadin_length: BlockNumber, + /// The length in timeslices of Regions which are up for sale in forthcoming sales. + pub region_length: Timeslice, + /// The proportion of cores available for sale which should be sold in order for the price + /// to remain the same in the next sale. + pub ideal_bulk_proportion: Perbill, + /// An artificial limit to the number of cores which are allowed to be sold. If `Some` then + /// no more cores will be sold than this. + pub limit_cores_offered: Option, + /// The amount by which the renewal price increases each sale period. + pub renewal_bump: Perbill, + /// The duration by which rewards for contributions to the InstaPool must be collected. + pub contribution_timeout: Timeslice, + } + + #[storage_alias] + pub type SaleInfo = StorageValue, SaleInfoRecordOf, OptionQuery>; + pub type SaleInfoRecordOf = + SaleInfoRecord, frame_system::pallet_prelude::BlockNumberFor>; + + /// The status of a Bulk Coretime Sale. + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct SaleInfoRecord { + /// The relay block number at which the sale will/did start. + pub sale_start: BlockNumber, + /// The length in relay chain blocks of the Leadin Period (where the price is decreasing). + pub leadin_length: BlockNumber, + /// The price of Bulk Coretime after the Leadin Period. + pub price: Balance, + /// The first timeslice of the Regions which are being sold in this sale. + pub region_begin: Timeslice, + /// The timeslice on which the Regions which are being sold in the sale terminate. (i.e. + /// One after the last timeslice which the Regions control.) + pub region_end: Timeslice, + /// The number of cores we want to sell, ideally. Selling this amount would result in no + /// change to the price for the next sale. + pub ideal_cores_sold: CoreIndex, + /// Number of cores which are/have been offered for sale. + pub cores_offered: CoreIndex, + /// The index of the first core which is for sale. Core of Regions which are sold have + /// incrementing indices from this. + pub first_core: CoreIndex, + /// The latest price at which Bulk Coretime was purchased until surpassing the ideal number + /// of cores were sold. + pub sellout_price: Option, + /// Number of cores which have been sold; never more than cores_offered. + pub cores_sold: CoreIndex, + } +} + +pub mod v4 { + use super::*; + + type BlockNumberFor = frame_system::pallet_prelude::BlockNumberFor; + + pub trait BlockToRelayHeightConversion { + /// Converts absolute value of parachain block number to relay chain block number + fn convert_block_number_to_relay_height( + block_number: BlockNumberFor, + ) -> RelayBlockNumberOf; + + /// Converts parachain block length into equivalent relay chain block length + fn convert_block_length_to_relay_length( + block_number: BlockNumberFor, + ) -> RelayBlockNumberOf; + } + + pub struct MigrateToV4Impl(PhantomData, PhantomData); + impl> UncheckedOnRuntimeUpgrade + for MigrateToV4Impl + { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let (interlude_length, configuration_leadin_length) = + if let Some(config_record) = v3::Configuration::::get() { + (config_record.interlude_length, config_record.leadin_length) + } else { + ((0 as u32).into(), (0 as u32).into()) + }; + + let updated_interlude_length: RelayBlockNumberOf = + BlockConversion::convert_block_length_to_relay_length(interlude_length); + let updated_leadin_length: RelayBlockNumberOf = + BlockConversion::convert_block_length_to_relay_length(configuration_leadin_length); + log::info!(target: LOG_TARGET, "Configuration Pre-Migration: Interlude Length {:?}->{:?} Leadin Length {:?}->{:?}", interlude_length, updated_interlude_length, configuration_leadin_length, updated_leadin_length); + + let (sale_start, sale_info_leadin_length) = + if let Some(sale_info_record) = v3::SaleInfo::::get() { + (sale_info_record.sale_start, sale_info_record.leadin_length) + } else { + ((0 as u32).into(), (0 as u32).into()) + }; + + let updated_sale_start: RelayBlockNumberOf = + BlockConversion::convert_block_number_to_relay_height(sale_start); + let updated_sale_info_leadin_length: RelayBlockNumberOf = + BlockConversion::convert_block_length_to_relay_length(sale_info_leadin_length); + log::info!(target: LOG_TARGET, "SaleInfo Pre-Migration: Sale Start {:?}->{:?} Interlude Length {:?}->{:?}", sale_start, updated_sale_start, sale_info_leadin_length, updated_sale_info_leadin_length); + + Ok((interlude_length, configuration_leadin_length, sale_start, sale_info_leadin_length) + .encode()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let mut weight = T::DbWeight::get().reads(1); + + if let Some(config_record) = v3::Configuration::::take() { + log::info!(target: LOG_TARGET, "migrating Configuration record"); + + let updated_interlude_length: RelayBlockNumberOf = + BlockConversion::convert_block_length_to_relay_length( + config_record.interlude_length, + ); + let updated_leadin_length: RelayBlockNumberOf = + BlockConversion::convert_block_length_to_relay_length( + config_record.leadin_length, + ); + + let updated_config_record = ConfigRecord { + interlude_length: updated_interlude_length, + leadin_length: updated_leadin_length, + advance_notice: config_record.advance_notice, + region_length: config_record.region_length, + ideal_bulk_proportion: config_record.ideal_bulk_proportion, + limit_cores_offered: config_record.limit_cores_offered, + renewal_bump: config_record.renewal_bump, + contribution_timeout: config_record.contribution_timeout, + }; + Configuration::::put(updated_config_record); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + if let Some(sale_info) = v3::SaleInfo::::take() { + log::info!(target: LOG_TARGET, "migrating SaleInfo record"); + + let updated_sale_start: RelayBlockNumberOf = + BlockConversion::convert_block_number_to_relay_height(sale_info.sale_start); + let updated_leadin_length: RelayBlockNumberOf = + BlockConversion::convert_block_length_to_relay_length(sale_info.leadin_length); + + let updated_sale_info = SaleInfoRecord { + sale_start: updated_sale_start, + leadin_length: updated_leadin_length, + end_price: sale_info.price, + region_begin: sale_info.region_begin, + region_end: sale_info.region_end, + ideal_cores_sold: sale_info.ideal_cores_sold, + cores_offered: sale_info.cores_offered, + first_core: sale_info.first_core, + sellout_price: sale_info.sellout_price, + cores_sold: sale_info.cores_sold, + }; + SaleInfo::::put(updated_sale_info); + } + + weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let ( + old_interlude_length, + old_configuration_leadin_length, + old_sale_start, + old_sale_info_leadin_length, + ): (BlockNumberFor, BlockNumberFor, BlockNumberFor, BlockNumberFor) = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + + if let Some(config_record) = Configuration::::get() { + ensure!( + Self::verify_updated_block_length( + old_configuration_leadin_length, + config_record.leadin_length + ), + "must migrate configuration leadin_length" + ); + + ensure!( + Self::verify_updated_block_length( + old_interlude_length, + config_record.interlude_length + ), + "must migrate configuration interlude_length" + ); + } + + if let Some(sale_info) = SaleInfo::::get() { + ensure!( + Self::verify_updated_block_time(old_sale_start, sale_info.sale_start), + "must migrate sale info sale_start" + ); + + ensure!( + Self::verify_updated_block_length( + old_sale_info_leadin_length, + sale_info.leadin_length + ), + "must migrate sale info leadin_length" + ); + } + + Ok(()) + } + } + + #[cfg(feature = "try-runtime")] + impl> + MigrateToV4Impl + { + fn verify_updated_block_time( + old_value: BlockNumberFor, + new_value: RelayBlockNumberOf, + ) -> bool { + BlockConversion::convert_block_number_to_relay_height(old_value) == new_value + } + + fn verify_updated_block_length( + old_value: BlockNumberFor, + new_value: RelayBlockNumberOf, + ) -> bool { + BlockConversion::convert_block_length_to_relay_length(old_value) == new_value + } + } } /// Migrate the pallet storage from `0` to `1`. @@ -182,3 +426,11 @@ pub type MigrateV2ToV3 = frame_support::migrations::VersionedMigration< Pallet, ::DbWeight, >; + +pub type MigrateV3ToV4 = frame_support::migrations::VersionedMigration< + 3, + 4, + v4::MigrateToV4Impl, + Pallet, + ::DbWeight, +>; diff --git a/substrate/frame/broker/src/tests.rs b/substrate/frame/broker/src/tests.rs index f3fd5234e4ca..a130a2050d9a 100644 --- a/substrate/frame/broker/src/tests.rs +++ b/substrate/frame/broker/src/tests.rs @@ -1837,3 +1837,306 @@ fn start_sales_sets_correct_core_count() { System::assert_has_event(Event::::CoreCountRequested { core_count: 9 }.into()); }) } + +// Reservations currently need two sale period boundaries to pass before coming into effect. +#[test] +fn reserve_works() { + TestExt::new().execute_with(|| { + assert_ok!(Broker::do_start_sales(100, 0)); + // Advance forward from start_sales, but not into the first sale. + advance_to(1); + + let system_workload = Schedule::truncate_from(vec![ScheduleItem { + mask: CoreMask::complete(), + assignment: Task(1004), + }]); + + // This shouldn't work, as the reservation will never be assigned a core unless one is + // available. + // assert_noop!(Broker::do_reserve(system_workload.clone()), Error::::Unavailable); + + // Add another core and create the reservation. + let status = Status::::get().unwrap(); + assert_ok!(Broker::request_core_count(RuntimeOrigin::root(), status.core_count + 1)); + assert_ok!(Broker::reserve(RuntimeOrigin::root(), system_workload.clone())); + + // This is added to reservations. + System::assert_last_event( + Event::ReservationMade { index: 0, workload: system_workload.clone() }.into(), + ); + assert_eq!(Reservations::::get(), vec![system_workload.clone()]); + + // But not yet in workplan for any of the next few regions. + for i in 0..20 { + assert_eq!(Workplan::::get((i, 0)), None); + } + // And it hasn't been assigned a core. + assert_eq!(CoretimeTrace::get(), vec![]); + + // Go to next sale. Rotate sale puts it in the workplan. + advance_sale_period(); + assert_eq!(Workplan::::get((7, 0)), Some(system_workload.clone())); + // But it still hasn't been assigned a core. + assert_eq!(CoretimeTrace::get(), vec![]); + + // Go to the second sale after reserving. + advance_sale_period(); + // Core is assigned at block 14 (timeslice 7) after being reserved all the way back at + // timeslice 1! Since the mock periods are 3 timeslices long, this means that reservations + // made in period 0 will only come into effect in period 2. + assert_eq!( + CoretimeTrace::get(), + vec![( + 12, + AssignCore { + core: 0, + begin: 14, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + )] + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 14, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + + // And it's in the workplan for the next period. + assert_eq!(Workplan::::get((10, 0)), Some(system_workload.clone())); + }); +} + +// We can use a hack to accelerate this by injecting it into the workplan. +#[test] +fn can_reserve_workloads_quickly() { + TestExt::new().execute_with(|| { + // Start sales. + assert_ok!(Broker::do_start_sales(100, 0)); + advance_to(2); + + let system_workload = Schedule::truncate_from(vec![ScheduleItem { + mask: CoreMask::complete(), + assignment: Task(1004), + }]); + + // This shouldn't work, as the reservation will never be assigned a core unless one is + // available. + // assert_noop!(Broker::do_reserve(system_workload.clone()), Error::::Unavailable); + + // Add another core and create the reservation. + let core_count = Status::::get().unwrap().core_count; + assert_ok!(Broker::request_core_count(RuntimeOrigin::root(), core_count + 1)); + assert_ok!(Broker::reserve(RuntimeOrigin::root(), system_workload.clone())); + + // These are the additional steps to onboard this immediately. + let core_index = core_count; + // In a real network this would call the relay chain + // `assigner_coretime::assign_core` extrinsic directly. + ::assign_core( + core_index, + 2, + vec![(Task(1004), 57600)], + None, + ); + // Inject into the workplan to ensure it's scheduled in the next rotate_sale. + Workplan::::insert((4, core_index), system_workload.clone()); + + // Reservation is added for the workload. + System::assert_has_event( + Event::ReservationMade { index: 0, workload: system_workload.clone() }.into(), + ); + System::assert_has_event(Event::CoreCountRequested { core_count: 1 }.into()); + + // It is also in the workplan for the next region. + assert_eq!(Workplan::::get((4, 0)), Some(system_workload.clone())); + + // Go to next sale. Rotate sale puts it in the workplan. + advance_sale_period(); + assert_eq!(Workplan::::get((7, 0)), Some(system_workload.clone())); + + // Go to the second sale after reserving. + advance_sale_period(); + + // Check the trace to ensure it has a core in every region. + assert_eq!( + CoretimeTrace::get(), + vec![ + ( + 2, + AssignCore { + core: 0, + begin: 2, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + ), + ( + 6, + AssignCore { + core: 0, + begin: 8, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + ), + ( + 12, + AssignCore { + core: 0, + begin: 14, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + ) + ] + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 8, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 14, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 14, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + + // And it's in the workplan for the next period. + assert_eq!(Workplan::::get((10, 0)), Some(system_workload.clone())); + }); +} + +// Add an extrinsic to do it properly. +#[test] +fn force_reserve_works() { + TestExt::new().execute_with(|| { + let system_workload = Schedule::truncate_from(vec![ScheduleItem { + mask: CoreMask::complete(), + assignment: Task(1004), + }]); + + // Not intended to work before sales are started. + assert_noop!( + Broker::force_reserve(RuntimeOrigin::root(), system_workload.clone(), 0), + Error::::NoSales + ); + + // Start sales. + assert_ok!(Broker::do_start_sales(100, 0)); + advance_to(1); + + // Add a new core. With the mock this is instant, with current relay implementation it + // takes two sessions to come into effect. + assert_ok!(Broker::do_request_core_count(1)); + + // Force reserve should now work. + assert_ok!(Broker::force_reserve(RuntimeOrigin::root(), system_workload.clone(), 0)); + + // Reservation is added for the workload. + System::assert_has_event( + Event::ReservationMade { index: 0, workload: system_workload.clone() }.into(), + ); + System::assert_has_event(Event::CoreCountRequested { core_count: 1 }.into()); + assert_eq!(Reservations::::get(), vec![system_workload.clone()]); + + // Advance to where that timeslice will be committed. + advance_to(3); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 4, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + + // It is also in the workplan for the next region. + assert_eq!(Workplan::::get((4, 0)), Some(system_workload.clone())); + + // Go to next sale. Rotate sale puts it in the workplan. + advance_sale_period(); + assert_eq!(Workplan::::get((7, 0)), Some(system_workload.clone())); + + // Go to the second sale after reserving. + advance_sale_period(); + + // Check the trace to ensure it has a core in every region. + assert_eq!( + CoretimeTrace::get(), + vec![ + ( + 2, + AssignCore { + core: 0, + begin: 4, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + ), + ( + 6, + AssignCore { + core: 0, + begin: 8, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + ), + ( + 12, + AssignCore { + core: 0, + begin: 14, + assignment: vec![(Task(1004), 57600)], + end_hint: None + } + ) + ] + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 8, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 14, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + System::assert_has_event( + Event::CoreAssigned { + core: 0, + when: 14, + assignment: vec![(CoreAssignment::Task(1004), 57600)], + } + .into(), + ); + + // And it's in the workplan for the next period. + assert_eq!(Workplan::::get((10, 0)), Some(system_workload.clone())); + }); +} diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index 8dbd5df57166..e0b4932f11e2 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -19,7 +19,7 @@ use super::*; use alloc::{vec, vec::Vec}; use frame_support::{pallet_prelude::*, traits::defensive_prelude::*, weights::WeightMeter}; use sp_arithmetic::traits::{One, SaturatedConversion, Saturating, Zero}; -use sp_runtime::traits::{ConvertBack, MaybeConvert}; +use sp_runtime::traits::{BlockNumberProvider, ConvertBack, MaybeConvert}; use CompletionStatus::Complete; impl Pallet { @@ -158,7 +158,7 @@ impl Pallet { config: &ConfigRecordOf, status: &StatusRecord, ) -> Option<()> { - let now = frame_system::Pallet::::block_number(); + let now = RCBlockNumberProviderOf::::current_block_number(); let pool_item = ScheduleItem { assignment: CoreAssignment::Pool, mask: CoreMask::complete() }; diff --git a/substrate/frame/broker/src/types.rs b/substrate/frame/broker/src/types.rs index 10e6756bc90e..f970b310a3cb 100644 --- a/substrate/frame/broker/src/types.rs +++ b/substrate/frame/broker/src/types.rs @@ -21,7 +21,7 @@ use crate::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::fungible::Inspect; -use frame_system::{pallet_prelude::BlockNumberFor, Config as SConfig}; +use frame_system::Config as SConfig; use scale_info::TypeInfo; use sp_arithmetic::Perbill; use sp_core::{ConstU32, RuntimeDebug}; @@ -208,11 +208,11 @@ pub struct PoolIoRecord { /// The status of a Bulk Coretime Sale. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct SaleInfoRecord { - /// The local block number at which the sale will/did start. - pub sale_start: BlockNumber, +pub struct SaleInfoRecord { + /// The relay block number at which the sale will/did start. + pub sale_start: RelayBlockNumber, /// The length in blocks of the Leadin Period (where the price is decreasing). - pub leadin_length: BlockNumber, + pub leadin_length: RelayBlockNumber, /// The price of Bulk Coretime after the Leadin Period. pub end_price: Balance, /// The first timeslice of the Regions which are being sold in this sale. @@ -235,7 +235,7 @@ pub struct SaleInfoRecord { /// Number of cores which have been sold; never more than cores_offered. pub cores_sold: CoreIndex, } -pub type SaleInfoRecordOf = SaleInfoRecord, BlockNumberFor>; +pub type SaleInfoRecordOf = SaleInfoRecord, RelayBlockNumberOf>; /// Record for Polkadot Core reservations (generally tasked with the maintenance of System /// Chains). @@ -272,14 +272,14 @@ pub type OnDemandRevenueRecordOf = /// Configuration of this pallet. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ConfigRecord { +pub struct ConfigRecord { /// The number of Relay-chain blocks in advance which scheduling should be fixed and the /// `Coretime::assign` API used to inform the Relay-chain. pub advance_notice: RelayBlockNumber, /// The length in blocks of the Interlude Period for forthcoming sales. - pub interlude_length: BlockNumber, + pub interlude_length: RelayBlockNumber, /// The length in blocks of the Leadin Period for forthcoming sales. - pub leadin_length: BlockNumber, + pub leadin_length: RelayBlockNumber, /// The length in timeslices of Regions which are up for sale in forthcoming sales. pub region_length: Timeslice, /// The proportion of cores available for sale which should be sold. @@ -296,11 +296,11 @@ pub struct ConfigRecord { /// The duration by which rewards for contributions to the InstaPool must be collected. pub contribution_timeout: Timeslice, } -pub type ConfigRecordOf = ConfigRecord, RelayBlockNumberOf>; +pub type ConfigRecordOf = ConfigRecord>; -impl ConfigRecord +impl ConfigRecord where - BlockNumber: sp_arithmetic::traits::Zero, + RelayBlockNumber: sp_arithmetic::traits::Zero, { /// Check the config for basic validity constraints. pub(crate) fn validate(&self) -> Result<(), ()> { diff --git a/substrate/frame/broker/src/utility_impls.rs b/substrate/frame/broker/src/utility_impls.rs index e937e0cbbec5..73f05d1e5ef4 100644 --- a/substrate/frame/broker/src/utility_impls.rs +++ b/substrate/frame/broker/src/utility_impls.rs @@ -24,7 +24,6 @@ use frame_support::{ OnUnbalanced, }, }; -use frame_system::pallet_prelude::BlockNumberFor; use sp_arithmetic::{ traits::{SaturatedConversion, Saturating}, FixedPointNumber, FixedU64, @@ -60,7 +59,7 @@ impl Pallet { T::PalletId::get().into_account_truncating() } - pub fn sale_price(sale: &SaleInfoRecordOf, now: BlockNumberFor) -> BalanceOf { + pub fn sale_price(sale: &SaleInfoRecordOf, now: RelayBlockNumberOf) -> BalanceOf { let num = now.saturating_sub(sale.sale_start).min(sale.leadin_length).saturated_into(); let through = FixedU64::from_rational(num, sale.leadin_length.saturated_into()); T::PriceAdapter::leadin_factor_at(through).saturating_mul_int(sale.end_price) diff --git a/substrate/frame/broker/src/weights.rs b/substrate/frame/broker/src/weights.rs index 2f25fddc2050..87e588551661 100644 --- a/substrate/frame/broker/src/weights.rs +++ b/substrate/frame/broker/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `sergej-B650-AORUS-ELITE-AX`, CPU: `AMD Ryzen 9 7900X3D 12-Core Processor` +//! HOSTNAME: `runner-acd6uxux-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/release/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_broker -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/broker/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_broker +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/broker/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -79,10 +77,11 @@ pub trait WeightInfo { fn notify_core_count() -> Weight; fn notify_revenue() -> Weight; fn do_tick_base() -> Weight; + fn force_reserve() -> Weight; fn swap_leases() -> Weight; - fn on_new_timeslice() -> Weight; fn enable_auto_renew() -> Weight; fn disable_auto_renew() -> Weight; + fn on_new_timeslice() -> Weight; } /// Weights for `pallet_broker` using the Substrate node and recommended hardware. @@ -94,8 +93,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_593_000 picoseconds. - Weight::from_parts(1_703_000, 0) + // Minimum execution time: 2_498_000 picoseconds. + Weight::from_parts(2_660_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -104,8 +103,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 12_864_000 picoseconds. - Weight::from_parts(13_174_000, 7496) + // Minimum execution time: 23_090_000 picoseconds. + Weight::from_parts(23_664_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -115,8 +114,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 12_284_000 picoseconds. - Weight::from_parts(13_566_000, 7496) + // Minimum execution time: 21_782_000 picoseconds. + Weight::from_parts(22_708_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -126,8 +125,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 6_743_000 picoseconds. - Weight::from_parts(7_094_000, 1526) + // Minimum execution time: 14_966_000 picoseconds. + Weight::from_parts(15_592_000, 1526) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -152,10 +151,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 21_120_000 picoseconds. - Weight::from_parts(40_929_422, 8499) - // Standard Error: 471 - .saturating_add(Weight::from_parts(1_004, 0).saturating_mul(n.into())) + // Minimum execution time: 31_757_000 picoseconds. + Weight::from_parts(57_977_268, 8499) + // Standard Error: 576 + .saturating_add(Weight::from_parts(3_102, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)) } @@ -163,19 +162,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Regions` (r:0 w:1) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `651` - // Estimated: `2136` - // Minimum execution time: 31_169_000 picoseconds. - Weight::from_parts(32_271_000, 2136) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `470` + // Estimated: `1542` + // Minimum execution time: 40_469_000 picoseconds. + Weight::from_parts(41_360_000, 1542) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) @@ -186,19 +181,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::PotentialRenewals` (r:1 w:2) /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `769` + // Measured: `588` // Estimated: `4698` - // Minimum execution time: 44_945_000 picoseconds. - Weight::from_parts(47_119_000, 4698) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Minimum execution time: 60_724_000 picoseconds. + Weight::from_parts(63_445_000, 4698) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Broker::Regions` (r:1 w:1) @@ -207,8 +198,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3551` - // Minimum execution time: 11_562_000 picoseconds. - Weight::from_parts(11_943_000, 3551) + // Minimum execution time: 23_734_000 picoseconds. + Weight::from_parts(25_080_000, 3551) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -218,8 +209,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3551` - // Minimum execution time: 13_075_000 picoseconds. - Weight::from_parts(13_616_000, 3551) + // Minimum execution time: 25_917_000 picoseconds. + Weight::from_parts(26_715_000, 3551) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -229,8 +220,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3551` - // Minimum execution time: 13_695_000 picoseconds. - Weight::from_parts(14_658_000, 3551) + // Minimum execution time: 26_764_000 picoseconds. + Weight::from_parts(27_770_000, 3551) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -246,8 +237,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `741` // Estimated: `4681` - // Minimum execution time: 22_623_000 picoseconds. - Weight::from_parts(23_233_000, 4681) + // Minimum execution time: 37_617_000 picoseconds. + Weight::from_parts(39_333_000, 4681) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -265,8 +256,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776` // Estimated: `5996` - // Minimum execution time: 26_901_000 picoseconds. - Weight::from_parts(27_472_000, 5996) + // Minimum execution time: 43_168_000 picoseconds. + Weight::from_parts(44_741_000, 5996) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -281,10 +272,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `878` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 51_778_000 picoseconds. - Weight::from_parts(53_726_731, 6196) - // Standard Error: 45_279 - .saturating_add(Weight::from_parts(677_769, 0).saturating_mul(m.into())) + // Minimum execution time: 75_317_000 picoseconds. + Weight::from_parts(76_792_860, 6196) + // Standard Error: 55_267 + .saturating_add(Weight::from_parts(1_878_133, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -296,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 31_790_000 picoseconds. - Weight::from_parts(32_601_000, 3593) + // Minimum execution time: 44_248_000 picoseconds. + Weight::from_parts(45_201_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -309,8 +300,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `604` // Estimated: `3551` - // Minimum execution time: 18_465_000 picoseconds. - Weight::from_parts(21_050_000, 3551) + // Minimum execution time: 39_853_000 picoseconds. + Weight::from_parts(44_136_000, 3551) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -324,8 +315,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 23_825_000 picoseconds. - Weight::from_parts(26_250_000, 3533) + // Minimum execution time: 46_452_000 picoseconds. + Weight::from_parts(52_780_000, 3533) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -339,10 +330,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `1014` + // Measured: `1117` // Estimated: `3593` - // Minimum execution time: 28_103_000 picoseconds. - Weight::from_parts(32_622_000, 3593) + // Minimum execution time: 64_905_000 picoseconds. + Weight::from_parts(72_914_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -354,8 +345,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `661` // Estimated: `4698` - // Minimum execution time: 16_751_000 picoseconds. - Weight::from_parts(17_373_000, 4698) + // Minimum execution time: 38_831_000 picoseconds. + Weight::from_parts(41_420_000, 4698) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -364,8 +355,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_705_000 picoseconds. - Weight::from_parts(2_991_768, 0) + // Minimum execution time: 4_595_000 picoseconds. + Weight::from_parts(4_964_606, 0) } /// Storage: `Broker::CoreCountInbox` (r:1 w:1) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -374,37 +365,58 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `404` // Estimated: `1487` - // Minimum execution time: 4_598_000 picoseconds. - Weight::from_parts(4_937_302, 1487) + // Minimum execution time: 8_640_000 picoseconds. + Weight::from_parts(9_153_332, 1487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:1) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `991` - // Estimated: `4456` - // Minimum execution time: 37_601_000 picoseconds. - Weight::from_parts(38_262_000, 4456) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `667` + // Estimated: `3593` + // Minimum execution time: 40_570_000 picoseconds. + Weight::from_parts(41_402_000, 3593) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } + /// Storage: `Broker::InstaPoolIo` (r:3 w:3) + /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:0) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(6011), added: 6506, mode: `MaxEncodedLen`) + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(101), added: 596, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::PotentialRenewals` (r:10 w:20) + /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:10 w:10) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Broker::SaleInfo` (r:0 w:1) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:1000) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn rotate_sale(_n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) + fn rotate_sale(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `8548` + // Estimated: `38070` + // Minimum execution time: 29_370_000 picoseconds. + Weight::from_parts(334_030_189, 38070) + // Standard Error: 6_912 + .saturating_add(Weight::from_parts(1_268_750, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(26_u64)) + .saturating_add(T::DbWeight::get().writes(34_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } /// Storage: `Broker::InstaPoolIo` (r:1 w:0) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -414,8 +426,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 5_391_000 picoseconds. - Weight::from_parts(5_630_000, 3493) + // Minimum execution time: 9_005_000 picoseconds. + Weight::from_parts(9_392_000, 3493) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -427,8 +439,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 10_249_000 picoseconds. - Weight::from_parts(10_529_000, 4681) + // Minimum execution time: 19_043_000 picoseconds. + Weight::from_parts(20_089_000, 4681) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -436,8 +448,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 120_000 picoseconds. - Weight::from_parts(140_000, 0) + // Minimum execution time: 149_000 picoseconds. + Weight::from_parts(183_000, 0) } /// Storage: `Broker::CoreCountInbox` (r:0 w:1) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -445,8 +457,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_402_000 picoseconds. - Weight::from_parts(1_513_000, 0) + // Minimum execution time: 2_248_000 picoseconds. + Weight::from_parts(2_425_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::RevenueInbox` (r:0 w:1) @@ -455,8 +467,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_902_000 picoseconds. - Weight::from_parts(2_116_000, 0) + // Minimum execution time: 2_413_000 picoseconds. + Weight::from_parts(2_640_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Status` (r:1 w:1) @@ -465,16 +477,33 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) /// Storage: `Broker::CoreCountInbox` (r:1 w:0) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:0) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `603` - // Estimated: `4068` - // Minimum execution time: 8_897_000 picoseconds. - Weight::from_parts(9_218_000, 4068) + // Measured: `441` + // Estimated: `1516` + // Minimum execution time: 17_083_000 picoseconds. + Weight::from_parts(18_077_000, 1516) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Broker::SaleInfo` (r:1 w:0) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:1) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(6011), added: 6506, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:2) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn force_reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `5253` + // Estimated: `7496` + // Minimum execution time: 28_363_000 picoseconds. + Weight::from_parts(29_243_000, 7496) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`) @@ -482,18 +511,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 4_678_000 picoseconds. - Weight::from_parts(4_920_000, 1526) + // Minimum execution time: 11_620_000 picoseconds. + Weight::from_parts(12_063_000, 1526) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn on_new_timeslice() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 229_000 picoseconds. - Weight::from_parts(268_000, 0) - } /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::PotentialRenewals` (r:1 w:2) @@ -504,34 +526,37 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::AutoRenewals` (r:1 w:1) /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(101), added: 596, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn enable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `930` + // Measured: `1121` // Estimated: `4698` - // Minimum execution time: 51_597_000 picoseconds. - Weight::from_parts(52_609_000, 4698) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 85_270_000 picoseconds. + Weight::from_parts(90_457_000, 4698) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Broker::AutoRenewals` (r:1 w:1) /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(101), added: 596, mode: `MaxEncodedLen`) fn disable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `484` + // Measured: `578` // Estimated: `1586` - // Minimum execution time: 8_907_000 picoseconds. - Weight::from_parts(9_167_000, 1586) + // Minimum execution time: 22_479_000 picoseconds. + Weight::from_parts(23_687_000, 1586) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + fn on_new_timeslice() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 245_000 picoseconds. + Weight::from_parts(290_000, 0) + } } // For backwards compatibility and tests. @@ -542,8 +567,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_593_000 picoseconds. - Weight::from_parts(1_703_000, 0) + // Minimum execution time: 2_498_000 picoseconds. + Weight::from_parts(2_660_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -552,8 +577,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 12_864_000 picoseconds. - Weight::from_parts(13_174_000, 7496) + // Minimum execution time: 23_090_000 picoseconds. + Weight::from_parts(23_664_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -563,8 +588,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 12_284_000 picoseconds. - Weight::from_parts(13_566_000, 7496) + // Minimum execution time: 21_782_000 picoseconds. + Weight::from_parts(22_708_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -574,8 +599,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 6_743_000 picoseconds. - Weight::from_parts(7_094_000, 1526) + // Minimum execution time: 14_966_000 picoseconds. + Weight::from_parts(15_592_000, 1526) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -600,10 +625,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 21_120_000 picoseconds. - Weight::from_parts(40_929_422, 8499) - // Standard Error: 471 - .saturating_add(Weight::from_parts(1_004, 0).saturating_mul(n.into())) + // Minimum execution time: 31_757_000 picoseconds. + Weight::from_parts(57_977_268, 8499) + // Standard Error: 576 + .saturating_add(Weight::from_parts(3_102, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(16_u64)) } @@ -611,19 +636,15 @@ impl WeightInfo for () { /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Regions` (r:0 w:1) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `651` - // Estimated: `2136` - // Minimum execution time: 31_169_000 picoseconds. - Weight::from_parts(32_271_000, 2136) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Measured: `470` + // Estimated: `1542` + // Minimum execution time: 40_469_000 picoseconds. + Weight::from_parts(41_360_000, 1542) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) @@ -634,19 +655,15 @@ impl WeightInfo for () { /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::PotentialRenewals` (r:1 w:2) /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `769` + // Measured: `588` // Estimated: `4698` - // Minimum execution time: 44_945_000 picoseconds. - Weight::from_parts(47_119_000, 4698) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Minimum execution time: 60_724_000 picoseconds. + Weight::from_parts(63_445_000, 4698) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Broker::Regions` (r:1 w:1) @@ -655,8 +672,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3551` - // Minimum execution time: 11_562_000 picoseconds. - Weight::from_parts(11_943_000, 3551) + // Minimum execution time: 23_734_000 picoseconds. + Weight::from_parts(25_080_000, 3551) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -666,8 +683,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3551` - // Minimum execution time: 13_075_000 picoseconds. - Weight::from_parts(13_616_000, 3551) + // Minimum execution time: 25_917_000 picoseconds. + Weight::from_parts(26_715_000, 3551) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -677,8 +694,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3551` - // Minimum execution time: 13_695_000 picoseconds. - Weight::from_parts(14_658_000, 3551) + // Minimum execution time: 26_764_000 picoseconds. + Weight::from_parts(27_770_000, 3551) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -694,8 +711,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `741` // Estimated: `4681` - // Minimum execution time: 22_623_000 picoseconds. - Weight::from_parts(23_233_000, 4681) + // Minimum execution time: 37_617_000 picoseconds. + Weight::from_parts(39_333_000, 4681) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -713,8 +730,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776` // Estimated: `5996` - // Minimum execution time: 26_901_000 picoseconds. - Weight::from_parts(27_472_000, 5996) + // Minimum execution time: 43_168_000 picoseconds. + Weight::from_parts(44_741_000, 5996) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -729,10 +746,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `878` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 51_778_000 picoseconds. - Weight::from_parts(53_726_731, 6196) - // Standard Error: 45_279 - .saturating_add(Weight::from_parts(677_769, 0).saturating_mul(m.into())) + // Minimum execution time: 75_317_000 picoseconds. + Weight::from_parts(76_792_860, 6196) + // Standard Error: 55_267 + .saturating_add(Weight::from_parts(1_878_133, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -744,8 +761,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 31_790_000 picoseconds. - Weight::from_parts(32_601_000, 3593) + // Minimum execution time: 44_248_000 picoseconds. + Weight::from_parts(45_201_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -757,8 +774,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `604` // Estimated: `3551` - // Minimum execution time: 18_465_000 picoseconds. - Weight::from_parts(21_050_000, 3551) + // Minimum execution time: 39_853_000 picoseconds. + Weight::from_parts(44_136_000, 3551) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -772,8 +789,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 23_825_000 picoseconds. - Weight::from_parts(26_250_000, 3533) + // Minimum execution time: 46_452_000 picoseconds. + Weight::from_parts(52_780_000, 3533) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -787,10 +804,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `1014` + // Measured: `1117` // Estimated: `3593` - // Minimum execution time: 28_103_000 picoseconds. - Weight::from_parts(32_622_000, 3593) + // Minimum execution time: 64_905_000 picoseconds. + Weight::from_parts(72_914_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -802,8 +819,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `661` // Estimated: `4698` - // Minimum execution time: 16_751_000 picoseconds. - Weight::from_parts(17_373_000, 4698) + // Minimum execution time: 38_831_000 picoseconds. + Weight::from_parts(41_420_000, 4698) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -812,8 +829,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_705_000 picoseconds. - Weight::from_parts(2_991_768, 0) + // Minimum execution time: 4_595_000 picoseconds. + Weight::from_parts(4_964_606, 0) } /// Storage: `Broker::CoreCountInbox` (r:1 w:1) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -822,37 +839,58 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `404` // Estimated: `1487` - // Minimum execution time: 4_598_000 picoseconds. - Weight::from_parts(4_937_302, 1487) + // Minimum execution time: 8_640_000 picoseconds. + Weight::from_parts(9_153_332, 1487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:1) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) /// Storage: `Broker::InstaPoolHistory` (r:1 w:1) /// Proof: `Broker::InstaPoolHistory` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `991` - // Estimated: `4456` - // Minimum execution time: 37_601_000 picoseconds. - Weight::from_parts(38_262_000, 4456) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `667` + // Estimated: `3593` + // Minimum execution time: 40_570_000 picoseconds. + Weight::from_parts(41_402_000, 3593) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } + /// Storage: `Broker::InstaPoolIo` (r:3 w:3) + /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:0) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(6011), added: 6506, mode: `MaxEncodedLen`) + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`) + /// Storage: `Broker::AutoRenewals` (r:1 w:1) + /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(101), added: 596, mode: `MaxEncodedLen`) + /// Storage: `Broker::Configuration` (r:1 w:0) + /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::PotentialRenewals` (r:10 w:20) + /// Proof: `Broker::PotentialRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:10 w:10) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Broker::SaleInfo` (r:0 w:1) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:1000) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn rotate_sale(_n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) + fn rotate_sale(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `8548` + // Estimated: `38070` + // Minimum execution time: 29_370_000 picoseconds. + Weight::from_parts(334_030_189, 38070) + // Standard Error: 6_912 + .saturating_add(Weight::from_parts(1_268_750, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(26_u64)) + .saturating_add(RocksDbWeight::get().writes(34_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) } /// Storage: `Broker::InstaPoolIo` (r:1 w:0) /// Proof: `Broker::InstaPoolIo` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) @@ -862,8 +900,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 5_391_000 picoseconds. - Weight::from_parts(5_630_000, 3493) + // Minimum execution time: 9_005_000 picoseconds. + Weight::from_parts(9_392_000, 3493) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -875,8 +913,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 10_249_000 picoseconds. - Weight::from_parts(10_529_000, 4681) + // Minimum execution time: 19_043_000 picoseconds. + Weight::from_parts(20_089_000, 4681) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -884,8 +922,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 120_000 picoseconds. - Weight::from_parts(140_000, 0) + // Minimum execution time: 149_000 picoseconds. + Weight::from_parts(183_000, 0) } /// Storage: `Broker::CoreCountInbox` (r:0 w:1) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) @@ -893,8 +931,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_402_000 picoseconds. - Weight::from_parts(1_513_000, 0) + // Minimum execution time: 2_248_000 picoseconds. + Weight::from_parts(2_425_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::RevenueInbox` (r:0 w:1) @@ -903,8 +941,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_902_000 picoseconds. - Weight::from_parts(2_116_000, 0) + // Minimum execution time: 2_413_000 picoseconds. + Weight::from_parts(2_640_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Status` (r:1 w:1) @@ -913,16 +951,33 @@ impl WeightInfo for () { /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) /// Storage: `Broker::CoreCountInbox` (r:1 w:0) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) + /// Storage: `Broker::RevenueInbox` (r:1 w:0) + /// Proof: `Broker::RevenueInbox` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `603` - // Estimated: `4068` - // Minimum execution time: 8_897_000 picoseconds. - Weight::from_parts(9_218_000, 4068) + // Measured: `441` + // Estimated: `1516` + // Minimum execution time: 17_083_000 picoseconds. + Weight::from_parts(18_077_000, 1516) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `Broker::SaleInfo` (r:1 w:0) + /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) + /// Storage: `Broker::Reservations` (r:1 w:1) + /// Proof: `Broker::Reservations` (`max_values`: Some(1), `max_size`: Some(6011), added: 6506, mode: `MaxEncodedLen`) + /// Storage: `Broker::Status` (r:1 w:0) + /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) + /// Storage: `Broker::Workplan` (r:0 w:2) + /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) + fn force_reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `5253` + // Estimated: `7496` + // Minimum execution time: 28_363_000 picoseconds. + Weight::from_parts(29_243_000, 7496) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Broker::Leases` (r:1 w:1) /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`) @@ -930,18 +985,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 4_678_000 picoseconds. - Weight::from_parts(4_920_000, 1526) + // Minimum execution time: 11_620_000 picoseconds. + Weight::from_parts(12_063_000, 1526) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - fn on_new_timeslice() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 229_000 picoseconds. - Weight::from_parts(268_000, 0) - } /// Storage: `Broker::SaleInfo` (r:1 w:1) /// Proof: `Broker::SaleInfo` (`max_values`: Some(1), `max_size`: Some(57), added: 552, mode: `MaxEncodedLen`) /// Storage: `Broker::PotentialRenewals` (r:1 w:2) @@ -952,32 +1000,35 @@ impl WeightInfo for () { /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Broker::AutoRenewals` (r:1 w:1) /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(101), added: 596, mode: `MaxEncodedLen`) /// Storage: `Broker::Workplan` (r:0 w:1) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn enable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `930` + // Measured: `1121` // Estimated: `4698` - // Minimum execution time: 51_597_000 picoseconds. - Weight::from_parts(52_609_000, 4698) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 85_270_000 picoseconds. + Weight::from_parts(90_457_000, 4698) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Broker::AutoRenewals` (r:1 w:1) /// Proof: `Broker::AutoRenewals` (`max_values`: Some(1), `max_size`: Some(101), added: 596, mode: `MaxEncodedLen`) fn disable_auto_renew() -> Weight { // Proof Size summary in bytes: - // Measured: `484` + // Measured: `578` // Estimated: `1586` - // Minimum execution time: 8_907_000 picoseconds. - Weight::from_parts(9_167_000, 1586) + // Minimum execution time: 22_479_000 picoseconds. + Weight::from_parts(23_687_000, 1586) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } -} \ No newline at end of file + fn on_new_timeslice() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 245_000 picoseconds. + Weight::from_parts(290_000, 0) + } +} diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index a250886b5e3d..b7d9d245892a 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-bounties = { workspace = true } pallet-treasury = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/child-bounties/src/benchmarking.rs b/substrate/frame/child-bounties/src/benchmarking.rs index 68e99e21a456..2864f3ab5048 100644 --- a/substrate/frame/child-bounties/src/benchmarking.rs +++ b/substrate/frame/child-bounties/src/benchmarking.rs @@ -19,17 +19,15 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; - -use alloc::{vec, vec::Vec}; - -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use sp_runtime::traits::BlockNumberProvider; - -use crate::Pallet as ChildBounties; +use alloc::vec; +use frame_benchmarking::{v2::*, BenchmarkError}; +use frame_support::ensure; +use frame_system::RawOrigin; use pallet_bounties::Pallet as Bounties; use pallet_treasury::Pallet as Treasury; +use sp_runtime::traits::BlockNumberProvider; + +use crate::*; const SEED: u32 = 0; @@ -144,16 +142,16 @@ fn activate_child_bounty( let mut bounty_setup = activate_bounty::(user, description)?; let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); - ChildBounties::::add_child_bounty( + Pallet::::add_child_bounty( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_value, bounty_setup.reason.clone(), )?; - bounty_setup.child_bounty_id = ChildBountyCount::::get() - 1; + bounty_setup.child_bounty_id = ParentTotalChildBounties::::get(bounty_setup.bounty_id) - 1; - ChildBounties::::propose_curator( + Pallet::::propose_curator( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_id, @@ -161,7 +159,7 @@ fn activate_child_bounty( bounty_setup.child_bounty_fee, )?; - ChildBounties::::accept_curator( + Pallet::::accept_curator( RawOrigin::Signed(bounty_setup.child_curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_id, @@ -180,145 +178,227 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -benchmarks! { - add_child_bounty { - let d in 0 .. T::MaximumReasonLength::get(); +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn add_child_bounty( + d: Linear<0, { T::MaximumReasonLength::get() }>, + ) -> Result<(), BenchmarkError> { setup_pot_account::(); let bounty_setup = activate_bounty::(0, d)?; - }: _(RawOrigin::Signed(bounty_setup.curator), bounty_setup.bounty_id, - bounty_setup.child_bounty_value, bounty_setup.reason.clone()) - verify { - assert_last_event::(Event::Added { - index: bounty_setup.bounty_id, - child_index: bounty_setup.child_bounty_id, - }.into()) + + #[extrinsic_call] + _( + RawOrigin::Signed(bounty_setup.curator), + bounty_setup.bounty_id, + bounty_setup.child_bounty_value, + bounty_setup.reason.clone(), + ); + + assert_last_event::( + Event::Added { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + } + .into(), + ); + + Ok(()) } - propose_curator { + #[benchmark] + fn propose_curator() -> Result<(), BenchmarkError> { setup_pot_account::(); let bounty_setup = activate_bounty::(0, T::MaximumReasonLength::get())?; let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); - ChildBounties::::add_child_bounty( + Pallet::::add_child_bounty( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_value, bounty_setup.reason.clone(), )?; - let child_bounty_id = ChildBountyCount::::get() - 1; + let child_bounty_id = ParentTotalChildBounties::::get(bounty_setup.bounty_id) - 1; + + #[extrinsic_call] + _( + RawOrigin::Signed(bounty_setup.curator), + bounty_setup.bounty_id, + child_bounty_id, + child_curator_lookup, + bounty_setup.child_bounty_fee, + ); - }: _(RawOrigin::Signed(bounty_setup.curator), bounty_setup.bounty_id, - child_bounty_id, child_curator_lookup, bounty_setup.child_bounty_fee) + Ok(()) + } - accept_curator { + #[benchmark] + fn accept_curator() -> Result<(), BenchmarkError> { setup_pot_account::(); let mut bounty_setup = activate_bounty::(0, T::MaximumReasonLength::get())?; let child_curator_lookup = T::Lookup::unlookup(bounty_setup.child_curator.clone()); - ChildBounties::::add_child_bounty( + Pallet::::add_child_bounty( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_value, bounty_setup.reason.clone(), )?; - bounty_setup.child_bounty_id = ChildBountyCount::::get() - 1; + bounty_setup.child_bounty_id = + ParentTotalChildBounties::::get(bounty_setup.bounty_id) - 1; - ChildBounties::::propose_curator( + Pallet::::propose_curator( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_id, child_curator_lookup, bounty_setup.child_bounty_fee, )?; - }: _(RawOrigin::Signed(bounty_setup.child_curator), bounty_setup.bounty_id, - bounty_setup.child_bounty_id) + + #[extrinsic_call] + _( + RawOrigin::Signed(bounty_setup.child_curator), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + ); + + Ok(()) + } // Worst case when curator is inactive and any sender un-assigns the curator. - unassign_curator { + #[benchmark] + fn unassign_curator() -> Result<(), BenchmarkError> { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; Treasury::::on_initialize(frame_system::Pallet::::block_number()); set_block_number::(T::SpendPeriod::get() + T::BountyUpdatePeriod::get() + 1u32.into()); let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), bounty_setup.bounty_id, - bounty_setup.child_bounty_id) - award_child_bounty { + #[extrinsic_call] + _(RawOrigin::Signed(caller), bounty_setup.bounty_id, bounty_setup.child_bounty_id); + + Ok(()) + } + + #[benchmark] + fn award_child_bounty() -> Result<(), BenchmarkError> { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; - let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); + let beneficiary_account = account::("beneficiary", 0, SEED); let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); - }: _(RawOrigin::Signed(bounty_setup.child_curator), bounty_setup.bounty_id, - bounty_setup.child_bounty_id, beneficiary) - verify { - assert_last_event::(Event::Awarded { - index: bounty_setup.bounty_id, - child_index: bounty_setup.child_bounty_id, - beneficiary: beneficiary_account - }.into()) + + #[extrinsic_call] + _( + RawOrigin::Signed(bounty_setup.child_curator), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + beneficiary, + ); + + assert_last_event::( + Event::Awarded { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + beneficiary: beneficiary_account, + } + .into(), + ); + + Ok(()) } - claim_child_bounty { + #[benchmark] + fn claim_child_bounty() -> Result<(), BenchmarkError> { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; - let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); + let beneficiary_account = account("beneficiary", 0, SEED); let beneficiary = T::Lookup::unlookup(beneficiary_account); - ChildBounties::::award_child_bounty( + Pallet::::award_child_bounty( RawOrigin::Signed(bounty_setup.child_curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_id, - beneficiary + beneficiary, )?; - let beneficiary_account: T::AccountId = account("beneficiary", 0, SEED); - let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); + let beneficiary_account = account("beneficiary", 0, SEED); set_block_number::(T::SpendPeriod::get() + T::BountyDepositPayoutDelay::get()); - ensure!(T::Currency::free_balance(&beneficiary_account).is_zero(), - "Beneficiary already has balance."); - - }: _(RawOrigin::Signed(bounty_setup.curator), bounty_setup.bounty_id, - bounty_setup.child_bounty_id) - verify { - ensure!(!T::Currency::free_balance(&beneficiary_account).is_zero(), - "Beneficiary didn't get paid."); + ensure!( + T::Currency::free_balance(&beneficiary_account).is_zero(), + "Beneficiary already has balance." + ); + + #[extrinsic_call] + _( + RawOrigin::Signed(bounty_setup.curator), + bounty_setup.bounty_id, + bounty_setup.child_bounty_id, + ); + + ensure!( + !T::Currency::free_balance(&beneficiary_account).is_zero(), + "Beneficiary didn't get paid." + ); + + Ok(()) } // Best case scenario. - close_child_bounty_added { + #[benchmark] + fn close_child_bounty_added() -> Result<(), BenchmarkError> { setup_pot_account::(); let mut bounty_setup = activate_bounty::(0, T::MaximumReasonLength::get())?; - ChildBounties::::add_child_bounty( + Pallet::::add_child_bounty( RawOrigin::Signed(bounty_setup.curator.clone()).into(), bounty_setup.bounty_id, bounty_setup.child_bounty_value, bounty_setup.reason.clone(), )?; - bounty_setup.child_bounty_id = ChildBountyCount::::get() - 1; - - }: close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, - bounty_setup.child_bounty_id) - verify { - assert_last_event::(Event::Canceled { - index: bounty_setup.bounty_id, - child_index: bounty_setup.child_bounty_id - }.into()) + bounty_setup.child_bounty_id = + ParentTotalChildBounties::::get(bounty_setup.bounty_id) - 1; + + #[extrinsic_call] + close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id); + + assert_last_event::( + Event::Canceled { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + } + .into(), + ); + + Ok(()) } // Worst case scenario. - close_child_bounty_active { + #[benchmark] + fn close_child_bounty_active() -> Result<(), BenchmarkError> { setup_pot_account::(); let bounty_setup = activate_child_bounty::(0, T::MaximumReasonLength::get())?; Treasury::::on_initialize(frame_system::Pallet::::block_number()); - }: close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id) - verify { - assert_last_event::(Event::Canceled { - index: bounty_setup.bounty_id, - child_index: bounty_setup.child_bounty_id, - }.into()) + + #[extrinsic_call] + close_child_bounty(RawOrigin::Root, bounty_setup.bounty_id, bounty_setup.child_bounty_id); + + assert_last_event::( + Event::Canceled { + index: bounty_setup.bounty_id, + child_index: bounty_setup.child_bounty_id, + } + .into(), + ); + + Ok(()) } - impl_benchmark_test_suite!(ChildBounties, crate::tests::new_test_ext(), crate::tests::Test) + impl_benchmark_test_suite! { + Pallet, + tests::new_test_ext(), + tests::Test + } } diff --git a/substrate/frame/child-bounties/src/lib.rs b/substrate/frame/child-bounties/src/lib.rs index 1e970b6ae67c..9fca26510989 100644 --- a/substrate/frame/child-bounties/src/lib.rs +++ b/substrate/frame/child-bounties/src/lib.rs @@ -53,11 +53,15 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +pub mod migration; mod tests; pub mod weights; extern crate alloc; +/// The log target for this pallet. +const LOG_TARGET: &str = "runtime::child-bounties"; + use alloc::vec::Vec; use frame_support::traits::{ @@ -75,7 +79,9 @@ use sp_runtime::{ }; use frame_support::pallet_prelude::*; -use frame_system::pallet_prelude::*; +use frame_system::pallet_prelude::{ + ensure_signed, BlockNumberFor as SystemBlockNumberFor, OriginFor, +}; use pallet_bounties::BountyStatus; use scale_info::TypeInfo; pub use weights::WeightInfo; @@ -86,6 +92,8 @@ type BalanceOf = pallet_treasury::BalanceOf; type BountiesError = pallet_bounties::Error; type BountyIndex = pallet_bounties::BountyIndex; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type BlockNumberFor = + <::BlockNumberProvider as BlockNumberProvider>::BlockNumber; /// A child bounty proposal. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -134,7 +142,11 @@ pub mod pallet { use super::*; + /// The in-code storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -184,16 +196,22 @@ pub mod pallet { Canceled { index: BountyIndex, child_index: BountyIndex }, } - /// Number of total child bounties. + /// DEPRECATED: Replaced with `ParentTotalChildBounties` storage item keeping dedicated counts + /// for each parent bounty. Number of total child bounties. Will be removed in May 2025. #[pallet::storage] pub type ChildBountyCount = StorageValue<_, BountyIndex, ValueQuery>; - /// Number of child bounties per parent bounty. + /// Number of active child bounties per parent bounty. /// Map of parent bounty index to number of child bounties. #[pallet::storage] pub type ParentChildBounties = StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>; + /// Number of total child bounties per parent bounty, including completed bounties. + #[pallet::storage] + pub type ParentTotalChildBounties = + StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>; + /// Child bounties that have been added. #[pallet::storage] pub type ChildBounties = StorageDoubleMap< @@ -205,10 +223,27 @@ pub mod pallet { ChildBounty, BlockNumberFor>, >; - /// The description of each child-bounty. + /// The description of each child-bounty. Indexed by `(parent_id, child_id)`. + /// + /// This item replaces the `ChildBountyDescriptions` storage item from the V0 storage version. #[pallet::storage] - pub type ChildBountyDescriptions = - StorageMap<_, Twox64Concat, BountyIndex, BoundedVec>; + pub type ChildBountyDescriptionsV1 = StorageDoubleMap< + _, + Twox64Concat, + BountyIndex, + Twox64Concat, + BountyIndex, + BoundedVec, + >; + + /// The mapping of the child bounty ids from storage version `V0` to the new `V1` version. + /// + /// The `V0` ids based on total child bounty count [`ChildBountyCount`]`. The `V1` version ids + /// based on the child bounty count per parent bounty [`ParentTotalChildBounties`]. + /// The item intended solely for client convenience and not used in the pallet's core logic. + #[pallet::storage] + pub type V0ToV1ChildBountyIds = + StorageMap<_, Twox64Concat, BountyIndex, (BountyIndex, BountyIndex)>; /// The cumulative child-bounty curator fee for each parent bounty. #[pallet::storage] @@ -276,15 +311,19 @@ pub mod pallet { )?; // Get child-bounty ID. - let child_bounty_id = ChildBountyCount::::get(); - let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); + let child_bounty_id = ParentTotalChildBounties::::get(parent_bounty_id); + let child_bounty_account = + Self::child_bounty_account_id(parent_bounty_id, child_bounty_id); // Transfer funds from parent bounty to child-bounty. T::Currency::transfer(&parent_bounty_account, &child_bounty_account, value, KeepAlive)?; // Increment the active child-bounty count. ParentChildBounties::::mutate(parent_bounty_id, |count| count.saturating_inc()); - ChildBountyCount::::put(child_bounty_id.saturating_add(1)); + ParentTotalChildBounties::::insert( + parent_bounty_id, + child_bounty_id.saturating_add(1), + ); // Create child-bounty instance. Self::create_child_bounty( @@ -672,7 +711,8 @@ pub mod pallet { ); // Make curator fee payment. - let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); + let child_bounty_account = + Self::child_bounty_account_id(parent_bounty_id, child_bounty_id); let balance = T::Currency::free_balance(&child_bounty_account); let curator_fee = child_bounty.fee.min(balance); let payout = balance.saturating_sub(curator_fee); @@ -716,7 +756,7 @@ pub mod pallet { }); // Remove the child-bounty description. - ChildBountyDescriptions::::remove(child_bounty_id); + ChildBountyDescriptionsV1::::remove(parent_bounty_id, child_bounty_id); // Remove the child-bounty instance from the state. *maybe_child_bounty = None; @@ -772,6 +812,19 @@ pub mod pallet { Ok(()) } } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + let parent_bounty_id: BountyIndex = 1; + let child_bounty_id: BountyIndex = 2; + let _: T::AccountId = T::PalletId::get() + .try_into_sub_account(("cb", parent_bounty_id, child_bounty_id)) + .expect( + "The `AccountId` type must be large enough to fit the child bounty account ID.", + ); + } + } } impl Pallet { @@ -797,11 +850,14 @@ impl Pallet { } /// The account ID of a child-bounty account. - pub fn child_bounty_account_id(id: BountyIndex) -> T::AccountId { + pub fn child_bounty_account_id( + parent_bounty_id: BountyIndex, + child_bounty_id: BountyIndex, + ) -> T::AccountId { // This function is taken from the parent (bounties) pallet, but the // prefix is changed to have different AccountId when the index of // parent and child is same. - T::PalletId::get().into_sub_account_truncating(("cb", id)) + T::PalletId::get().into_sub_account_truncating(("cb", parent_bounty_id, child_bounty_id)) } fn create_child_bounty( @@ -818,7 +874,7 @@ impl Pallet { status: ChildBountyStatus::Added, }; ChildBounties::::insert(parent_bounty_id, child_bounty_id, &child_bounty); - ChildBountyDescriptions::::insert(child_bounty_id, description); + ChildBountyDescriptionsV1::::insert(parent_bounty_id, child_bounty_id, description); Self::deposit_event(Event::Added { index: parent_bounty_id, child_index: child_bounty_id }); } @@ -877,7 +933,8 @@ impl Pallet { // Transfer fund from child-bounty to parent bounty. let parent_bounty_account = pallet_bounties::Pallet::::bounty_account_id(parent_bounty_id); - let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); + let child_bounty_account = + Self::child_bounty_account_id(parent_bounty_id, child_bounty_id); let balance = T::Currency::free_balance(&child_bounty_account); let transfer_result = T::Currency::transfer( &child_bounty_account, @@ -888,7 +945,7 @@ impl Pallet { debug_assert!(transfer_result.is_ok()); // Remove the child-bounty description. - ChildBountyDescriptions::::remove(child_bounty_id); + ChildBountyDescriptionsV1::::remove(parent_bounty_id, child_bounty_id); *maybe_child_bounty = None; @@ -902,16 +959,22 @@ impl Pallet { } } -// Implement ChildBountyManager to connect with the bounties pallet. This is -// where we pass the active child bounties and child curator fees to the parent -// bounty. +/// Implement ChildBountyManager to connect with the bounties pallet. This is +/// where we pass the active child bounties and child curator fees to the parent +/// bounty. +/// +/// Function `children_curator_fees` not only returns the fee but also removes cumulative curator +/// fees during call. impl pallet_bounties::ChildBountyManager> for Pallet { + /// Returns number of active child bounties for `bounty_id` fn child_bounties_count( bounty_id: pallet_bounties::BountyIndex, ) -> pallet_bounties::BountyIndex { ParentChildBounties::::get(bounty_id) } + /// Returns cumulative child bounty curator fees for `bounty_id` also removing the associated + /// storage item. This function is assumed to be called when parent bounty is claimed. fn children_curator_fees(bounty_id: pallet_bounties::BountyIndex) -> BalanceOf { // This is asked for when the parent bounty is being claimed. No use of // keeping it in state after that. Hence removing. @@ -919,4 +982,14 @@ impl pallet_bounties::ChildBountyManager> for Pallet ChildrenCuratorFees::::remove(bounty_id); children_fee_total } + + /// Clean up the storage on a parent bounty removal. + fn bounty_removed(bounty_id: BountyIndex) { + debug_assert!(ParentChildBounties::::get(bounty_id).is_zero()); + debug_assert!(ChildrenCuratorFees::::get(bounty_id).is_zero()); + debug_assert!(ChildBounties::::iter_key_prefix(bounty_id).count().is_zero()); + debug_assert!(ChildBountyDescriptionsV1::::iter_key_prefix(bounty_id).count().is_zero()); + ParentChildBounties::::remove(bounty_id); + ParentTotalChildBounties::::remove(bounty_id); + } } diff --git a/substrate/frame/child-bounties/src/migration.rs b/substrate/frame/child-bounties/src/migration.rs new file mode 100644 index 000000000000..52232a5a7f2f --- /dev/null +++ b/substrate/frame/child-bounties/src/migration.rs @@ -0,0 +1,229 @@ +// 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. + +use super::*; +use core::marker::PhantomData; +use frame_support::{ + storage_alias, + traits::{Get, UncheckedOnRuntimeUpgrade}, +}; + +use alloc::collections::BTreeSet; +#[cfg(feature = "try-runtime")] +use alloc::vec::Vec; +#[cfg(feature = "try-runtime")] +use frame_support::ensure; + +pub mod v1 { + use super::*; + + /// Creates a new ids for the child balances based on the child bounty count per parent bounty + /// instead of the total child bounty count. Translates the existing child bounties to the new + /// ids. Creates the `V0ToV1ChildBountyIds` map from `old_child_id` to new (`parent_id`, + /// `new_child_id`). + /// + /// `TransferWeight` returns `Weight` of `T::Currency::transfer` and `T::Currency::free_balance` + /// operation which is performed during this migration. + pub struct MigrateToV1Impl(PhantomData<(T, TransferWeight)>); + + #[storage_alias] + type ChildBountyDescriptions = StorageMap< + Pallet, + Twox64Concat, + BountyIndex, + BoundedVec::MaximumReasonLength>, + >; + + impl> UncheckedOnRuntimeUpgrade + for MigrateToV1Impl + { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // increment reads/writes after the action + let mut reads = 0u64; + let mut writes = 0u64; + let mut transfer_weights: Weight = Weight::zero(); + + // keep ids order roughly the same with the old order + let mut old_bounty_ids = BTreeSet::new(); + // first iteration collect all existing ids not to mutate map as we iterate it + for (parent_bounty_id, old_child_bounty_id) in ChildBounties::::iter_keys() { + reads += 1; + old_bounty_ids.insert((parent_bounty_id, old_child_bounty_id)); + } + + log::info!( + target: LOG_TARGET, + "Migrating {} child bounties", + old_bounty_ids.len(), + ); + + for (parent_bounty_id, old_child_bounty_id) in old_bounty_ids { + // assign new child bounty id + let new_child_bounty_id = ParentTotalChildBounties::::get(parent_bounty_id); + reads += 1; + ParentTotalChildBounties::::insert( + parent_bounty_id, + new_child_bounty_id.saturating_add(1), + ); + writes += 1; + + V0ToV1ChildBountyIds::::insert( + old_child_bounty_id, + (parent_bounty_id, new_child_bounty_id), + ); + writes += 1; + + let old_child_bounty_account = + Self::old_child_bounty_account_id(old_child_bounty_id); + let new_child_bounty_account = + Pallet::::child_bounty_account_id(parent_bounty_id, new_child_bounty_id); + let old_balance = T::Currency::free_balance(&old_child_bounty_account); + log::info!( + "Transferring {:?} funds from old child bounty account {:?} to new child bounty account {:?}", + old_balance, old_child_bounty_account, new_child_bounty_account + ); + if let Err(err) = T::Currency::transfer( + &old_child_bounty_account, + &new_child_bounty_account, + old_balance, + AllowDeath, + ) { + log::error!( + target: LOG_TARGET, + "Error transferring funds: {:?}", + err + ); + } + transfer_weights += TransferWeight::get(); + + log::info!( + target: LOG_TARGET, + "Remapped parent bounty {} child bounty id {}->{}", + parent_bounty_id, + old_child_bounty_id, + new_child_bounty_id, + ); + + let bounty_description = ChildBountyDescriptions::::take(old_child_bounty_id); + writes += 1; + let child_bounty = ChildBounties::::take(parent_bounty_id, old_child_bounty_id); + writes += 1; + + // should always be some + if let Some(taken) = child_bounty { + ChildBounties::::insert(parent_bounty_id, new_child_bounty_id, taken); + writes += 1; + } else { + log::error!( + "child bounty with old id {} not found, should be impossible", + old_child_bounty_id + ); + } + if let Some(bounty_description) = bounty_description { + super::super::ChildBountyDescriptionsV1::::insert( + parent_bounty_id, + new_child_bounty_id, + bounty_description, + ); + writes += 1; + } else { + log::error!( + "child bounty description with old id {} not found, should be impossible", + old_child_bounty_id + ); + } + } + + log::info!( + target: LOG_TARGET, + "Migration done, reads: {}, writes: {}, transfer weights: {}", + reads, writes, transfer_weights + ); + + T::DbWeight::get().reads_writes(reads, writes) + transfer_weights + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let old_child_bounty_count = ChildBounties::::iter_keys().count() as u32; + let old_child_bounty_descriptions = + v1::ChildBountyDescriptions::::iter_keys().count() as u32; + let old_child_bounty_ids = ChildBounties::::iter_keys().collect::>(); + Ok((old_child_bounty_count, old_child_bounty_descriptions, old_child_bounty_ids) + .encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + type StateType = (u32, u32, Vec<(u32, u32)>); + let (old_child_bounty_count, old_child_bounty_descriptions, old_child_bounty_ids) = + StateType::decode(&mut &state[..]).expect("Can't decode previous state"); + let new_child_bounty_count = ChildBounties::::iter_keys().count() as u32; + let new_child_bounty_descriptions = + super::super::ChildBountyDescriptionsV1::::iter_keys().count() as u32; + + ensure!( + old_child_bounty_count == new_child_bounty_count, + "child bounty count doesn't match" + ); + ensure!( + old_child_bounty_descriptions == new_child_bounty_descriptions, + "child bounty descriptions count doesn't match" + ); + + let old_child_bounty_descriptions_storage = + v1::ChildBountyDescriptions::::iter_keys().count(); + log::info!("old child bounty descriptions: {}", old_child_bounty_descriptions_storage); + ensure!( + old_child_bounty_descriptions_storage == 0, + "Old bounty descriptions should have been drained." + ); + + for (_, old_child_bounty_id) in old_child_bounty_ids { + let old_account_id = Self::old_child_bounty_account_id(old_child_bounty_id); + let balance = T::Currency::total_balance(&old_account_id); + if !balance.is_zero() { + log::error!( + "Old child bounty id {} still has balance {:?}", + old_child_bounty_id, + balance + ); + } + } + + Ok(()) + } + } + + impl> MigrateToV1Impl { + fn old_child_bounty_account_id(id: BountyIndex) -> T::AccountId { + // This function is taken from the parent (bounties) pallet, but the + // prefix is changed to have different AccountId when the index of + // parent and child is same. + T::PalletId::get().into_sub_account_truncating(("cb", id)) + } + } +} + +/// Migrate the pallet storage from `0` to `1`. +pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + v1::MigrateToV1Impl, + Pallet, + ::DbWeight, +>; diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 96d01b03560d..939983054f66 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -66,10 +66,16 @@ parameter_types! { } type Balance = u64; +// must be at least 20 bytes long because of child-bounty account derivation. +type AccountId = sp_core::U256; + +fn account_id(id: u8) -> AccountId { + sp_core::U256::from(id) +} #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { - type AccountId = u128; + type AccountId = AccountId; type Lookup = IdentityLookup; type Block = Block; type AccountData = pallet_balances::AccountData; @@ -82,14 +88,14 @@ impl pallet_balances::Config for Test { parameter_types! { pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub TreasuryAccount: u128 = Treasury::account_id(); + pub TreasuryAccount: AccountId = Treasury::account_id(); pub const SpendLimit: Balance = u64::MAX; } impl pallet_treasury::Config for Test { type PalletId = TreasuryPalletId; type Currency = pallet_balances::Pallet; - type RejectOrigin = frame_system::EnsureRoot; + type RejectOrigin = frame_system::EnsureRoot; type RuntimeEvent = RuntimeEvent; type SpendPeriod = ConstU64<2>; type Burn = Burn; @@ -141,7 +147,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { // Total issuance will be 200 with treasury account initialized at ED. - balances: vec![(0, 100), (1, 98), (2, 1)], + balances: vec![(account_id(0), 100), (account_id(1), 98), (account_id(2), 1)], } .assimilate_storage(&mut t) .unwrap(); @@ -161,6 +167,7 @@ fn last_event() -> ChildBountiesEvent { } #[test] +#[allow(deprecated)] fn genesis_config_works() { new_test_ext().execute_with(|| { assert_eq!(Treasury::pot(), 0); @@ -194,52 +201,71 @@ fn add_child_bounty() { go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); let fee = 8; - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), fee)); - Balances::make_free_balance_be(&4, 10); + Balances::make_free_balance_be(&account_id(4), 10); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // This verifies that the accept curator logic took a deposit. let expected_deposit = CuratorDepositMultiplier::get() * fee; - assert_eq!(Balances::reserved_balance(&4), expected_deposit); - assert_eq!(Balances::free_balance(&4), 10 - expected_deposit); + assert_eq!(Balances::reserved_balance(&account_id(4)), expected_deposit); + assert_eq!(Balances::free_balance(&account_id(4)), 10 - expected_deposit); // Add child-bounty. // Acc-4 is the parent curator. // Call from invalid origin & check for error "RequireCurator". assert_noop!( - ChildBounties::add_child_bounty(RuntimeOrigin::signed(0), 0, 10, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty( + RuntimeOrigin::signed(account_id(0)), + 0, + 10, + b"12345-p1".to_vec() + ), BountiesError::RequireCurator, ); // Update the parent curator balance. - Balances::make_free_balance_be(&4, 101); + Balances::make_free_balance_be(&account_id(4), 101); // parent curator fee is reserved on parent bounty account. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); assert_noop!( - ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 50, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty( + RuntimeOrigin::signed(account_id(4)), + 0, + 50, + b"12345-p1".to_vec() + ), TokenError::NotExpendable, ); assert_noop!( - ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 100, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty( + RuntimeOrigin::signed(account_id(4)), + 0, + 100, + b"12345-p1".to_vec() + ), Error::::InsufficientBountyBalance, ); // Add child-bounty with valid value, which can be funded by parent bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -248,8 +274,8 @@ fn add_child_bounty() { // Check for the event child-bounty added. assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); - assert_eq!(Balances::free_balance(4), 101); - assert_eq!(Balances::reserved_balance(4), expected_deposit); + assert_eq!(Balances::free_balance(account_id(4)), 101); + assert_eq!(Balances::reserved_balance(account_id(4)), expected_deposit); // DB check. // Check the child-bounty status. @@ -269,7 +295,7 @@ fn add_child_bounty() { // Check the child-bounty description status. assert_eq!( - pallet_child_bounties::ChildBountyDescriptions::::get(0).unwrap(), + pallet_child_bounties::ChildBountyDescriptionsV1::::get(0, 0).unwrap(), b"12345-p1".to_vec(), ); }); @@ -286,18 +312,22 @@ fn child_bounty_assign_curator() { // Make the parent bounty. go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - Balances::make_free_balance_be(&4, 101); - Balances::make_free_balance_be(&8, 101); + Balances::make_free_balance_be(&account_id(4), 101); + Balances::make_free_balance_be(&account_id(8), 101); - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); let fee = 4; - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Bounty account status before adding child-bounty. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); @@ -306,13 +336,13 @@ fn child_bounty_assign_curator() { // Check the balance of parent curator. // Curator deposit is reserved for parent curator on parent bounty. let expected_deposit = Bounties::calculate_curator_deposit(&fee); - assert_eq!(Balances::free_balance(4), 101 - expected_deposit); - assert_eq!(Balances::reserved_balance(4), expected_deposit); + assert_eq!(Balances::free_balance(account_id(4)), 101 - expected_deposit); + assert_eq!(Balances::reserved_balance(account_id(4)), expected_deposit); // Add child-bounty. // Acc-4 is the parent curator & make sure enough deposit. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -325,11 +355,17 @@ fn child_bounty_assign_curator() { assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); // Child-bounty account status. - assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); - assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0, 0)), 10); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); let fee = 6u64; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + fee + )); assert_eq!( pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), @@ -338,20 +374,20 @@ fn child_bounty_assign_curator() { value: 10, fee, curator_deposit: 0, - status: ChildBountyStatus::CuratorProposed { curator: 8 }, + status: ChildBountyStatus::CuratorProposed { curator: account_id(8) }, } ); // Check the balance of parent curator. - assert_eq!(Balances::free_balance(4), 101 - expected_deposit); - assert_eq!(Balances::reserved_balance(4), expected_deposit); + assert_eq!(Balances::free_balance(account_id(4)), 101 - expected_deposit); + assert_eq!(Balances::reserved_balance(account_id(4)), expected_deposit); assert_noop!( - ChildBounties::accept_curator(RuntimeOrigin::signed(3), 0, 0), + ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(3)), 0, 0), BountiesError::RequireCurator, ); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; @@ -362,21 +398,21 @@ fn child_bounty_assign_curator() { value: 10, fee, curator_deposit: expected_child_deposit, - status: ChildBountyStatus::Active { curator: 8 }, + status: ChildBountyStatus::Active { curator: account_id(8) }, } ); // Deposit for child-bounty curator deposit is reserved. - assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); - assert_eq!(Balances::reserved_balance(8), expected_child_deposit); + assert_eq!(Balances::free_balance(account_id(8)), 101 - expected_child_deposit); + assert_eq!(Balances::reserved_balance(account_id(8)), expected_child_deposit); // Bounty account status at exit. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 40); assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); // Child-bounty account status at exit. - assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); - assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0, 0)), 10); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); // Treasury account status at exit. assert_eq!(Balances::free_balance(Treasury::account_id()), 26); @@ -394,21 +430,25 @@ fn award_claim_child_bounty() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -418,17 +458,33 @@ fn award_claim_child_bounty() { // Propose and accept curator for child-bounty. let fee = 8; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); // Award child-bounty. // Test for non child-bounty curator. assert_noop!( - ChildBounties::award_child_bounty(RuntimeOrigin::signed(3), 0, 0, 7), + ChildBounties::award_child_bounty( + RuntimeOrigin::signed(account_id(3)), + 0, + 0, + account_id(7) + ), BountiesError::RequireCurator, ); - assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty( + RuntimeOrigin::signed(account_id(8)), + 0, + 0, + account_id(7) + )); let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -439,8 +495,8 @@ fn award_claim_child_bounty() { fee, curator_deposit: expected_deposit, status: ChildBountyStatus::PendingPayout { - curator: 8, - beneficiary: 7, + curator: account_id(8), + beneficiary: account_id(7), unlock_at: 5 }, } @@ -449,25 +505,25 @@ fn award_claim_child_bounty() { // Claim child-bounty. // Test for Premature condition. assert_noop!( - ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0), + ChildBounties::claim_child_bounty(RuntimeOrigin::signed(account_id(7)), 0, 0), BountiesError::Premature ); go_to_block(9); - assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); + assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(account_id(7)), 0, 0)); // Ensure child-bounty curator is paid with curator fee & deposit refund. - assert_eq!(Balances::free_balance(8), 101 + fee); - assert_eq!(Balances::reserved_balance(8), 0); + assert_eq!(Balances::free_balance(account_id(8)), 101 + fee); + assert_eq!(Balances::reserved_balance(account_id(8)), 0); // Ensure executor is paid with beneficiary amount. - assert_eq!(Balances::free_balance(7), 10 - fee); - assert_eq!(Balances::reserved_balance(7), 0); + assert_eq!(Balances::free_balance(account_id(7)), 10 - fee); + assert_eq!(Balances::reserved_balance(account_id(7)), 0); // Child-bounty account status. - assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 0); - assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); // Check the child-bounty count. assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); @@ -484,22 +540,26 @@ fn close_child_bounty_added() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -511,11 +571,17 @@ fn close_child_bounty_added() { // Close child-bounty. // Wrong origin. - assert_noop!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(7), 0, 0), BadOrigin); - assert_noop!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(8), 0, 0), BadOrigin); + assert_noop!( + ChildBounties::close_child_bounty(RuntimeOrigin::signed(account_id(7)), 0, 0), + BadOrigin + ); + assert_noop!( + ChildBounties::close_child_bounty(RuntimeOrigin::signed(account_id(8)), 0, 0), + BadOrigin + ); // Correct origin - parent curator. - assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(account_id(4)), 0, 0)); // Check the child-bounty count. assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); @@ -525,8 +591,8 @@ fn close_child_bounty_added() { assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); // Child-bounty account status. - assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 0); - assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); }); } @@ -540,22 +606,26 @@ fn close_child_bounty_active() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -564,26 +634,32 @@ fn close_child_bounty_active() { assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + 2 + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); // Close child-bounty in active state. - assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(account_id(4)), 0, 0)); // Check the child-bounty count. assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); // Ensure child-bounty curator balance is unreserved. - assert_eq!(Balances::free_balance(8), 101); - assert_eq!(Balances::reserved_balance(8), 0); + assert_eq!(Balances::free_balance(account_id(8)), 101); + assert_eq!(Balances::reserved_balance(account_id(8)), 0); // Parent-bounty account status. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); // Child-bounty account status. - assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 0); - assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); }); } @@ -597,22 +673,26 @@ fn close_child_bounty_pending() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); let parent_fee = 6; - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, parent_fee)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), parent_fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -622,15 +702,26 @@ fn close_child_bounty_pending() { // Propose and accept curator for child-bounty. let child_fee = 4; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, child_fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + child_fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); - assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty( + RuntimeOrigin::signed(account_id(8)), + 0, + 0, + account_id(7) + )); // Close child-bounty in pending_payout state. assert_noop!( - ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0), + ChildBounties::close_child_bounty(RuntimeOrigin::signed(account_id(4)), 0, 0), BountiesError::PendingPayout ); @@ -638,12 +729,12 @@ fn close_child_bounty_pending() { assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 1); // Ensure no changes in child-bounty curator balance. - assert_eq!(Balances::reserved_balance(8), expected_child_deposit); - assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); + assert_eq!(Balances::reserved_balance(account_id(8)), expected_child_deposit); + assert_eq!(Balances::free_balance(account_id(8)), 101 - expected_child_deposit); // Child-bounty account status. - assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0)), 10); - assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); + assert_eq!(Balances::free_balance(ChildBounties::child_bounty_account_id(0, 0)), 10); + assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0, 0)), 0); }); } @@ -657,22 +748,26 @@ fn child_bounty_added_unassign_curator() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -682,7 +777,7 @@ fn child_bounty_added_unassign_curator() { // Unassign curator in added state. assert_noop!( - ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(4)), 0, 0), BountiesError::UnexpectedStatus ); }); @@ -698,22 +793,26 @@ fn child_bounty_curator_proposed_unassign_curator() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -722,7 +821,13 @@ fn child_bounty_curator_proposed_unassign_curator() { assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + 2 + )); assert_eq!( pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), @@ -731,15 +836,18 @@ fn child_bounty_curator_proposed_unassign_curator() { value: 10, fee: 2, curator_deposit: 0, - status: ChildBountyStatus::CuratorProposed { curator: 8 }, + status: ChildBountyStatus::CuratorProposed { curator: account_id(8) }, } ); // Random account cannot unassign the curator when in proposed state. - assert_noop!(ChildBounties::unassign_curator(RuntimeOrigin::signed(99), 0, 0), BadOrigin); + assert_noop!( + ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(99)), 0, 0), + BadOrigin + ); // Unassign curator. - assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(4)), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -772,23 +880,27 @@ fn child_bounty_active_unassign_curator() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&6, 101); // Child-bounty curator 1. - Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(6), 101); // Child-bounty curator 1. + Balances::make_free_balance_be(&account_id(7), 101); // Child-bounty curator 2. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator 3. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Create Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -799,8 +911,14 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty. let fee = 6; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -810,7 +928,7 @@ fn child_bounty_active_unassign_curator() { value: 10, fee, curator_deposit: expected_child_deposit, - status: ChildBountyStatus::Active { curator: 8 }, + status: ChildBountyStatus::Active { curator: account_id(8) }, } ); @@ -832,13 +950,19 @@ fn child_bounty_active_unassign_curator() { ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); - assert_eq!(Balances::reserved_balance(8), 0); // slashed + assert_eq!(Balances::free_balance(account_id(8)), 101 - expected_child_deposit); + assert_eq!(Balances::reserved_balance(account_id(8)), 0); // slashed // Propose and accept curator for child-bounty again. let fee = 2; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 7, fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(7), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(7), + fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(7)), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( @@ -848,14 +972,14 @@ fn child_bounty_active_unassign_curator() { value: 10, fee, curator_deposit: expected_child_deposit, - status: ChildBountyStatus::Active { curator: 7 }, + status: ChildBountyStatus::Active { curator: account_id(7) }, } ); go_to_block(5); // Unassign curator again - from parent curator. - assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(4)), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -870,12 +994,18 @@ fn child_bounty_active_unassign_curator() { ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(7), 101 - expected_child_deposit); - assert_eq!(Balances::reserved_balance(7), 0); // slashed + assert_eq!(Balances::free_balance(account_id(7)), 101 - expected_child_deposit); + assert_eq!(Balances::reserved_balance(account_id(7)), 0); // slashed // Propose and accept curator for child-bounty again. - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 6, 2)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(6), + 2 + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(6)), 0, 0)); assert_eq!( pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), @@ -884,14 +1014,14 @@ fn child_bounty_active_unassign_curator() { value: 10, fee, curator_deposit: expected_child_deposit, - status: ChildBountyStatus::Active { curator: 6 }, + status: ChildBountyStatus::Active { curator: account_id(6) }, } ); go_to_block(6); // Unassign curator again - from child-bounty curator. - assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(6), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(6)), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -906,13 +1036,19 @@ fn child_bounty_active_unassign_curator() { ); // Ensure child-bounty curator was **not** slashed. - assert_eq!(Balances::free_balance(6), 101); // not slashed - assert_eq!(Balances::reserved_balance(6), 0); + assert_eq!(Balances::free_balance(account_id(6)), 101); // not slashed + assert_eq!(Balances::reserved_balance(account_id(6)), 0); // Propose and accept curator for child-bounty one last time. let fee = 2; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 6, fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(6), + fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(6)), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( @@ -922,7 +1058,7 @@ fn child_bounty_active_unassign_curator() { value: 10, fee, curator_deposit: expected_child_deposit, - status: ChildBountyStatus::Active { curator: 6 }, + status: ChildBountyStatus::Active { curator: account_id(6) }, } ); @@ -931,14 +1067,14 @@ fn child_bounty_active_unassign_curator() { // Unassign curator again - from non curator; non reject origin; some random guy. // Bounty update period is not yet complete. assert_noop!( - ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(3)), 0, 0), BountiesError::Premature ); go_to_block(20); // Unassign child curator from random account after inactivity. - assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(3)), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -953,8 +1089,8 @@ fn child_bounty_active_unassign_curator() { ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(6), 101 - expected_child_deposit); // slashed - assert_eq!(Balances::reserved_balance(6), 0); + assert_eq!(Balances::free_balance(account_id(6)), 101 - expected_child_deposit); // slashed + assert_eq!(Balances::reserved_balance(account_id(6)), 0); }); } @@ -970,23 +1106,27 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator 1. - Balances::make_free_balance_be(&5, 101); // Parent-bounty curator 2. - Balances::make_free_balance_be(&6, 101); // Child-bounty curator 1. - Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator 1. + Balances::make_free_balance_be(&account_id(5), 101); // Parent-bounty curator 2. + Balances::make_free_balance_be(&account_id(6), 101); // Child-bounty curator 1. + Balances::make_free_balance_be(&account_id(7), 101); // Child-bounty curator 2. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator 3. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Create Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -997,8 +1137,14 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Propose and accept curator for child-bounty. let fee = 8; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -1008,7 +1154,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { value: 10, fee, curator_deposit: expected_child_deposit, - status: ChildBountyStatus::Active { curator: 8 }, + status: ChildBountyStatus::Active { curator: account_id(8) }, } ); @@ -1022,7 +1168,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Try unassign child-bounty curator - from non curator; non reject // origin; some random guy. Bounty update period is not yet complete. assert_noop!( - ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(3)), 0, 0), Error::::ParentBountyNotActive ); @@ -1042,21 +1188,27 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { ); // Ensure child-bounty curator was slashed. - assert_eq!(Balances::free_balance(8), 101 - expected_child_deposit); - assert_eq!(Balances::reserved_balance(8), 0); // slashed + assert_eq!(Balances::free_balance(account_id(8)), 101 - expected_child_deposit); + assert_eq!(Balances::reserved_balance(account_id(8)), 0); // slashed go_to_block(6); // Propose and accept curator for parent-bounty again. - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 5, 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(5), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(5), 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(5)), 0)); go_to_block(7); // Propose and accept curator for child-bounty again. let fee = 2; - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(5), 0, 0, 7, fee)); - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(7), 0, 0)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(5)), + 0, + 0, + account_id(7), + fee + )); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(7)), 0, 0)); let expected_deposit = CuratorDepositMin::get(); assert_eq!( @@ -1066,24 +1218,24 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { value: 10, fee, curator_deposit: expected_deposit, - status: ChildBountyStatus::Active { curator: 7 }, + status: ChildBountyStatus::Active { curator: account_id(7) }, } ); go_to_block(8); assert_noop!( - ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(3)), 0, 0), BountiesError::Premature ); // Unassign parent bounty curator again. - assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(5), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(account_id(5)), 0)); go_to_block(9); // Unassign curator again - from parent curator. - assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(7), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(account_id(7)), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -1098,8 +1250,8 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { ); // Ensure child-bounty curator was not slashed. - assert_eq!(Balances::free_balance(7), 101); - assert_eq!(Balances::reserved_balance(7), 0); // slashed + assert_eq!(Balances::free_balance(account_id(7)), 101); + assert_eq!(Balances::reserved_balance(account_id(7)), 0); // slashed }); } @@ -1113,27 +1265,36 @@ fn close_parent_with_child_bounty() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); // Try add child-bounty. // Should fail, parent bounty not active yet. assert_noop!( - ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 10, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty( + RuntimeOrigin::signed(account_id(4)), + 0, + 10, + b"12345-p1".to_vec() + ), Error::::ParentBountyNotActive ); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -1154,10 +1315,14 @@ fn close_parent_with_child_bounty() { // Check the child-bounty count. assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); + assert_eq!(pallet_child_bounties::ParentTotalChildBounties::::get(0), 1); // Try close parent-bounty again. // Should pass this time. assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); + + // Check the total count is removed after the parent bounty removal. + assert_eq!(pallet_child_bounties::ParentTotalChildBounties::::get(0), 0); }); } @@ -1173,20 +1338,24 @@ fn children_curator_fee_calculation_test() { assert_eq!(Balances::reserved_balance(Treasury::account_id()), 0); // Bounty curator initial balance. - Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. - Balances::make_free_balance_be(&8, 101); // Child-bounty curator. + Balances::make_free_balance_be(&account_id(4), 101); // Parent-bounty curator. + Balances::make_free_balance_be(&account_id(8), 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty( + RuntimeOrigin::signed(account_id(0)), + 50, + b"12345".to_vec() + )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); go_to_block(2); - assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, account_id(4), 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(account_id(4)), 0)); // Child-bounty. assert_ok!(ChildBounties::add_child_bounty( - RuntimeOrigin::signed(4), + RuntimeOrigin::signed(account_id(4)), 0, 10, b"12345-p1".to_vec() @@ -1198,13 +1367,24 @@ fn children_curator_fee_calculation_test() { let fee = 6; // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::propose_curator( + RuntimeOrigin::signed(account_id(4)), + 0, + 0, + account_id(8), + fee + )); // Check curator fee added to the sum. assert_eq!(pallet_child_bounties::ChildrenCuratorFees::::get(0), fee); // Accept curator for child-bounty. - assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(account_id(8)), 0, 0)); // Award child-bounty. - assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty( + RuntimeOrigin::signed(account_id(8)), + 0, + 0, + account_id(7) + )); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; @@ -1216,8 +1396,8 @@ fn children_curator_fee_calculation_test() { fee, curator_deposit: expected_child_deposit, status: ChildBountyStatus::PendingPayout { - curator: 8, - beneficiary: 7, + curator: account_id(8), + beneficiary: account_id(7), unlock_at: 7 }, } @@ -1226,26 +1406,32 @@ fn children_curator_fee_calculation_test() { go_to_block(9); // Claim child-bounty. - assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); + assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(account_id(7)), 0, 0)); // Check the child-bounty count. assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); // Award the parent bounty. - assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 9)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(account_id(4)), 0, account_id(9))); go_to_block(15); + // Check the total count. + assert_eq!(pallet_child_bounties::ParentTotalChildBounties::::get(0), 1); + // Claim the parent bounty. - assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(9), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(account_id(9)), 0)); + + // Check the total count after the parent bounty removal. + assert_eq!(pallet_child_bounties::ParentTotalChildBounties::::get(0), 0); // Ensure parent-bounty curator received correctly reduced fee. - assert_eq!(Balances::free_balance(4), 101 + 6 - fee); // 101 + 6 - 2 - assert_eq!(Balances::reserved_balance(4), 0); + assert_eq!(Balances::free_balance(account_id(4)), 101 + 6 - fee); // 101 + 6 - 2 + assert_eq!(Balances::reserved_balance(account_id(4)), 0); // Verify parent-bounty beneficiary balance. - assert_eq!(Balances::free_balance(9), 34); - assert_eq!(Balances::reserved_balance(9), 0); + assert_eq!(Balances::free_balance(account_id(9)), 34); + assert_eq!(Balances::reserved_balance(account_id(9)), 0); }); } @@ -1255,7 +1441,7 @@ fn accept_curator_handles_different_deposit_calculations() { // in a different curator deposit, and if the child curator matches the parent curator. new_test_ext().execute_with(|| { // Setup a parent bounty. - let parent_curator = 0; + let parent_curator = account_id(0); let parent_index = 0; let parent_value = 1_000_000; let parent_fee = 10_000; @@ -1284,7 +1470,7 @@ fn accept_curator_handles_different_deposit_calculations() { // Case 1: Parent and child curator are not the same. let child_index = 0; - let child_curator = 1; + let child_curator = account_id(1); let child_value = 1_000; let child_fee = 100; let starting_balance = 100 * child_fee + child_value; @@ -1351,7 +1537,7 @@ fn accept_curator_handles_different_deposit_calculations() { // Case 3: Upper Limit let child_index = 2; - let child_curator = 2; + let child_curator = account_id(2); let child_value = 10_000; let child_fee = 5_000; @@ -1386,7 +1572,7 @@ fn accept_curator_handles_different_deposit_calculations() { // Case 4: Lower Limit let child_index = 3; - let child_curator = 3; + let child_curator = account_id(3); let child_value = 10_000; let child_fee = 0; @@ -1416,3 +1602,10 @@ fn accept_curator_handles_different_deposit_calculations() { assert_eq!(Balances::reserved_balance(child_curator), expected_deposit); }); } + +#[test] +fn integrity_test() { + new_test_ext().execute_with(|| { + ChildBounties::integrity_test(); + }); +} diff --git a/substrate/frame/child-bounties/src/weights.rs b/substrate/frame/child-bounties/src/weights.rs index 1c0583d58e02..61bb5bca7a78 100644 --- a/substrate/frame/child-bounties/src/weights.rs +++ b/substrate/frame/child-bounties/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_child_bounties` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -70,19 +70,21 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyCount` (r:1 w:1) - /// Proof: `ChildBounties::ChildBountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentTotalChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) /// Storage: `ChildBounties::ChildBounties` (r:0 w:1) /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) /// The range of component `d` is `[0, 300]`. - fn add_child_bounty(_d: u32, ) -> Weight { + fn add_child_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `745` + // Measured: `812` // Estimated: `6196` - // Minimum execution time: 65_654_000 picoseconds. - Weight::from_parts(68_255_084, 6196) + // Minimum execution time: 71_601_000 picoseconds. + Weight::from_parts(74_162_244, 6196) + // Standard Error: 328 + .saturating_add(Weight::from_parts(1_528, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -94,10 +96,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `799` + // Measured: `842` // Estimated: `3642` - // Minimum execution time: 18_534_000 picoseconds. - Weight::from_parts(19_332_000, 3642) + // Minimum execution time: 24_835_000 picoseconds. + Weight::from_parts(26_049_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -109,10 +111,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `1048` // Estimated: `3642` - // Minimum execution time: 33_212_000 picoseconds. - Weight::from_parts(35_407_000, 3642) + // Minimum execution time: 40_409_000 picoseconds. + Weight::from_parts(41_432_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -124,10 +126,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `1048` // Estimated: `3642` - // Minimum execution time: 35_510_000 picoseconds. - Weight::from_parts(36_345_000, 3642) + // Minimum execution time: 49_747_000 picoseconds. + Weight::from_parts(51_222_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -137,10 +139,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `842` + // Measured: `908` // Estimated: `3642` - // Minimum execution time: 19_085_000 picoseconds. - Weight::from_parts(20_094_000, 3642) + // Minimum execution time: 26_462_000 picoseconds. + Weight::from_parts(27_166_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -150,14 +152,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `682` + // Measured: `752` // Estimated: `8799` - // Minimum execution time: 110_529_000 picoseconds. - Weight::from_parts(112_660_000, 8799) + // Minimum execution time: 110_207_000 picoseconds. + Weight::from_parts(111_918_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -171,14 +173,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1045` + // Measured: `1122` // Estimated: `6196` - // Minimum execution time: 76_363_000 picoseconds. - Weight::from_parts(77_799_000, 6196) + // Minimum execution time: 78_217_000 picoseconds. + Weight::from_parts(79_799_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -192,14 +194,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1232` + // Measured: `1343` // Estimated: `8799` - // Minimum execution time: 89_977_000 picoseconds. - Weight::from_parts(92_978_000, 8799) + // Minimum execution time: 93_624_000 picoseconds. + Weight::from_parts(96_697_000, 8799) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -213,19 +215,21 @@ impl WeightInfo for () { /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyCount` (r:1 w:1) - /// Proof: `ChildBounties::ChildBountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentTotalChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentTotalChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) /// Storage: `ChildBounties::ChildBounties` (r:0 w:1) /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) /// The range of component `d` is `[0, 300]`. - fn add_child_bounty(_d: u32, ) -> Weight { + fn add_child_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `745` + // Measured: `812` // Estimated: `6196` - // Minimum execution time: 65_654_000 picoseconds. - Weight::from_parts(68_255_084, 6196) + // Minimum execution time: 71_601_000 picoseconds. + Weight::from_parts(74_162_244, 6196) + // Standard Error: 328 + .saturating_add(Weight::from_parts(1_528, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -237,10 +241,10 @@ impl WeightInfo for () { /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `799` + // Measured: `842` // Estimated: `3642` - // Minimum execution time: 18_534_000 picoseconds. - Weight::from_parts(19_332_000, 3642) + // Minimum execution time: 24_835_000 picoseconds. + Weight::from_parts(26_049_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -252,10 +256,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `1048` // Estimated: `3642` - // Minimum execution time: 33_212_000 picoseconds. - Weight::from_parts(35_407_000, 3642) + // Minimum execution time: 40_409_000 picoseconds. + Weight::from_parts(41_432_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -267,10 +271,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `1048` // Estimated: `3642` - // Minimum execution time: 35_510_000 picoseconds. - Weight::from_parts(36_345_000, 3642) + // Minimum execution time: 49_747_000 picoseconds. + Weight::from_parts(51_222_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -280,10 +284,10 @@ impl WeightInfo for () { /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `842` + // Measured: `908` // Estimated: `3642` - // Minimum execution time: 19_085_000 picoseconds. - Weight::from_parts(20_094_000, 3642) + // Minimum execution time: 26_462_000 picoseconds. + Weight::from_parts(27_166_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -293,14 +297,14 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `682` + // Measured: `752` // Estimated: `8799` - // Minimum execution time: 110_529_000 picoseconds. - Weight::from_parts(112_660_000, 8799) + // Minimum execution time: 110_207_000 picoseconds. + Weight::from_parts(111_918_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -314,14 +318,14 @@ impl WeightInfo for () { /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1045` + // Measured: `1122` // Estimated: `6196` - // Minimum execution time: 76_363_000 picoseconds. - Weight::from_parts(77_799_000, 6196) + // Minimum execution time: 78_217_000 picoseconds. + Weight::from_parts(79_799_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -335,14 +339,14 @@ impl WeightInfo for () { /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptionsV1` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptionsV1` (`max_values`: None, `max_size`: Some(326), added: 2801, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1232` + // Measured: `1343` // Estimated: `8799` - // Minimum execution time: 89_977_000 picoseconds. - Weight::from_parts(92_978_000, 8799) + // Minimum execution time: 93_624_000 picoseconds. + Weight::from_parts(96_697_000, 8799) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index 59a9d23f7b19..8e53000352ae 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } docify = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { features = ["experimental"], workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/collective/src/weights.rs b/substrate/frame/collective/src/weights.rs index 1a7485b4ab7b..4d47d2fe9ead 100644 --- a/substrate/frame/collective/src/weights.rs +++ b/substrate/frame/collective/src/weights.rs @@ -18,25 +18,27 @@ //! Autogenerated weights for `pallet_collective` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-09-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_collective +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_collective -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/collective/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -80,13 +82,13 @@ impl WeightInfo for SubstrateWeight { fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15894 + m * (1967 ±23) + p * (4332 ±23)` - // Minimum execution time: 16_699_000 picoseconds. - Weight::from_parts(17_015_000, 15894) - // Standard Error: 63_844 - .saturating_add(Weight::from_parts(4_593_256, 0).saturating_mul(m.into())) - // Standard Error: 63_844 - .saturating_add(Weight::from_parts(8_935_845, 0).saturating_mul(p.into())) + // Estimated: `15927 + m * (1967 ±24) + p * (4332 ±24)` + // Minimum execution time: 16_292_000 picoseconds. + Weight::from_parts(16_707_000, 15927) + // Standard Error: 65_976 + .saturating_add(Weight::from_parts(4_766_715, 0).saturating_mul(m.into())) + // Standard Error: 65_976 + .saturating_add(Weight::from_parts(9_280_562, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -104,14 +106,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` + // Measured: `413 + m * (32 ±0)` // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 22_010_000 picoseconds. - Weight::from_parts(21_392_812, 3997) - // Standard Error: 34 - .saturating_add(Weight::from_parts(1_533, 0).saturating_mul(b.into())) - // Standard Error: 354 - .saturating_add(Weight::from_parts(15_866, 0).saturating_mul(m.into())) + // Minimum execution time: 24_281_000 picoseconds. + Weight::from_parts(23_568_200, 3997) + // Standard Error: 47 + .saturating_add(Weight::from_parts(1_681, 0).saturating_mul(b.into())) + // Standard Error: 492 + .saturating_add(Weight::from_parts(15_851, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -127,14 +129,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` + // Measured: `413 + m * (32 ±0)` // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 24_250_000 picoseconds. - Weight::from_parts(23_545_893, 3997) - // Standard Error: 40 - .saturating_add(Weight::from_parts(1_646, 0).saturating_mul(b.into())) - // Standard Error: 421 - .saturating_add(Weight::from_parts(26_248, 0).saturating_mul(m.into())) + // Minimum execution time: 26_424_000 picoseconds. + Weight::from_parts(26_130_784, 3997) + // Standard Error: 56 + .saturating_add(Weight::from_parts(1_577, 0).saturating_mul(b.into())) + // Standard Error: 585 + .saturating_add(Weight::from_parts(20_984, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -145,7 +147,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Council::Proposals` (r:1 w:1) /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Council::ProposalCount` (r:1 w:1) /// Proof: `Council::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Council::Voting` (r:0 w:1) @@ -157,16 +159,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3991 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 46_538_000 picoseconds. - Weight::from_parts(63_900_448, 3991) - // Standard Error: 350 - .saturating_add(Weight::from_parts(2_827, 0).saturating_mul(b.into())) - // Standard Error: 3_658 - .saturating_add(Weight::from_parts(53_340, 0).saturating_mul(m.into())) - // Standard Error: 3_611 - .saturating_add(Weight::from_parts(213_719, 0).saturating_mul(p.into())) + // Measured: `651 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `4024 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 47_547_000 picoseconds. + Weight::from_parts(65_808_006, 4024) + // Standard Error: 330 + .saturating_add(Weight::from_parts(4_211, 0).saturating_mul(b.into())) + // Standard Error: 3_443 + .saturating_add(Weight::from_parts(43_705, 0).saturating_mul(m.into())) + // Standard Error: 3_399 + .saturating_add(Weight::from_parts(235_928, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) @@ -179,12 +181,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1011 + m * (64 ±0)` - // Estimated: `4475 + m * (64 ±0)` - // Minimum execution time: 28_413_000 picoseconds. - Weight::from_parts(28_981_832, 4475) - // Standard Error: 665 - .saturating_add(Weight::from_parts(43_005, 0).saturating_mul(m.into())) + // Measured: `1044 + m * (64 ±0)` + // Estimated: `4508 + m * (64 ±0)` + // Minimum execution time: 32_388_000 picoseconds. + Weight::from_parts(34_955_946, 4508) + // Standard Error: 2_253 + .saturating_add(Weight::from_parts(34_184, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -201,14 +203,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `600 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4042 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_725_000 picoseconds. - Weight::from_parts(30_174_093, 4042) - // Standard Error: 1_458 - .saturating_add(Weight::from_parts(41_100, 0).saturating_mul(m.into())) - // Standard Error: 1_422 - .saturating_add(Weight::from_parts(177_303, 0).saturating_mul(p.into())) + // Measured: `633 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4075 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 29_663_000 picoseconds. + Weight::from_parts(33_355_561, 4075) + // Standard Error: 2_045 + .saturating_add(Weight::from_parts(28_190, 0).saturating_mul(m.into())) + // Standard Error: 1_994 + .saturating_add(Weight::from_parts(185_801, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) @@ -231,16 +233,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1047 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4360 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 48_882_000 picoseconds. - Weight::from_parts(51_938_773, 4360) - // Standard Error: 208 - .saturating_add(Weight::from_parts(3_559, 0).saturating_mul(b.into())) - // Standard Error: 2_201 - .saturating_add(Weight::from_parts(38_678, 0).saturating_mul(m.into())) - // Standard Error: 2_145 - .saturating_add(Weight::from_parts(214_061, 0).saturating_mul(p.into())) + // Measured: `1080 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4393 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 46_764_000 picoseconds. + Weight::from_parts(49_084_241, 4393) + // Standard Error: 284 + .saturating_add(Weight::from_parts(3_771, 0).saturating_mul(b.into())) + // Standard Error: 3_003 + .saturating_add(Weight::from_parts(33_189, 0).saturating_mul(m.into())) + // Standard Error: 2_927 + .saturating_add(Weight::from_parts(245_387, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) @@ -261,14 +263,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `620 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4062 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 30_613_000 picoseconds. - Weight::from_parts(36_174_190, 4062) - // Standard Error: 1_899 - .saturating_add(Weight::from_parts(46_781, 0).saturating_mul(m.into())) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(185_875, 0).saturating_mul(p.into())) + // Measured: `653 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4095 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 32_188_000 picoseconds. + Weight::from_parts(35_015_624, 4095) + // Standard Error: 2_283 + .saturating_add(Weight::from_parts(39_633, 0).saturating_mul(m.into())) + // Standard Error: 2_226 + .saturating_add(Weight::from_parts(191_898, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) @@ -293,16 +295,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1067 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4380 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 51_253_000 picoseconds. - Weight::from_parts(56_399_941, 4380) - // Standard Error: 218 - .saturating_add(Weight::from_parts(2_920, 0).saturating_mul(b.into())) - // Standard Error: 2_310 - .saturating_add(Weight::from_parts(30_473, 0).saturating_mul(m.into())) - // Standard Error: 2_252 - .saturating_add(Weight::from_parts(208_468, 0).saturating_mul(p.into())) + // Measured: `1100 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4413 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 49_281_000 picoseconds. + Weight::from_parts(53_838_013, 4413) + // Standard Error: 317 + .saturating_add(Weight::from_parts(4_011, 0).saturating_mul(b.into())) + // Standard Error: 3_353 + .saturating_add(Weight::from_parts(19_609, 0).saturating_mul(m.into())) + // Standard Error: 3_269 + .saturating_add(Weight::from_parts(236_964, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) @@ -318,12 +320,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `392 + p * (32 ±0)` - // Estimated: `1877 + p * (32 ±0)` - // Minimum execution time: 14_646_000 picoseconds. - Weight::from_parts(17_305_497, 1877) - // Standard Error: 1_331 - .saturating_add(Weight::from_parts(156_038, 0).saturating_mul(p.into())) + // Measured: `425 + p * (32 ±0)` + // Estimated: `1910 + p * (32 ±0)` + // Minimum execution time: 14_767_000 picoseconds. + Weight::from_parts(16_823_844, 1910) + // Standard Error: 1_424 + .saturating_add(Weight::from_parts(170_583, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) @@ -335,7 +337,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Council::Proposals` (r:1 w:1) /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Council::Voting` (r:0 w:1) @@ -344,19 +346,19 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[1, 100]`. fn kill(d: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1863 + d * (212 ±0) + p * (41 ±0)` - // Estimated: `5172 + d * (1901 ±14) + p * (43 ±0)` - // Minimum execution time: 22_164_000 picoseconds. - Weight::from_parts(24_932_256, 5172) - // Standard Error: 404_014 - .saturating_add(Weight::from_parts(33_833_807, 0).saturating_mul(d.into())) - // Standard Error: 6_256 - .saturating_add(Weight::from_parts(281_910, 0).saturating_mul(p.into())) + // Measured: `1896 + d * (212 ±0) + p * (41 ±0)` + // Estimated: `5205 + d * (1910 ±14) + p * (43 ±0)` + // Minimum execution time: 24_956_000 picoseconds. + Weight::from_parts(25_382_488, 5205) + // Standard Error: 374_961 + .saturating_add(Weight::from_parts(31_856_043, 0).saturating_mul(d.into())) + // Standard Error: 5_806 + .saturating_add(Weight::from_parts(288_259, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(d.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(d.into()))) - .saturating_add(Weight::from_parts(0, 1901).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 1910).saturating_mul(d.into())) .saturating_add(Weight::from_parts(0, 43).saturating_mul(p.into())) } /// Storage: `Council::ProposalOf` (r:1 w:0) @@ -366,13 +368,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn release_proposal_cost() -> Weight { // Proof Size summary in bytes: - // Measured: `1964` - // Estimated: `5429` - // Minimum execution time: 69_220_000 picoseconds. - Weight::from_parts(70_215_000, 5429) + // Measured: `1997` + // Estimated: `5462` + // Minimum execution time: 67_153_000 picoseconds. + Weight::from_parts(70_174_000, 5462) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -394,13 +396,13 @@ impl WeightInfo for () { fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15894 + m * (1967 ±23) + p * (4332 ±23)` - // Minimum execution time: 16_699_000 picoseconds. - Weight::from_parts(17_015_000, 15894) - // Standard Error: 63_844 - .saturating_add(Weight::from_parts(4_593_256, 0).saturating_mul(m.into())) - // Standard Error: 63_844 - .saturating_add(Weight::from_parts(8_935_845, 0).saturating_mul(p.into())) + // Estimated: `15927 + m * (1967 ±24) + p * (4332 ±24)` + // Minimum execution time: 16_292_000 picoseconds. + Weight::from_parts(16_707_000, 15927) + // Standard Error: 65_976 + .saturating_add(Weight::from_parts(4_766_715, 0).saturating_mul(m.into())) + // Standard Error: 65_976 + .saturating_add(Weight::from_parts(9_280_562, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -418,14 +420,14 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` + // Measured: `413 + m * (32 ±0)` // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 22_010_000 picoseconds. - Weight::from_parts(21_392_812, 3997) - // Standard Error: 34 - .saturating_add(Weight::from_parts(1_533, 0).saturating_mul(b.into())) - // Standard Error: 354 - .saturating_add(Weight::from_parts(15_866, 0).saturating_mul(m.into())) + // Minimum execution time: 24_281_000 picoseconds. + Weight::from_parts(23_568_200, 3997) + // Standard Error: 47 + .saturating_add(Weight::from_parts(1_681, 0).saturating_mul(b.into())) + // Standard Error: 492 + .saturating_add(Weight::from_parts(15_851, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -441,14 +443,14 @@ impl WeightInfo for () { /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` + // Measured: `413 + m * (32 ±0)` // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 24_250_000 picoseconds. - Weight::from_parts(23_545_893, 3997) - // Standard Error: 40 - .saturating_add(Weight::from_parts(1_646, 0).saturating_mul(b.into())) - // Standard Error: 421 - .saturating_add(Weight::from_parts(26_248, 0).saturating_mul(m.into())) + // Minimum execution time: 26_424_000 picoseconds. + Weight::from_parts(26_130_784, 3997) + // Standard Error: 56 + .saturating_add(Weight::from_parts(1_577, 0).saturating_mul(b.into())) + // Standard Error: 585 + .saturating_add(Weight::from_parts(20_984, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -459,7 +461,7 @@ impl WeightInfo for () { /// Storage: `Council::Proposals` (r:1 w:1) /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Council::ProposalCount` (r:1 w:1) /// Proof: `Council::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Council::Voting` (r:0 w:1) @@ -471,16 +473,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3991 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 46_538_000 picoseconds. - Weight::from_parts(63_900_448, 3991) - // Standard Error: 350 - .saturating_add(Weight::from_parts(2_827, 0).saturating_mul(b.into())) - // Standard Error: 3_658 - .saturating_add(Weight::from_parts(53_340, 0).saturating_mul(m.into())) - // Standard Error: 3_611 - .saturating_add(Weight::from_parts(213_719, 0).saturating_mul(p.into())) + // Measured: `651 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `4024 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 47_547_000 picoseconds. + Weight::from_parts(65_808_006, 4024) + // Standard Error: 330 + .saturating_add(Weight::from_parts(4_211, 0).saturating_mul(b.into())) + // Standard Error: 3_443 + .saturating_add(Weight::from_parts(43_705, 0).saturating_mul(m.into())) + // Standard Error: 3_399 + .saturating_add(Weight::from_parts(235_928, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) @@ -493,12 +495,12 @@ impl WeightInfo for () { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1011 + m * (64 ±0)` - // Estimated: `4475 + m * (64 ±0)` - // Minimum execution time: 28_413_000 picoseconds. - Weight::from_parts(28_981_832, 4475) - // Standard Error: 665 - .saturating_add(Weight::from_parts(43_005, 0).saturating_mul(m.into())) + // Measured: `1044 + m * (64 ±0)` + // Estimated: `4508 + m * (64 ±0)` + // Minimum execution time: 32_388_000 picoseconds. + Weight::from_parts(34_955_946, 4508) + // Standard Error: 2_253 + .saturating_add(Weight::from_parts(34_184, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -515,14 +517,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `600 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4042 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_725_000 picoseconds. - Weight::from_parts(30_174_093, 4042) - // Standard Error: 1_458 - .saturating_add(Weight::from_parts(41_100, 0).saturating_mul(m.into())) - // Standard Error: 1_422 - .saturating_add(Weight::from_parts(177_303, 0).saturating_mul(p.into())) + // Measured: `633 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4075 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 29_663_000 picoseconds. + Weight::from_parts(33_355_561, 4075) + // Standard Error: 2_045 + .saturating_add(Weight::from_parts(28_190, 0).saturating_mul(m.into())) + // Standard Error: 1_994 + .saturating_add(Weight::from_parts(185_801, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) @@ -545,16 +547,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1047 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4360 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 48_882_000 picoseconds. - Weight::from_parts(51_938_773, 4360) - // Standard Error: 208 - .saturating_add(Weight::from_parts(3_559, 0).saturating_mul(b.into())) - // Standard Error: 2_201 - .saturating_add(Weight::from_parts(38_678, 0).saturating_mul(m.into())) - // Standard Error: 2_145 - .saturating_add(Weight::from_parts(214_061, 0).saturating_mul(p.into())) + // Measured: `1080 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4393 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 46_764_000 picoseconds. + Weight::from_parts(49_084_241, 4393) + // Standard Error: 284 + .saturating_add(Weight::from_parts(3_771, 0).saturating_mul(b.into())) + // Standard Error: 3_003 + .saturating_add(Weight::from_parts(33_189, 0).saturating_mul(m.into())) + // Standard Error: 2_927 + .saturating_add(Weight::from_parts(245_387, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) @@ -575,14 +577,14 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `620 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4062 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 30_613_000 picoseconds. - Weight::from_parts(36_174_190, 4062) - // Standard Error: 1_899 - .saturating_add(Weight::from_parts(46_781, 0).saturating_mul(m.into())) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(185_875, 0).saturating_mul(p.into())) + // Measured: `653 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `4095 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 32_188_000 picoseconds. + Weight::from_parts(35_015_624, 4095) + // Standard Error: 2_283 + .saturating_add(Weight::from_parts(39_633, 0).saturating_mul(m.into())) + // Standard Error: 2_226 + .saturating_add(Weight::from_parts(191_898, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) @@ -607,16 +609,16 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1067 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4380 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 51_253_000 picoseconds. - Weight::from_parts(56_399_941, 4380) - // Standard Error: 218 - .saturating_add(Weight::from_parts(2_920, 0).saturating_mul(b.into())) - // Standard Error: 2_310 - .saturating_add(Weight::from_parts(30_473, 0).saturating_mul(m.into())) - // Standard Error: 2_252 - .saturating_add(Weight::from_parts(208_468, 0).saturating_mul(p.into())) + // Measured: `1100 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4413 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 49_281_000 picoseconds. + Weight::from_parts(53_838_013, 4413) + // Standard Error: 317 + .saturating_add(Weight::from_parts(4_011, 0).saturating_mul(b.into())) + // Standard Error: 3_353 + .saturating_add(Weight::from_parts(19_609, 0).saturating_mul(m.into())) + // Standard Error: 3_269 + .saturating_add(Weight::from_parts(236_964, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) @@ -632,12 +634,12 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `392 + p * (32 ±0)` - // Estimated: `1877 + p * (32 ±0)` - // Minimum execution time: 14_646_000 picoseconds. - Weight::from_parts(17_305_497, 1877) - // Standard Error: 1_331 - .saturating_add(Weight::from_parts(156_038, 0).saturating_mul(p.into())) + // Measured: `425 + p * (32 ±0)` + // Estimated: `1910 + p * (32 ±0)` + // Minimum execution time: 14_767_000 picoseconds. + Weight::from_parts(16_823_844, 1910) + // Standard Error: 1_424 + .saturating_add(Weight::from_parts(170_583, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) @@ -649,7 +651,7 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Council::Proposals` (r:1 w:1) /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Council::Voting` (r:0 w:1) @@ -658,19 +660,19 @@ impl WeightInfo for () { /// The range of component `p` is `[1, 100]`. fn kill(d: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1863 + d * (212 ±0) + p * (41 ±0)` - // Estimated: `5172 + d * (1901 ±14) + p * (43 ±0)` - // Minimum execution time: 22_164_000 picoseconds. - Weight::from_parts(24_932_256, 5172) - // Standard Error: 404_014 - .saturating_add(Weight::from_parts(33_833_807, 0).saturating_mul(d.into())) - // Standard Error: 6_256 - .saturating_add(Weight::from_parts(281_910, 0).saturating_mul(p.into())) + // Measured: `1896 + d * (212 ±0) + p * (41 ±0)` + // Estimated: `5205 + d * (1910 ±14) + p * (43 ±0)` + // Minimum execution time: 24_956_000 picoseconds. + Weight::from_parts(25_382_488, 5205) + // Standard Error: 374_961 + .saturating_add(Weight::from_parts(31_856_043, 0).saturating_mul(d.into())) + // Standard Error: 5_806 + .saturating_add(Weight::from_parts(288_259, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(d.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(d.into()))) - .saturating_add(Weight::from_parts(0, 1901).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 1910).saturating_mul(d.into())) .saturating_add(Weight::from_parts(0, 43).saturating_mul(p.into())) } /// Storage: `Council::ProposalOf` (r:1 w:0) @@ -680,13 +682,13 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn release_proposal_cost() -> Weight { // Proof Size summary in bytes: - // Measured: `1964` - // Estimated: `5429` - // Minimum execution time: 69_220_000 picoseconds. - Weight::from_parts(70_215_000, 5429) + // Measured: `1997` + // Estimated: `5462` + // Minimum execution time: 67_153_000 picoseconds. + Weight::from_parts(70_174_000, 5462) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 316ea6813048..e39128639e3e 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -18,25 +18,25 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -paste = { workspace = true } bitflags = { workspace = true } codec = { features = [ "derive", "max-encoded-len", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } +impl-trait-for-tuples = { workspace = true } log = { workspace = true } +paste = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = { features = [ "const_generics", ], workspace = true } wasmi = { workspace = true } -impl-trait-for-tuples = { workspace = true } # Only used in benchmarking to generate contract code -wasm-instrument = { optional = true, workspace = true } rand = { optional = true, workspace = true } rand_pcg = { optional = true, workspace = true } +wasm-instrument = { optional = true, workspace = true } # Substrate Dependencies environmental = { workspace = true } @@ -44,8 +44,8 @@ frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-balances = { optional = true, workspace = true } -pallet-contracts-uapi = { workspace = true, default-features = true } pallet-contracts-proc-macro = { workspace = true, default-features = true } +pallet-contracts-uapi = { workspace = true, default-features = true } sp-api = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } @@ -58,21 +58,21 @@ xcm-builder = { workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } assert_matches = { workspace = true } +pallet-contracts-fixtures = { workspace = true } pretty_assertions = { workspace = true } wat = { workspace = true } -pallet-contracts-fixtures = { workspace = true } # Polkadot Dependencies xcm-builder = { workspace = true, default-features = true } # Substrate Dependencies +pallet-assets = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } pallet-insecure-randomness-collective-flip = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } pallet-proxy = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +pallet-utility = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } @@ -119,6 +119,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "wasm-instrument", "xcm-builder/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 4c01c1f061b7..cf31f9eccc9c 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -11,13 +11,13 @@ description = "Fixtures for testing contracts pallet." workspace = true [dependencies] +anyhow = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -anyhow = { workspace = true, default-features = true } [build-dependencies] +anyhow = { workspace = true, default-features = true } parity-wasm = { workspace = true } tempfile = { workspace = true } toml = { workspace = true } twox-hash = { workspace = true, default-features = true } -anyhow = { workspace = true, default-features = true } diff --git a/substrate/frame/contracts/fixtures/build/Cargo.toml b/substrate/frame/contracts/fixtures/build/Cargo.toml index ba487a2bb5ca..18e8c2767d5f 100644 --- a/substrate/frame/contracts/fixtures/build/Cargo.toml +++ b/substrate/frame/contracts/fixtures/build/Cargo.toml @@ -8,9 +8,9 @@ edition = "2021" # All paths or versions are injected dynamically by the build script. [dependencies] -uapi = { package = 'pallet-contracts-uapi', path = "", default-features = false } common = { package = 'pallet-contracts-fixtures-common', path = "" } polkavm-derive = { version = "" } +uapi = { package = 'pallet-contracts-uapi', path = "", default-features = false } [profile.release] opt-level = 3 diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index d6e2d51ef452..a7423b33abc1 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -19,8 +19,8 @@ frame-system = { workspace = true } pallet-assets = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-contracts = { workspace = true, default-features = true } -pallet-contracts-uapi = { workspace = true } pallet-contracts-proc-macro = { workspace = true, default-features = true } +pallet-contracts-uapi = { workspace = true } pallet-insecure-randomness-collective-flip = { workspace = true, default-features = true } pallet-message-queue = { workspace = true, default-features = true } pallet-proxy = { workspace = true, default-features = true } @@ -44,8 +44,8 @@ xcm-simulator = { workspace = true, default-features = true } [dev-dependencies] assert_matches = { workspace = true } -pretty_assertions = { workspace = true } pallet-contracts-fixtures = { workspace = true } +pretty_assertions = { workspace = true } [features] default = ["std"] @@ -87,4 +87,5 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index c3b6e3273f34..b01d0aa4fa48 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -399,6 +399,7 @@ impl pallet_proxy::Config for Test { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = ConstU64<1>; type AnnouncementDepositFactor = ConstU64<1>; + type BlockNumberProvider = frame_system::Pallet; } impl pallet_dummy::Config for Test {} diff --git a/substrate/frame/contracts/src/weights.rs b/substrate/frame/contracts/src/weights.rs index 25b36fc404fe..f6c56468e5de 100644 --- a/substrate/frame/contracts/src/weights.rs +++ b/substrate/frame/contracts/src/weights.rs @@ -18,25 +18,27 @@ //! Autogenerated weights for `pallet_contracts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yaoqqom-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_contracts +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_contracts -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/contracts/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -141,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 1_915_000 picoseconds. - Weight::from_parts(1_986_000, 1627) + // Minimum execution time: 2_809_000 picoseconds. + Weight::from_parts(2_956_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -152,10 +154,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 11_103_000 picoseconds. - Weight::from_parts(11_326_000, 442) - // Standard Error: 2_291 - .saturating_add(Weight::from_parts(1_196_329, 0).saturating_mul(k.into())) + // Minimum execution time: 17_559_000 picoseconds. + Weight::from_parts(17_850_000, 442) + // Standard Error: 2_722 + .saturating_add(Weight::from_parts(1_376_892, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -169,10 +171,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 7_783_000 picoseconds. - Weight::from_parts(4_462_075, 6149) + // Minimum execution time: 8_830_000 picoseconds. + Weight::from_parts(6_649_003, 6149) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_634, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_676, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -185,8 +187,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 15_971_000 picoseconds. - Weight::from_parts(16_730_000, 6450) + // Minimum execution time: 21_927_000 picoseconds. + Weight::from_parts(22_655_000, 6450) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,10 +201,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_149_000 picoseconds. - Weight::from_parts(3_264_000, 3635) - // Standard Error: 559 - .saturating_add(Weight::from_parts(1_111_209, 0).saturating_mul(k.into())) + // Minimum execution time: 4_465_000 picoseconds. + Weight::from_parts(4_774_000, 3635) + // Standard Error: 867 + .saturating_add(Weight::from_parts(1_071_462, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -221,10 +223,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `325 + c * (1 ±0)` // Estimated: `6263 + c * (1 ±0)` - // Minimum execution time: 15_072_000 picoseconds. - Weight::from_parts(15_721_891, 6263) + // Minimum execution time: 21_627_000 picoseconds. + Weight::from_parts(21_491_424, 6263) // Standard Error: 2 - .saturating_add(Weight::from_parts(428, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(480, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -235,8 +237,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 12_047_000 picoseconds. - Weight::from_parts(12_500_000, 6380) + // Minimum execution time: 17_262_000 picoseconds. + Weight::from_parts(17_785_000, 6380) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -245,13 +247,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 47_488_000 picoseconds. - Weight::from_parts(48_482_000, 6292) + // Minimum execution time: 52_303_000 picoseconds. + Weight::from_parts(53_902_000, 6292) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -263,8 +265,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 52_801_000 picoseconds. - Weight::from_parts(54_230_000, 6534) + // Minimum execution time: 58_585_000 picoseconds. + Weight::from_parts(60_478_000, 6534) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -274,8 +276,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `409` // Estimated: `6349` - // Minimum execution time: 11_618_000 picoseconds. - Weight::from_parts(12_068_000, 6349) + // Minimum execution time: 16_673_000 picoseconds. + Weight::from_parts(17_325_000, 6349) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -285,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_131_000 picoseconds. - Weight::from_parts(2_255_000, 1627) + // Minimum execution time: 3_073_000 picoseconds. + Weight::from_parts(3_262_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -298,8 +300,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 10_773_000 picoseconds. - Weight::from_parts(11_118_000, 3631) + // Minimum execution time: 11_687_000 picoseconds. + Weight::from_parts(12_178_000, 3631) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -309,8 +311,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_371_000 picoseconds. - Weight::from_parts(4_624_000, 3607) + // Minimum execution time: 4_553_000 picoseconds. + Weight::from_parts(4_826_000, 3607) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -321,8 +323,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 5_612_000 picoseconds. - Weight::from_parts(5_838_000, 3632) + // Minimum execution time: 6_794_000 picoseconds. + Weight::from_parts(6_959_000, 3632) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -333,8 +335,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 5_487_000 picoseconds. - Weight::from_parts(5_693_000, 3607) + // Minimum execution time: 6_120_000 picoseconds. + Weight::from_parts(6_420_000, 3607) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -354,11 +356,11 @@ impl WeightInfo for SubstrateWeight { fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `800 + c * (1 ±0)` - // Estimated: `4266 + c * (1 ±0)` - // Minimum execution time: 247_545_000 picoseconds. - Weight::from_parts(268_016_699, 4266) - // Standard Error: 4 - .saturating_add(Weight::from_parts(700, 0).saturating_mul(c.into())) + // Estimated: `4268 + c * (1 ±0)` + // Minimum execution time: 266_424_000 picoseconds. + Weight::from_parts(283_325_502, 4268) + // Standard Error: 12 + .saturating_add(Weight::from_parts(950, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -368,7 +370,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) @@ -385,15 +387,15 @@ impl WeightInfo for SubstrateWeight { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `323` - // Estimated: `6262` - // Minimum execution time: 4_396_772_000 picoseconds. - Weight::from_parts(235_107_907, 6262) - // Standard Error: 185 - .saturating_add(Weight::from_parts(53_843, 0).saturating_mul(c.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(2_143, 0).saturating_mul(i.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(2_210, 0).saturating_mul(s.into())) + // Estimated: `6267` + // Minimum execution time: 4_371_315_000 picoseconds. + Weight::from_parts(4_739_462_000, 6267) + // Standard Error: 329 + .saturating_add(Weight::from_parts(38_518, 0).saturating_mul(c.into())) + // Standard Error: 39 + .saturating_add(Weight::from_parts(605, 0).saturating_mul(i.into())) + // Standard Error: 39 + .saturating_add(Weight::from_parts(561, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -412,19 +414,19 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `560` - // Estimated: `4017` - // Minimum execution time: 2_240_868_000 picoseconds. - Weight::from_parts(2_273_668_000, 4017) - // Standard Error: 32 - .saturating_add(Weight::from_parts(934, 0).saturating_mul(i.into())) - // Standard Error: 32 - .saturating_add(Weight::from_parts(920, 0).saturating_mul(s.into())) + // Estimated: `4016` + // Minimum execution time: 2_304_531_000 picoseconds. + Weight::from_parts(2_352_810_000, 4016) + // Standard Error: 35 + .saturating_add(Weight::from_parts(1_004, 0).saturating_mul(i.into())) + // Standard Error: 35 + .saturating_add(Weight::from_parts(936, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -444,8 +446,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `826` // Estimated: `4291` - // Minimum execution time: 165_067_000 picoseconds. - Weight::from_parts(168_582_000, 4291) + // Minimum execution time: 183_658_000 picoseconds. + Weight::from_parts(189_507_000, 4291) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -454,7 +456,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) /// The range of component `c` is `[0, 125952]`. @@ -462,10 +464,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 229_454_000 picoseconds. - Weight::from_parts(251_495_551, 3607) - // Standard Error: 71 - .saturating_add(Weight::from_parts(51_428, 0).saturating_mul(c.into())) + // Minimum execution time: 253_006_000 picoseconds. + Weight::from_parts(269_271_744, 3607) + // Standard Error: 79 + .saturating_add(Weight::from_parts(49_970, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -474,7 +476,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) /// The range of component `c` is `[0, 125952]`. @@ -482,10 +484,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 240_390_000 picoseconds. - Weight::from_parts(273_854_266, 3607) - // Standard Error: 243 - .saturating_add(Weight::from_parts(51_836, 0).saturating_mul(c.into())) + // Minimum execution time: 247_567_000 picoseconds. + Weight::from_parts(271_875_922, 3607) + // Standard Error: 78 + .saturating_add(Weight::from_parts(50_117, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -494,15 +496,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 39_374_000 picoseconds. - Weight::from_parts(40_247_000, 3780) + // Minimum execution time: 48_151_000 picoseconds. + Weight::from_parts(49_407_000, 3780) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -516,8 +518,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `552` // Estimated: `6492` - // Minimum execution time: 24_473_000 picoseconds. - Weight::from_parts(25_890_000, 6492) + // Minimum execution time: 30_173_000 picoseconds. + Weight::from_parts(30_941_000, 6492) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -526,17 +528,17 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_528_000 picoseconds. - Weight::from_parts(9_301_010, 0) - // Standard Error: 98 - .saturating_add(Weight::from_parts(53_173, 0).saturating_mul(r.into())) + // Minimum execution time: 8_350_000 picoseconds. + Weight::from_parts(9_238_867, 0) + // Standard Error: 139 + .saturating_add(Weight::from_parts(52_355, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 643_000 picoseconds. - Weight::from_parts(678_000, 0) + // Minimum execution time: 757_000 picoseconds. + Weight::from_parts(827_000, 0) } /// Storage: `Contracts::ContractInfoOf` (r:1 w:0) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) @@ -544,8 +546,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `354` // Estimated: `3819` - // Minimum execution time: 6_107_000 picoseconds. - Weight::from_parts(6_235_000, 3819) + // Minimum execution time: 12_202_000 picoseconds. + Weight::from_parts(12_708_000, 3819) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Contracts::ContractInfoOf` (r:1 w:0) @@ -554,109 +556,106 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `447` // Estimated: `3912` - // Minimum execution time: 7_316_000 picoseconds. - Weight::from_parts(7_653_000, 3912) + // Minimum execution time: 13_492_000 picoseconds. + Weight::from_parts(13_845_000, 3912) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 721_000 picoseconds. - Weight::from_parts(764_000, 0) + // Minimum execution time: 798_000 picoseconds. + Weight::from_parts(856_000, 0) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 369_000 picoseconds. - Weight::from_parts(417_000, 0) + // Minimum execution time: 364_000 picoseconds. + Weight::from_parts(414_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 318_000 picoseconds. - Weight::from_parts(349_000, 0) + // Minimum execution time: 355_000 picoseconds. + Weight::from_parts(396_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 590_000 picoseconds. - Weight::from_parts(628_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(719_000, 0) } fn seal_gas_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 660_000 picoseconds. - Weight::from_parts(730_000, 0) + // Minimum execution time: 770_000 picoseconds. + Weight::from_parts(827_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 4_361_000 picoseconds. - Weight::from_parts(4_577_000, 0) + // Minimum execution time: 5_839_000 picoseconds. + Weight::from_parts(6_174_000, 0) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 560_000 picoseconds. - Weight::from_parts(603_000, 0) + // Minimum execution time: 681_000 picoseconds. + Weight::from_parts(757_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(610_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(730_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 557_000 picoseconds. - Weight::from_parts(583_000, 0) + // Minimum execution time: 654_000 picoseconds. + Weight::from_parts(713_000, 0) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 550_000 picoseconds. - Weight::from_parts(602_000, 0) + // Minimum execution time: 707_000 picoseconds. + Weight::from_parts(752_000, 0) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) fn seal_weight_to_fee() -> Weight { // Proof Size summary in bytes: - // Measured: `67` - // Estimated: `1552` - // Minimum execution time: 4_065_000 picoseconds. - Weight::from_parts(4_291_000, 1552) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_562_000 picoseconds. + Weight::from_parts(1_749_000, 0) } /// The range of component `n` is `[0, 1048572]`. fn seal_input(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 487_000 picoseconds. - Weight::from_parts(517_000, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(301, 0).saturating_mul(n.into())) + // Minimum execution time: 483_000 picoseconds. + Weight::from_parts(536_000, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(329, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048572]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 318_000 picoseconds. - Weight::from_parts(372_000, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(411, 0).saturating_mul(n.into())) + // Minimum execution time: 372_000 picoseconds. + Weight::from_parts(384_000, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(433, 0).saturating_mul(n.into())) } /// Storage: `Contracts::DeletionQueueCounter` (r:1 w:1) /// Proof: `Contracts::DeletionQueueCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) @@ -669,10 +668,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `319 + n * (78 ±0)` // Estimated: `3784 + n * (2553 ±0)` - // Minimum execution time: 13_251_000 picoseconds. - Weight::from_parts(15_257_892, 3784) - // Standard Error: 7_089 - .saturating_add(Weight::from_parts(3_443_907, 0).saturating_mul(n.into())) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(20_544_934, 3784) + // Standard Error: 9_422 + .saturating_add(Weight::from_parts(4_431_910, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -685,8 +684,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 3_434_000 picoseconds. - Weight::from_parts(3_605_000, 1561) + // Minimum execution time: 4_503_000 picoseconds. + Weight::from_parts(4_743_000, 1561) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `System::EventTopics` (r:4 w:4) @@ -697,12 +696,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `990 + t * (2475 ±0)` - // Minimum execution time: 3_668_000 picoseconds. - Weight::from_parts(3_999_591, 990) - // Standard Error: 5_767 - .saturating_add(Weight::from_parts(2_011_090, 0).saturating_mul(t.into())) + // Minimum execution time: 3_838_000 picoseconds. + Weight::from_parts(4_110_930, 990) + // Standard Error: 6_782 + .saturating_add(Weight::from_parts(2_241_357, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(12, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(20, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) .saturating_add(Weight::from_parts(0, 2475).saturating_mul(t.into())) @@ -712,10 +711,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 443_000 picoseconds. - Weight::from_parts(472_000, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_207, 0).saturating_mul(i.into())) + // Minimum execution time: 506_000 picoseconds. + Weight::from_parts(526_000, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -723,8 +722,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16618` // Estimated: `16618` - // Minimum execution time: 13_752_000 picoseconds. - Weight::from_parts(14_356_000, 16618) + // Minimum execution time: 16_531_000 picoseconds. + Weight::from_parts(16_947_000, 16618) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -733,8 +732,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `26628` // Estimated: `26628` - // Minimum execution time: 43_444_000 picoseconds. - Weight::from_parts(45_087_000, 26628) + // Minimum execution time: 57_673_000 picoseconds. + Weight::from_parts(63_131_000, 26628) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -743,8 +742,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16618` // Estimated: `16618` - // Minimum execution time: 15_616_000 picoseconds. - Weight::from_parts(16_010_000, 16618) + // Minimum execution time: 18_388_000 picoseconds. + Weight::from_parts(18_882_000, 16618) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -754,8 +753,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `26628` // Estimated: `26628` - // Minimum execution time: 47_020_000 picoseconds. - Weight::from_parts(50_152_000, 26628) + // Minimum execution time: 62_048_000 picoseconds. + Weight::from_parts(71_685_000, 26628) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -767,12 +766,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `250 + o * (1 ±0)` // Estimated: `249 + o * (1 ±0)` - // Minimum execution time: 8_824_000 picoseconds. - Weight::from_parts(8_915_233, 249) - // Standard Error: 1 - .saturating_add(Weight::from_parts(255, 0).saturating_mul(n.into())) - // Standard Error: 1 - .saturating_add(Weight::from_parts(39, 0).saturating_mul(o.into())) + // Minimum execution time: 11_886_000 picoseconds. + Weight::from_parts(11_100_121, 249) + // Standard Error: 2 + .saturating_add(Weight::from_parts(258, 0).saturating_mul(n.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(91, 0).saturating_mul(o.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -784,10 +783,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 7_133_000 picoseconds. - Weight::from_parts(7_912_778, 248) + // Minimum execution time: 9_576_000 picoseconds. + Weight::from_parts(10_418_109, 248) // Standard Error: 1 - .saturating_add(Weight::from_parts(88, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(115, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -799,10 +798,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 6_746_000 picoseconds. - Weight::from_parts(7_647_236, 248) + // Minimum execution time: 8_903_000 picoseconds. + Weight::from_parts(10_108_260, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(603, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(626, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -813,10 +812,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 6_247_000 picoseconds. - Weight::from_parts(6_952_661, 248) + // Minimum execution time: 8_216_000 picoseconds. + Weight::from_parts(9_267_036, 248) // Standard Error: 1 - .saturating_add(Weight::from_parts(77, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(103, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -827,10 +826,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 7_428_000 picoseconds. - Weight::from_parts(8_384_015, 248) + // Minimum execution time: 9_713_000 picoseconds. + Weight::from_parts(10_998_797, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(625, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(639, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -839,36 +838,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_478_000 picoseconds. - Weight::from_parts(1_533_000, 0) + // Minimum execution time: 1_521_000 picoseconds. + Weight::from_parts(1_612_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_485_000 picoseconds. - Weight::from_parts(2_728_000, 0) + // Minimum execution time: 2_866_000 picoseconds. + Weight::from_parts(3_150_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_195_000 picoseconds. - Weight::from_parts(3_811_000, 0) + // Minimum execution time: 3_200_000 picoseconds. + Weight::from_parts(3_373_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_902_000 picoseconds. - Weight::from_parts(4_118_000, 0) + // Minimum execution time: 4_138_000 picoseconds. + Weight::from_parts(4_488_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_571_000 picoseconds. - Weight::from_parts(1_662_000, 0) + // Minimum execution time: 1_594_000 picoseconds. + Weight::from_parts(1_799_000, 0) } /// The range of component `n` is `[0, 16384]`. /// The range of component `o` is `[0, 16384]`. @@ -876,57 +875,57 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_250_000 picoseconds. - Weight::from_parts(2_465_568, 0) + // Minimum execution time: 5_811_000 picoseconds. + Weight::from_parts(2_851_992, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(208, 0).saturating_mul(n.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(223, 0).saturating_mul(o.into())) + .saturating_add(Weight::from_parts(222, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_012_000 picoseconds. - Weight::from_parts(2_288_004, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(239, 0).saturating_mul(n.into())) + // Minimum execution time: 2_335_000 picoseconds. + Weight::from_parts(2_661_318, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(234, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_906_000 picoseconds. - Weight::from_parts(2_121_040, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(225, 0).saturating_mul(n.into())) + // Minimum execution time: 2_189_000 picoseconds. + Weight::from_parts(2_487_605, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(220, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_736_000 picoseconds. - Weight::from_parts(1_954_728, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(111, 0).saturating_mul(n.into())) + // Minimum execution time: 1_831_000 picoseconds. + Weight::from_parts(2_071_548, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(134, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_take_transient_storage(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_872_000 picoseconds. - Weight::from_parts(8_125_644, 0) + // Minimum execution time: 8_106_000 picoseconds. + Weight::from_parts(8_556_699, 0) } fn seal_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 8_489_000 picoseconds. - Weight::from_parts(8_791_000, 0) + // Minimum execution time: 10_433_000 picoseconds. + Weight::from_parts(10_873_000, 0) } /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) @@ -942,12 +941,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `620 + t * (280 ±0)` // Estimated: `4085 + t * (2182 ±0)` - // Minimum execution time: 122_759_000 picoseconds. - Weight::from_parts(120_016_020, 4085) - // Standard Error: 173_118 - .saturating_add(Weight::from_parts(42_848_338, 0).saturating_mul(t.into())) + // Minimum execution time: 140_018_000 picoseconds. + Weight::from_parts(142_816_362, 4085) + // Standard Error: 187_348 + .saturating_add(Weight::from_parts(42_978_763, 0).saturating_mul(t.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(6, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(3, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -962,8 +961,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `430` // Estimated: `3895` - // Minimum execution time: 111_566_000 picoseconds. - Weight::from_parts(115_083_000, 3895) + // Minimum execution time: 130_708_000 picoseconds. + Weight::from_parts(134_865_000, 3895) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) @@ -982,12 +981,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `676` // Estimated: `4132` - // Minimum execution time: 1_871_402_000 picoseconds. - Weight::from_parts(1_890_038_000, 4132) - // Standard Error: 24 - .saturating_add(Weight::from_parts(581, 0).saturating_mul(i.into())) - // Standard Error: 24 - .saturating_add(Weight::from_parts(915, 0).saturating_mul(s.into())) + // Minimum execution time: 1_891_181_000 picoseconds. + Weight::from_parts(1_901_270_000, 4132) + // Standard Error: 26 + .saturating_add(Weight::from_parts(617, 0).saturating_mul(i.into())) + // Standard Error: 26 + .saturating_add(Weight::from_parts(983, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -996,64 +995,64 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 966_000 picoseconds. - Weight::from_parts(9_599_151, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_336, 0).saturating_mul(n.into())) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(12_708_667, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_320, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_416_000 picoseconds. - Weight::from_parts(10_964_255, 0) + // Minimum execution time: 1_402_000 picoseconds. + Weight::from_parts(12_527_035, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_593, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_526, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 821_000 picoseconds. - Weight::from_parts(6_579_283, 0) + // Minimum execution time: 787_000 picoseconds. + Weight::from_parts(8_175_079, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_466, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_460, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 773_000 picoseconds. - Weight::from_parts(10_990_209, 0) + // Minimum execution time: 807_000 picoseconds. + Weight::from_parts(6_418_831, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_457, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 43_195_000 picoseconds. - Weight::from_parts(41_864_855, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(5_154, 0).saturating_mul(n.into())) + // Minimum execution time: 49_651_000 picoseconds. + Weight::from_parts(48_834_618, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(5_221, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 47_747_000 picoseconds. - Weight::from_parts(49_219_000, 0) + // Minimum execution time: 48_222_000 picoseconds. + Weight::from_parts(49_638_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_854_000 picoseconds. - Weight::from_parts(12_962_000, 0) + // Minimum execution time: 12_739_000 picoseconds. + Weight::from_parts(12_958_000, 0) } /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) @@ -1063,8 +1062,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `430` // Estimated: `3895` - // Minimum execution time: 17_868_000 picoseconds. - Weight::from_parts(18_486_000, 3895) + // Minimum execution time: 25_663_000 picoseconds. + Weight::from_parts(26_249_000, 3895) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -1074,8 +1073,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `355` // Estimated: `3820` - // Minimum execution time: 8_393_000 picoseconds. - Weight::from_parts(8_640_000, 3820) + // Minimum execution time: 14_726_000 picoseconds. + Weight::from_parts(15_392_000, 3820) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -1085,8 +1084,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `355` // Estimated: `3558` - // Minimum execution time: 7_489_000 picoseconds. - Weight::from_parts(7_815_000, 3558) + // Minimum execution time: 13_779_000 picoseconds. + Weight::from_parts(14_168_000, 3558) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -1094,15 +1093,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 299_000 picoseconds. - Weight::from_parts(339_000, 0) + // Minimum execution time: 359_000 picoseconds. + Weight::from_parts(402_000, 0) } fn seal_account_reentrance_count() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 324_000 picoseconds. - Weight::from_parts(380_000, 0) + // Minimum execution time: 339_000 picoseconds. + Weight::from_parts(389_000, 0) } /// Storage: `Contracts::Nonce` (r:1 w:0) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) @@ -1110,8 +1109,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `219` // Estimated: `1704` - // Minimum execution time: 2_768_000 picoseconds. - Weight::from_parts(3_025_000, 1704) + // Minimum execution time: 4_079_000 picoseconds. + Weight::from_parts(4_355_000, 1704) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 5000]`. @@ -1119,10 +1118,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766_000 picoseconds. - Weight::from_parts(722_169, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(7_191, 0).saturating_mul(r.into())) + // Minimum execution time: 836_000 picoseconds. + Weight::from_parts(591_552, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(7_522, 0).saturating_mul(r.into())) } } @@ -1134,8 +1133,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 1_915_000 picoseconds. - Weight::from_parts(1_986_000, 1627) + // Minimum execution time: 2_809_000 picoseconds. + Weight::from_parts(2_956_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1145,10 +1144,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 11_103_000 picoseconds. - Weight::from_parts(11_326_000, 442) - // Standard Error: 2_291 - .saturating_add(Weight::from_parts(1_196_329, 0).saturating_mul(k.into())) + // Minimum execution time: 17_559_000 picoseconds. + Weight::from_parts(17_850_000, 442) + // Standard Error: 2_722 + .saturating_add(Weight::from_parts(1_376_892, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1162,10 +1161,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 7_783_000 picoseconds. - Weight::from_parts(4_462_075, 6149) + // Minimum execution time: 8_830_000 picoseconds. + Weight::from_parts(6_649_003, 6149) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_634, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_676, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -1178,8 +1177,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 15_971_000 picoseconds. - Weight::from_parts(16_730_000, 6450) + // Minimum execution time: 21_927_000 picoseconds. + Weight::from_parts(22_655_000, 6450) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1192,10 +1191,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_149_000 picoseconds. - Weight::from_parts(3_264_000, 3635) - // Standard Error: 559 - .saturating_add(Weight::from_parts(1_111_209, 0).saturating_mul(k.into())) + // Minimum execution time: 4_465_000 picoseconds. + Weight::from_parts(4_774_000, 3635) + // Standard Error: 867 + .saturating_add(Weight::from_parts(1_071_462, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -1214,10 +1213,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `325 + c * (1 ±0)` // Estimated: `6263 + c * (1 ±0)` - // Minimum execution time: 15_072_000 picoseconds. - Weight::from_parts(15_721_891, 6263) + // Minimum execution time: 21_627_000 picoseconds. + Weight::from_parts(21_491_424, 6263) // Standard Error: 2 - .saturating_add(Weight::from_parts(428, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(480, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -1228,8 +1227,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 12_047_000 picoseconds. - Weight::from_parts(12_500_000, 6380) + // Minimum execution time: 17_262_000 picoseconds. + Weight::from_parts(17_785_000, 6380) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1238,13 +1237,13 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 47_488_000 picoseconds. - Weight::from_parts(48_482_000, 6292) + // Minimum execution time: 52_303_000 picoseconds. + Weight::from_parts(53_902_000, 6292) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1256,8 +1255,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 52_801_000 picoseconds. - Weight::from_parts(54_230_000, 6534) + // Minimum execution time: 58_585_000 picoseconds. + Weight::from_parts(60_478_000, 6534) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1267,8 +1266,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `409` // Estimated: `6349` - // Minimum execution time: 11_618_000 picoseconds. - Weight::from_parts(12_068_000, 6349) + // Minimum execution time: 16_673_000 picoseconds. + Weight::from_parts(17_325_000, 6349) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1278,8 +1277,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_131_000 picoseconds. - Weight::from_parts(2_255_000, 1627) + // Minimum execution time: 3_073_000 picoseconds. + Weight::from_parts(3_262_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1291,8 +1290,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 10_773_000 picoseconds. - Weight::from_parts(11_118_000, 3631) + // Minimum execution time: 11_687_000 picoseconds. + Weight::from_parts(12_178_000, 3631) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1302,8 +1301,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_371_000 picoseconds. - Weight::from_parts(4_624_000, 3607) + // Minimum execution time: 4_553_000 picoseconds. + Weight::from_parts(4_826_000, 3607) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -1314,8 +1313,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 5_612_000 picoseconds. - Weight::from_parts(5_838_000, 3632) + // Minimum execution time: 6_794_000 picoseconds. + Weight::from_parts(6_959_000, 3632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -1326,8 +1325,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 5_487_000 picoseconds. - Weight::from_parts(5_693_000, 3607) + // Minimum execution time: 6_120_000 picoseconds. + Weight::from_parts(6_420_000, 3607) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1347,11 +1346,11 @@ impl WeightInfo for () { fn call_with_code_per_byte(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `800 + c * (1 ±0)` - // Estimated: `4266 + c * (1 ±0)` - // Minimum execution time: 247_545_000 picoseconds. - Weight::from_parts(268_016_699, 4266) - // Standard Error: 4 - .saturating_add(Weight::from_parts(700, 0).saturating_mul(c.into())) + // Estimated: `4268 + c * (1 ±0)` + // Minimum execution time: 266_424_000 picoseconds. + Weight::from_parts(283_325_502, 4268) + // Standard Error: 12 + .saturating_add(Weight::from_parts(950, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -1361,7 +1360,7 @@ impl WeightInfo for () { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) @@ -1378,15 +1377,15 @@ impl WeightInfo for () { fn instantiate_with_code(c: u32, i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `323` - // Estimated: `6262` - // Minimum execution time: 4_396_772_000 picoseconds. - Weight::from_parts(235_107_907, 6262) - // Standard Error: 185 - .saturating_add(Weight::from_parts(53_843, 0).saturating_mul(c.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(2_143, 0).saturating_mul(i.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(2_210, 0).saturating_mul(s.into())) + // Estimated: `6267` + // Minimum execution time: 4_371_315_000 picoseconds. + Weight::from_parts(4_739_462_000, 6267) + // Standard Error: 329 + .saturating_add(Weight::from_parts(38_518, 0).saturating_mul(c.into())) + // Standard Error: 39 + .saturating_add(Weight::from_parts(605, 0).saturating_mul(i.into())) + // Standard Error: 39 + .saturating_add(Weight::from_parts(561, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1405,19 +1404,19 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `560` - // Estimated: `4017` - // Minimum execution time: 2_240_868_000 picoseconds. - Weight::from_parts(2_273_668_000, 4017) - // Standard Error: 32 - .saturating_add(Weight::from_parts(934, 0).saturating_mul(i.into())) - // Standard Error: 32 - .saturating_add(Weight::from_parts(920, 0).saturating_mul(s.into())) + // Estimated: `4016` + // Minimum execution time: 2_304_531_000 picoseconds. + Weight::from_parts(2_352_810_000, 4016) + // Standard Error: 35 + .saturating_add(Weight::from_parts(1_004, 0).saturating_mul(i.into())) + // Standard Error: 35 + .saturating_add(Weight::from_parts(936, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1437,8 +1436,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `826` // Estimated: `4291` - // Minimum execution time: 165_067_000 picoseconds. - Weight::from_parts(168_582_000, 4291) + // Minimum execution time: 183_658_000 picoseconds. + Weight::from_parts(189_507_000, 4291) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1447,7 +1446,7 @@ impl WeightInfo for () { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) /// The range of component `c` is `[0, 125952]`. @@ -1455,10 +1454,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 229_454_000 picoseconds. - Weight::from_parts(251_495_551, 3607) - // Standard Error: 71 - .saturating_add(Weight::from_parts(51_428, 0).saturating_mul(c.into())) + // Minimum execution time: 253_006_000 picoseconds. + Weight::from_parts(269_271_744, 3607) + // Standard Error: 79 + .saturating_add(Weight::from_parts(49_970, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1467,7 +1466,7 @@ impl WeightInfo for () { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) /// The range of component `c` is `[0, 125952]`. @@ -1475,10 +1474,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 240_390_000 picoseconds. - Weight::from_parts(273_854_266, 3607) - // Standard Error: 243 - .saturating_add(Weight::from_parts(51_836, 0).saturating_mul(c.into())) + // Minimum execution time: 247_567_000 picoseconds. + Weight::from_parts(271_875_922, 3607) + // Standard Error: 78 + .saturating_add(Weight::from_parts(50_117, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1487,15 +1486,15 @@ impl WeightInfo for () { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 39_374_000 picoseconds. - Weight::from_parts(40_247_000, 3780) + // Minimum execution time: 48_151_000 picoseconds. + Weight::from_parts(49_407_000, 3780) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1509,8 +1508,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `552` // Estimated: `6492` - // Minimum execution time: 24_473_000 picoseconds. - Weight::from_parts(25_890_000, 6492) + // Minimum execution time: 30_173_000 picoseconds. + Weight::from_parts(30_941_000, 6492) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1519,17 +1518,17 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_528_000 picoseconds. - Weight::from_parts(9_301_010, 0) - // Standard Error: 98 - .saturating_add(Weight::from_parts(53_173, 0).saturating_mul(r.into())) + // Minimum execution time: 8_350_000 picoseconds. + Weight::from_parts(9_238_867, 0) + // Standard Error: 139 + .saturating_add(Weight::from_parts(52_355, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 643_000 picoseconds. - Weight::from_parts(678_000, 0) + // Minimum execution time: 757_000 picoseconds. + Weight::from_parts(827_000, 0) } /// Storage: `Contracts::ContractInfoOf` (r:1 w:0) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) @@ -1537,8 +1536,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `354` // Estimated: `3819` - // Minimum execution time: 6_107_000 picoseconds. - Weight::from_parts(6_235_000, 3819) + // Minimum execution time: 12_202_000 picoseconds. + Weight::from_parts(12_708_000, 3819) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Contracts::ContractInfoOf` (r:1 w:0) @@ -1547,109 +1546,106 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `447` // Estimated: `3912` - // Minimum execution time: 7_316_000 picoseconds. - Weight::from_parts(7_653_000, 3912) + // Minimum execution time: 13_492_000 picoseconds. + Weight::from_parts(13_845_000, 3912) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 721_000 picoseconds. - Weight::from_parts(764_000, 0) + // Minimum execution time: 798_000 picoseconds. + Weight::from_parts(856_000, 0) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 369_000 picoseconds. - Weight::from_parts(417_000, 0) + // Minimum execution time: 364_000 picoseconds. + Weight::from_parts(414_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 318_000 picoseconds. - Weight::from_parts(349_000, 0) + // Minimum execution time: 355_000 picoseconds. + Weight::from_parts(396_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 590_000 picoseconds. - Weight::from_parts(628_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(719_000, 0) } fn seal_gas_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 660_000 picoseconds. - Weight::from_parts(730_000, 0) + // Minimum execution time: 770_000 picoseconds. + Weight::from_parts(827_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 4_361_000 picoseconds. - Weight::from_parts(4_577_000, 0) + // Minimum execution time: 5_839_000 picoseconds. + Weight::from_parts(6_174_000, 0) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 560_000 picoseconds. - Weight::from_parts(603_000, 0) + // Minimum execution time: 681_000 picoseconds. + Weight::from_parts(757_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(610_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(730_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 557_000 picoseconds. - Weight::from_parts(583_000, 0) + // Minimum execution time: 654_000 picoseconds. + Weight::from_parts(713_000, 0) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 550_000 picoseconds. - Weight::from_parts(602_000, 0) + // Minimum execution time: 707_000 picoseconds. + Weight::from_parts(752_000, 0) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) fn seal_weight_to_fee() -> Weight { // Proof Size summary in bytes: - // Measured: `67` - // Estimated: `1552` - // Minimum execution time: 4_065_000 picoseconds. - Weight::from_parts(4_291_000, 1552) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_562_000 picoseconds. + Weight::from_parts(1_749_000, 0) } /// The range of component `n` is `[0, 1048572]`. fn seal_input(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 487_000 picoseconds. - Weight::from_parts(517_000, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(301, 0).saturating_mul(n.into())) + // Minimum execution time: 483_000 picoseconds. + Weight::from_parts(536_000, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(329, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048572]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 318_000 picoseconds. - Weight::from_parts(372_000, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(411, 0).saturating_mul(n.into())) + // Minimum execution time: 372_000 picoseconds. + Weight::from_parts(384_000, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(433, 0).saturating_mul(n.into())) } /// Storage: `Contracts::DeletionQueueCounter` (r:1 w:1) /// Proof: `Contracts::DeletionQueueCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) @@ -1662,10 +1658,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `319 + n * (78 ±0)` // Estimated: `3784 + n * (2553 ±0)` - // Minimum execution time: 13_251_000 picoseconds. - Weight::from_parts(15_257_892, 3784) - // Standard Error: 7_089 - .saturating_add(Weight::from_parts(3_443_907, 0).saturating_mul(n.into())) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(20_544_934, 3784) + // Standard Error: 9_422 + .saturating_add(Weight::from_parts(4_431_910, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -1678,8 +1674,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 3_434_000 picoseconds. - Weight::from_parts(3_605_000, 1561) + // Minimum execution time: 4_503_000 picoseconds. + Weight::from_parts(4_743_000, 1561) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `System::EventTopics` (r:4 w:4) @@ -1690,12 +1686,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `990 + t * (2475 ±0)` - // Minimum execution time: 3_668_000 picoseconds. - Weight::from_parts(3_999_591, 990) - // Standard Error: 5_767 - .saturating_add(Weight::from_parts(2_011_090, 0).saturating_mul(t.into())) + // Minimum execution time: 3_838_000 picoseconds. + Weight::from_parts(4_110_930, 990) + // Standard Error: 6_782 + .saturating_add(Weight::from_parts(2_241_357, 0).saturating_mul(t.into())) // Standard Error: 1 - .saturating_add(Weight::from_parts(12, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(20, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) .saturating_add(Weight::from_parts(0, 2475).saturating_mul(t.into())) @@ -1705,10 +1701,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 443_000 picoseconds. - Weight::from_parts(472_000, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_207, 0).saturating_mul(i.into())) + // Minimum execution time: 506_000 picoseconds. + Weight::from_parts(526_000, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -1716,8 +1712,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `16618` // Estimated: `16618` - // Minimum execution time: 13_752_000 picoseconds. - Weight::from_parts(14_356_000, 16618) + // Minimum execution time: 16_531_000 picoseconds. + Weight::from_parts(16_947_000, 16618) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1726,8 +1722,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `26628` // Estimated: `26628` - // Minimum execution time: 43_444_000 picoseconds. - Weight::from_parts(45_087_000, 26628) + // Minimum execution time: 57_673_000 picoseconds. + Weight::from_parts(63_131_000, 26628) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1736,8 +1732,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `16618` // Estimated: `16618` - // Minimum execution time: 15_616_000 picoseconds. - Weight::from_parts(16_010_000, 16618) + // Minimum execution time: 18_388_000 picoseconds. + Weight::from_parts(18_882_000, 16618) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1747,8 +1743,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `26628` // Estimated: `26628` - // Minimum execution time: 47_020_000 picoseconds. - Weight::from_parts(50_152_000, 26628) + // Minimum execution time: 62_048_000 picoseconds. + Weight::from_parts(71_685_000, 26628) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1760,12 +1756,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `250 + o * (1 ±0)` // Estimated: `249 + o * (1 ±0)` - // Minimum execution time: 8_824_000 picoseconds. - Weight::from_parts(8_915_233, 249) - // Standard Error: 1 - .saturating_add(Weight::from_parts(255, 0).saturating_mul(n.into())) - // Standard Error: 1 - .saturating_add(Weight::from_parts(39, 0).saturating_mul(o.into())) + // Minimum execution time: 11_886_000 picoseconds. + Weight::from_parts(11_100_121, 249) + // Standard Error: 2 + .saturating_add(Weight::from_parts(258, 0).saturating_mul(n.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(91, 0).saturating_mul(o.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -1777,10 +1773,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 7_133_000 picoseconds. - Weight::from_parts(7_912_778, 248) + // Minimum execution time: 9_576_000 picoseconds. + Weight::from_parts(10_418_109, 248) // Standard Error: 1 - .saturating_add(Weight::from_parts(88, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(115, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1792,10 +1788,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 6_746_000 picoseconds. - Weight::from_parts(7_647_236, 248) + // Minimum execution time: 8_903_000 picoseconds. + Weight::from_parts(10_108_260, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(603, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(626, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1806,10 +1802,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 6_247_000 picoseconds. - Weight::from_parts(6_952_661, 248) + // Minimum execution time: 8_216_000 picoseconds. + Weight::from_parts(9_267_036, 248) // Standard Error: 1 - .saturating_add(Weight::from_parts(77, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(103, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1820,10 +1816,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 7_428_000 picoseconds. - Weight::from_parts(8_384_015, 248) + // Minimum execution time: 9_713_000 picoseconds. + Weight::from_parts(10_998_797, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(625, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(639, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1832,36 +1828,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_478_000 picoseconds. - Weight::from_parts(1_533_000, 0) + // Minimum execution time: 1_521_000 picoseconds. + Weight::from_parts(1_612_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_485_000 picoseconds. - Weight::from_parts(2_728_000, 0) + // Minimum execution time: 2_866_000 picoseconds. + Weight::from_parts(3_150_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_195_000 picoseconds. - Weight::from_parts(3_811_000, 0) + // Minimum execution time: 3_200_000 picoseconds. + Weight::from_parts(3_373_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_902_000 picoseconds. - Weight::from_parts(4_118_000, 0) + // Minimum execution time: 4_138_000 picoseconds. + Weight::from_parts(4_488_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_571_000 picoseconds. - Weight::from_parts(1_662_000, 0) + // Minimum execution time: 1_594_000 picoseconds. + Weight::from_parts(1_799_000, 0) } /// The range of component `n` is `[0, 16384]`. /// The range of component `o` is `[0, 16384]`. @@ -1869,57 +1865,57 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_250_000 picoseconds. - Weight::from_parts(2_465_568, 0) + // Minimum execution time: 5_811_000 picoseconds. + Weight::from_parts(2_851_992, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(208, 0).saturating_mul(n.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(223, 0).saturating_mul(o.into())) + .saturating_add(Weight::from_parts(222, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_012_000 picoseconds. - Weight::from_parts(2_288_004, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(239, 0).saturating_mul(n.into())) + // Minimum execution time: 2_335_000 picoseconds. + Weight::from_parts(2_661_318, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(234, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_906_000 picoseconds. - Weight::from_parts(2_121_040, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(225, 0).saturating_mul(n.into())) + // Minimum execution time: 2_189_000 picoseconds. + Weight::from_parts(2_487_605, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(220, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_736_000 picoseconds. - Weight::from_parts(1_954_728, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(111, 0).saturating_mul(n.into())) + // Minimum execution time: 1_831_000 picoseconds. + Weight::from_parts(2_071_548, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(134, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 16384]`. fn seal_take_transient_storage(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_872_000 picoseconds. - Weight::from_parts(8_125_644, 0) + // Minimum execution time: 8_106_000 picoseconds. + Weight::from_parts(8_556_699, 0) } fn seal_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 8_489_000 picoseconds. - Weight::from_parts(8_791_000, 0) + // Minimum execution time: 10_433_000 picoseconds. + Weight::from_parts(10_873_000, 0) } /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) @@ -1935,12 +1931,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `620 + t * (280 ±0)` // Estimated: `4085 + t * (2182 ±0)` - // Minimum execution time: 122_759_000 picoseconds. - Weight::from_parts(120_016_020, 4085) - // Standard Error: 173_118 - .saturating_add(Weight::from_parts(42_848_338, 0).saturating_mul(t.into())) + // Minimum execution time: 140_018_000 picoseconds. + Weight::from_parts(142_816_362, 4085) + // Standard Error: 187_348 + .saturating_add(Weight::from_parts(42_978_763, 0).saturating_mul(t.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(6, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(3, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -1955,8 +1951,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `430` // Estimated: `3895` - // Minimum execution time: 111_566_000 picoseconds. - Weight::from_parts(115_083_000, 3895) + // Minimum execution time: 130_708_000 picoseconds. + Weight::from_parts(134_865_000, 3895) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) @@ -1975,12 +1971,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `676` // Estimated: `4132` - // Minimum execution time: 1_871_402_000 picoseconds. - Weight::from_parts(1_890_038_000, 4132) - // Standard Error: 24 - .saturating_add(Weight::from_parts(581, 0).saturating_mul(i.into())) - // Standard Error: 24 - .saturating_add(Weight::from_parts(915, 0).saturating_mul(s.into())) + // Minimum execution time: 1_891_181_000 picoseconds. + Weight::from_parts(1_901_270_000, 4132) + // Standard Error: 26 + .saturating_add(Weight::from_parts(617, 0).saturating_mul(i.into())) + // Standard Error: 26 + .saturating_add(Weight::from_parts(983, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1989,64 +1985,64 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 966_000 picoseconds. - Weight::from_parts(9_599_151, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_336, 0).saturating_mul(n.into())) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(12_708_667, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_320, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_416_000 picoseconds. - Weight::from_parts(10_964_255, 0) + // Minimum execution time: 1_402_000 picoseconds. + Weight::from_parts(12_527_035, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_593, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_526, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 821_000 picoseconds. - Weight::from_parts(6_579_283, 0) + // Minimum execution time: 787_000 picoseconds. + Weight::from_parts(8_175_079, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_466, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_460, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 773_000 picoseconds. - Weight::from_parts(10_990_209, 0) + // Minimum execution time: 807_000 picoseconds. + Weight::from_parts(6_418_831, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_457, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 43_195_000 picoseconds. - Weight::from_parts(41_864_855, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(5_154, 0).saturating_mul(n.into())) + // Minimum execution time: 49_651_000 picoseconds. + Weight::from_parts(48_834_618, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(5_221, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 47_747_000 picoseconds. - Weight::from_parts(49_219_000, 0) + // Minimum execution time: 48_222_000 picoseconds. + Weight::from_parts(49_638_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_854_000 picoseconds. - Weight::from_parts(12_962_000, 0) + // Minimum execution time: 12_739_000 picoseconds. + Weight::from_parts(12_958_000, 0) } /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) @@ -2056,8 +2052,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `430` // Estimated: `3895` - // Minimum execution time: 17_868_000 picoseconds. - Weight::from_parts(18_486_000, 3895) + // Minimum execution time: 25_663_000 picoseconds. + Weight::from_parts(26_249_000, 3895) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2067,8 +2063,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `355` // Estimated: `3820` - // Minimum execution time: 8_393_000 picoseconds. - Weight::from_parts(8_640_000, 3820) + // Minimum execution time: 14_726_000 picoseconds. + Weight::from_parts(15_392_000, 3820) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2078,8 +2074,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `355` // Estimated: `3558` - // Minimum execution time: 7_489_000 picoseconds. - Weight::from_parts(7_815_000, 3558) + // Minimum execution time: 13_779_000 picoseconds. + Weight::from_parts(14_168_000, 3558) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2087,15 +2083,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 299_000 picoseconds. - Weight::from_parts(339_000, 0) + // Minimum execution time: 359_000 picoseconds. + Weight::from_parts(402_000, 0) } fn seal_account_reentrance_count() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 324_000 picoseconds. - Weight::from_parts(380_000, 0) + // Minimum execution time: 339_000 picoseconds. + Weight::from_parts(389_000, 0) } /// Storage: `Contracts::Nonce` (r:1 w:0) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) @@ -2103,8 +2099,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `219` // Estimated: `1704` - // Minimum execution time: 2_768_000 picoseconds. - Weight::from_parts(3_025_000, 1704) + // Minimum execution time: 4_079_000 picoseconds. + Weight::from_parts(4_355_000, 1704) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 5000]`. @@ -2112,9 +2108,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 766_000 picoseconds. - Weight::from_parts(722_169, 0) - // Standard Error: 10 - .saturating_add(Weight::from_parts(7_191, 0).saturating_mul(r.into())) + // Minimum execution time: 836_000 picoseconds. + Weight::from_parts(591_552, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(7_522, 0).saturating_mul(r.into())) } } diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index 09c70c287899..8297c35b31db 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -12,16 +12,16 @@ description = "Exposes all the host functions that a contract can import." workspace = true [dependencies] -paste = { workspace = true } bitflags = { workspace = true } -scale-info = { features = ["derive"], optional = true, workspace = true } codec = { features = [ "derive", "max-encoded-len", ], optional = true, workspace = true } +paste = { workspace = true } +scale-info = { features = ["derive"], optional = true, workspace = true } [package.metadata.docs.rs] -default-target = ["wasm32-unknown-unknown"] +targets = ["wasm32-unknown-unknown"] [features] default = ["scale"] diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index fdb4310610d9..2d23f493ea01 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -21,11 +21,11 @@ codec = { features = [ "derive", "max-encoded-len", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/conviction-voting/src/lib.rs b/substrate/frame/conviction-voting/src/lib.rs index 85da1aed3c27..31bd6b85ec86 100644 --- a/substrate/frame/conviction-voting/src/lib.rs +++ b/substrate/frame/conviction-voting/src/lib.rs @@ -171,10 +171,12 @@ pub mod pallet { Delegated(T::AccountId, T::AccountId), /// An \[account\] has cancelled a previous delegation operation. Undelegated(T::AccountId), - /// An account that has voted + /// An account has voted Voted { who: T::AccountId, vote: AccountVote> }, - /// A vote that been removed + /// A vote has been removed VoteRemoved { who: T::AccountId, vote: AccountVote> }, + /// The lockup period of a conviction vote expired, and the funds have been unlocked. + VoteUnlocked { who: T::AccountId, class: ClassOf }, } #[pallet::error] @@ -315,6 +317,7 @@ pub mod pallet { ensure_signed(origin)?; let target = T::Lookup::lookup(target)?; Self::update_lock(&class, &target); + Self::deposit_event(Event::VoteUnlocked { who: target, class }); Ok(()) } diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs index 37cdd7a5b338..dd9ee33ee183 100644 --- a/substrate/frame/conviction-voting/src/tests.rs +++ b/substrate/frame/conviction-voting/src/tests.rs @@ -238,27 +238,52 @@ fn basic_stuff() { fn basic_voting_works() { new_test_ext().execute_with(|| { assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(2, 5))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: aye(2, 5), + })); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(2, 5))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: nay(2, 5), + })); assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(5, 1))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: aye(5, 1), + })); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(5, 1))); assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: aye(10, 0), + })); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(10, 0))); assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::VoteRemoved { + who: 1, + vote: nay(10, 0), + })); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::VoteUnlocked { + who: 1, + class: class(3), + })); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -267,15 +292,32 @@ fn basic_voting_works() { fn split_voting_works() { new_test_ext().execute_with(|| { assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split(10, 0))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: split(10, 0), + })); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split(5, 5))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: split(5, 5), + })); assert_eq!(tally(3), Tally::from_parts(0, 0, 5)); assert_eq!(Balances::usable_balance(1), 0); assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::VoteRemoved { + who: 1, + vote: split(5, 5), + })); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::VoteUnlocked { + who: 1, + class: class(3), + })); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -284,25 +326,48 @@ fn split_voting_works() { fn abstain_voting_works() { new_test_ext().execute_with(|| { assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, split_abstain(0, 0, 10))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 1, + vote: split_abstain(0, 0, 10), + })); assert_eq!(tally(3), Tally::from_parts(0, 0, 10)); - assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, split_abstain(0, 0, 20))); - assert_eq!(tally(3), Tally::from_parts(0, 0, 30)); - assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, split_abstain(10, 0, 10))); - assert_eq!(tally(3), Tally::from_parts(1, 0, 30)); + + assert_ok!(Voting::vote(RuntimeOrigin::signed(6), 3, split_abstain(10, 0, 20))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 6, + vote: split_abstain(10, 0, 20), + })); + assert_eq!(tally(3), Tally::from_parts(1, 0, 40)); + + assert_ok!(Voting::vote(RuntimeOrigin::signed(6), 3, split_abstain(0, 0, 40))); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::Voted { + who: 6, + vote: split_abstain(0, 0, 40), + })); + + assert_eq!(tally(3), Tally::from_parts(0, 0, 50)); assert_eq!(Balances::usable_balance(1), 0); - assert_eq!(Balances::usable_balance(2), 0); + assert_eq!(Balances::usable_balance(6), 20); assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); - assert_eq!(tally(3), Tally::from_parts(1, 0, 20)); - - assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(2), None, 3)); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::VoteRemoved { + who: 1, + vote: split_abstain(0, 0, 10), + })); + assert_eq!(tally(3), Tally::from_parts(0, 0, 40)); + + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(6), Some(class(3)), 3)); + System::assert_last_event(tests::RuntimeEvent::Voting(Event::VoteRemoved { + who: 6, + vote: split_abstain(0, 0, 40), + })); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); assert_eq!(Balances::usable_balance(1), 10); - assert_ok!(Voting::unlock(RuntimeOrigin::signed(2), class(3), 2)); - assert_eq!(Balances::usable_balance(2), 20); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(6), class(3), 6)); + assert_eq!(Balances::usable_balance(6), 60); }); } diff --git a/substrate/frame/conviction-voting/src/types.rs b/substrate/frame/conviction-voting/src/types.rs index d6bbb678a14b..aa7dd578fbad 100644 --- a/substrate/frame/conviction-voting/src/types.rs +++ b/substrate/frame/conviction-voting/src/types.rs @@ -117,14 +117,9 @@ impl< pub fn from_parts( ayes_with_conviction: Votes, nays_with_conviction: Votes, - ayes: Votes, + support: Votes, ) -> Self { - Self { - ayes: ayes_with_conviction, - nays: nays_with_conviction, - support: ayes, - dummy: PhantomData, - } + Self { ayes: ayes_with_conviction, nays: nays_with_conviction, support, dummy: PhantomData } } /// Add an account's vote into the tally. diff --git a/substrate/frame/conviction-voting/src/weights.rs b/substrate/frame/conviction-voting/src/weights.rs index d8f3ffcb3be6..1abcd83e7d5c 100644 --- a/substrate/frame/conviction-voting/src/weights.rs +++ b/substrate/frame/conviction-voting/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_conviction_voting` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -81,8 +81,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `13141` // Estimated: `219984` - // Minimum execution time: 114_422_000 picoseconds. - Weight::from_parts(118_642_000, 219984) + // Minimum execution time: 135_295_000 picoseconds. + Weight::from_parts(142_897_000, 219984) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -104,8 +104,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `20283` // Estimated: `219984` - // Minimum execution time: 290_934_000 picoseconds. - Weight::from_parts(303_286_000, 219984) + // Minimum execution time: 324_485_000 picoseconds. + Weight::from_parts(337_467_000, 219984) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -121,8 +121,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `20035` // Estimated: `219984` - // Minimum execution time: 277_464_000 picoseconds. - Weight::from_parts(284_288_000, 219984) + // Minimum execution time: 302_574_000 picoseconds. + Weight::from_parts(315_016_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -134,8 +134,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `12742` // Estimated: `30706` - // Minimum execution time: 54_538_000 picoseconds. - Weight::from_parts(55_758_000, 30706) + // Minimum execution time: 65_548_000 picoseconds. + Weight::from_parts(71_499_000, 30706) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -158,10 +158,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `306 + r * (1628 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 47_243_000 picoseconds. - Weight::from_parts(50_023_534, 109992) - // Standard Error: 228_993 - .saturating_add(Weight::from_parts(43_173_465, 0).saturating_mul(r.into())) + // Minimum execution time: 61_383_000 picoseconds. + Weight::from_parts(70_695_789, 109992) + // Standard Error: 457_836 + .saturating_add(Weight::from_parts(44_163_910, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -181,10 +181,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `472 + r * (1377 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 23_529_000 picoseconds. - Weight::from_parts(25_071_526, 109992) - // Standard Error: 138_190 - .saturating_add(Weight::from_parts(40_350_973, 0).saturating_mul(r.into())) + // Minimum execution time: 33_466_000 picoseconds. + Weight::from_parts(39_261_420, 109992) + // Standard Error: 358_545 + .saturating_add(Weight::from_parts(43_197_579, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -203,8 +203,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `11800` // Estimated: `30706` - // Minimum execution time: 69_473_000 picoseconds. - Weight::from_parts(71_519_000, 30706) + // Minimum execution time: 87_030_000 picoseconds. + Weight::from_parts(91_851_000, 30706) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -230,8 +230,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `13141` // Estimated: `219984` - // Minimum execution time: 114_422_000 picoseconds. - Weight::from_parts(118_642_000, 219984) + // Minimum execution time: 135_295_000 picoseconds. + Weight::from_parts(142_897_000, 219984) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -253,8 +253,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `20283` // Estimated: `219984` - // Minimum execution time: 290_934_000 picoseconds. - Weight::from_parts(303_286_000, 219984) + // Minimum execution time: 324_485_000 picoseconds. + Weight::from_parts(337_467_000, 219984) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -270,8 +270,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `20035` // Estimated: `219984` - // Minimum execution time: 277_464_000 picoseconds. - Weight::from_parts(284_288_000, 219984) + // Minimum execution time: 302_574_000 picoseconds. + Weight::from_parts(315_016_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -283,8 +283,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `12742` // Estimated: `30706` - // Minimum execution time: 54_538_000 picoseconds. - Weight::from_parts(55_758_000, 30706) + // Minimum execution time: 65_548_000 picoseconds. + Weight::from_parts(71_499_000, 30706) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -307,10 +307,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `306 + r * (1628 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 47_243_000 picoseconds. - Weight::from_parts(50_023_534, 109992) - // Standard Error: 228_993 - .saturating_add(Weight::from_parts(43_173_465, 0).saturating_mul(r.into())) + // Minimum execution time: 61_383_000 picoseconds. + Weight::from_parts(70_695_789, 109992) + // Standard Error: 457_836 + .saturating_add(Weight::from_parts(44_163_910, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -330,10 +330,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `472 + r * (1377 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 23_529_000 picoseconds. - Weight::from_parts(25_071_526, 109992) - // Standard Error: 138_190 - .saturating_add(Weight::from_parts(40_350_973, 0).saturating_mul(r.into())) + // Minimum execution time: 33_466_000 picoseconds. + Weight::from_parts(39_261_420, 109992) + // Standard Error: 358_545 + .saturating_add(Weight::from_parts(43_197_579, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -352,8 +352,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `11800` // Estimated: `30706` - // Minimum execution time: 69_473_000 picoseconds. - Weight::from_parts(71_519_000, 30706) + // Minimum execution time: 87_030_000 picoseconds. + Weight::from_parts(91_851_000, 30706) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index 3d73ec58d613..c0017f477251 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +pallet-ranked-collective = { optional = true, workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -pallet-ranked-collective = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/frame/core-fellowship/src/tests/integration.rs b/substrate/frame/core-fellowship/src/tests/integration.rs index bcf70c7beb10..7a48ed9783e7 100644 --- a/substrate/frame/core-fellowship/src/tests/integration.rs +++ b/substrate/frame/core-fellowship/src/tests/integration.rs @@ -21,15 +21,15 @@ use frame_support::{ assert_noop, assert_ok, derive_impl, hypothetically, ord_parameter_types, pallet_prelude::Weight, parameter_types, - traits::{ConstU16, EitherOf, IsInVec, MapSuccess, PollStatus, Polling, TryMapSuccess}, + traits::{ConstU16, EitherOf, IsInVec, MapSuccess, NoOpPoll, TryMapSuccess}, }; use frame_system::EnsureSignedBy; -use pallet_ranked_collective::{EnsureRanked, Geometric, Rank, TallyOf, Votes}; +use pallet_ranked_collective::{EnsureRanked, Geometric, Rank}; use sp_core::{ConstU32, Get}; use sp_runtime::{ bounded_vec, traits::{Convert, ReduceBy, ReplaceWithDefault, TryMorphInto}, - BuildStorage, DispatchError, + BuildStorage, }; type Class = Rank; @@ -83,45 +83,6 @@ impl Config for Test { type MaxRank = ConstU32<9>; } -pub struct TestPolls; -impl Polling> for TestPolls { - type Index = u8; - type Votes = Votes; - type Moment = u64; - type Class = Class; - - fn classes() -> Vec { - unimplemented!() - } - fn as_ongoing(_: u8) -> Option<(TallyOf, Self::Class)> { - unimplemented!() - } - fn access_poll( - _: Self::Index, - _: impl FnOnce(PollStatus<&mut TallyOf, Self::Moment, Self::Class>) -> R, - ) -> R { - unimplemented!() - } - fn try_access_poll( - _: Self::Index, - _: impl FnOnce( - PollStatus<&mut TallyOf, Self::Moment, Self::Class>, - ) -> Result, - ) -> Result { - unimplemented!() - } - - #[cfg(feature = "runtime-benchmarks")] - fn create_ongoing(_: Self::Class) -> Result { - unimplemented!() - } - - #[cfg(feature = "runtime-benchmarks")] - fn end_ongoing(_: Self::Index, _: bool) -> Result<(), ()> { - unimplemented!() - } -} - /// Convert the tally class into the minimum rank required to vote on the poll. /// MinRank(Class) = Class - Delta pub struct MinRankOfClass(PhantomData); @@ -154,7 +115,7 @@ impl pallet_ranked_collective::Config for Test { // Members can exchange up to the rank of 2 below them. MapSuccess, ReduceBy>>, >; - type Polls = TestPolls; + type Polls = NoOpPoll; type MinRankOfClass = MinRankOfClass; type MemberSwappedHandler = CoreFellowship; type VoteWeight = Geometric; diff --git a/substrate/frame/core-fellowship/src/weights.rs b/substrate/frame/core-fellowship/src/weights.rs index 5e64600b662b..9bca8cb56094 100644 --- a/substrate/frame/core-fellowship/src/weights.rs +++ b/substrate/frame/core-fellowship/src/weights.rs @@ -18,25 +18,27 @@ //! Autogenerated weights for `pallet_core_fellowship` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-06-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-x5tnzzy-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate-node +// ./target/production/substrate-node // benchmark // pallet +// --chain=dev // --steps=50 // --repeat=20 +// --pallet=pallet_core_fellowship +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_core_fellowship -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/core-fellowship/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -72,8 +74,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_772_000 picoseconds. - Weight::from_parts(6_000_000, 0) + // Minimum execution time: 6_652_000 picoseconds. + Weight::from_parts(7_082_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `CoreFellowship::Params` (r:1 w:1) @@ -82,8 +84,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `399` // Estimated: `1853` - // Minimum execution time: 10_050_000 picoseconds. - Weight::from_parts(10_244_000, 1853) + // Minimum execution time: 12_485_000 picoseconds. + Weight::from_parts(12_784_000, 1853) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -105,8 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `17278` // Estimated: `19894` - // Minimum execution time: 54_433_000 picoseconds. - Weight::from_parts(55_650_000, 19894) + // Minimum execution time: 61_243_000 picoseconds. + Weight::from_parts(63_033_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -128,8 +130,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `17388` // Estimated: `19894` - // Minimum execution time: 57_634_000 picoseconds. - Weight::from_parts(58_816_000, 19894) + // Minimum execution time: 65_063_000 picoseconds. + Weight::from_parts(67_047_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -141,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3514` - // Minimum execution time: 14_527_000 picoseconds. - Weight::from_parts(14_948_000, 3514) + // Minimum execution time: 21_924_000 picoseconds. + Weight::from_parts(22_691_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -160,8 +162,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3514` - // Minimum execution time: 22_137_000 picoseconds. - Weight::from_parts(22_925_000, 3514) + // Minimum execution time: 24_720_000 picoseconds. + Weight::from_parts(25_580_000, 3514) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -183,8 +185,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16931` // Estimated: `19894` - // Minimum execution time: 51_837_000 picoseconds. - Weight::from_parts(52_810_000, 19894) + // Minimum execution time: 58_481_000 picoseconds. + Weight::from_parts(59_510_000, 19894) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -205,10 +207,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16844` // Estimated: `19894 + r * (2489 ±0)` - // Minimum execution time: 45_065_000 picoseconds. - Weight::from_parts(34_090_392, 19894) - // Standard Error: 18_620 - .saturating_add(Weight::from_parts(13_578_046, 0).saturating_mul(r.into())) + // Minimum execution time: 53_570_000 picoseconds. + Weight::from_parts(42_220_685, 19894) + // Standard Error: 18_061 + .saturating_add(Weight::from_parts(13_858_309, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -225,8 +227,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3514` - // Minimum execution time: 14_321_000 picoseconds. - Weight::from_parts(14_747_000, 3514) + // Minimum execution time: 17_492_000 picoseconds. + Weight::from_parts(18_324_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -238,8 +240,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `313` // Estimated: `3514` - // Minimum execution time: 13_525_000 picoseconds. - Weight::from_parts(13_843_000, 3514) + // Minimum execution time: 16_534_000 picoseconds. + Weight::from_parts(17_046_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -253,8 +255,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `16843` // Estimated: `19894` - // Minimum execution time: 34_719_000 picoseconds. - Weight::from_parts(35_162_000, 19894) + // Minimum execution time: 42_264_000 picoseconds. + Weight::from_parts(43_281_000, 19894) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -266,8 +268,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `79` // Estimated: `19894` - // Minimum execution time: 23_477_000 picoseconds. - Weight::from_parts(23_897_000, 19894) + // Minimum execution time: 25_461_000 picoseconds. + Weight::from_parts(26_014_000, 19894) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -281,8 +283,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_772_000 picoseconds. - Weight::from_parts(6_000_000, 0) + // Minimum execution time: 6_652_000 picoseconds. + Weight::from_parts(7_082_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `CoreFellowship::Params` (r:1 w:1) @@ -291,8 +293,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `399` // Estimated: `1853` - // Minimum execution time: 10_050_000 picoseconds. - Weight::from_parts(10_244_000, 1853) + // Minimum execution time: 12_485_000 picoseconds. + Weight::from_parts(12_784_000, 1853) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -314,8 +316,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `17278` // Estimated: `19894` - // Minimum execution time: 54_433_000 picoseconds. - Weight::from_parts(55_650_000, 19894) + // Minimum execution time: 61_243_000 picoseconds. + Weight::from_parts(63_033_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -337,8 +339,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `17388` // Estimated: `19894` - // Minimum execution time: 57_634_000 picoseconds. - Weight::from_parts(58_816_000, 19894) + // Minimum execution time: 65_063_000 picoseconds. + Weight::from_parts(67_047_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -350,8 +352,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3514` - // Minimum execution time: 14_527_000 picoseconds. - Weight::from_parts(14_948_000, 3514) + // Minimum execution time: 21_924_000 picoseconds. + Weight::from_parts(22_691_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -369,8 +371,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3514` - // Minimum execution time: 22_137_000 picoseconds. - Weight::from_parts(22_925_000, 3514) + // Minimum execution time: 24_720_000 picoseconds. + Weight::from_parts(25_580_000, 3514) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -392,8 +394,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `16931` // Estimated: `19894` - // Minimum execution time: 51_837_000 picoseconds. - Weight::from_parts(52_810_000, 19894) + // Minimum execution time: 58_481_000 picoseconds. + Weight::from_parts(59_510_000, 19894) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -414,10 +416,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `16844` // Estimated: `19894 + r * (2489 ±0)` - // Minimum execution time: 45_065_000 picoseconds. - Weight::from_parts(34_090_392, 19894) - // Standard Error: 18_620 - .saturating_add(Weight::from_parts(13_578_046, 0).saturating_mul(r.into())) + // Minimum execution time: 53_570_000 picoseconds. + Weight::from_parts(42_220_685, 19894) + // Standard Error: 18_061 + .saturating_add(Weight::from_parts(13_858_309, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -434,8 +436,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3514` - // Minimum execution time: 14_321_000 picoseconds. - Weight::from_parts(14_747_000, 3514) + // Minimum execution time: 17_492_000 picoseconds. + Weight::from_parts(18_324_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -447,8 +449,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `313` // Estimated: `3514` - // Minimum execution time: 13_525_000 picoseconds. - Weight::from_parts(13_843_000, 3514) + // Minimum execution time: 16_534_000 picoseconds. + Weight::from_parts(17_046_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -462,8 +464,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `16843` // Estimated: `19894` - // Minimum execution time: 34_719_000 picoseconds. - Weight::from_parts(35_162_000, 19894) + // Minimum execution time: 42_264_000 picoseconds. + Weight::from_parts(43_281_000, 19894) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -475,8 +477,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `79` // Estimated: `19894` - // Minimum execution time: 23_477_000 picoseconds. - Weight::from_parts(23_897_000, 19894) + // Minimum execution time: 25_461_000 picoseconds. + Weight::from_parts(26_014_000, 19894) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml index 8d5ccd342b6b..576276dced52 100644 --- a/substrate/frame/delegated-staking/Cargo.toml +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -15,23 +15,23 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-staking = { workspace = true } -sp-io = { workspace = true } -log = { workspace = true } [dev-dependencies] +frame-election-provider-support = { workspace = true } +pallet-balances = { workspace = true, default-features = true } +pallet-nomination-pools = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -substrate-test-utils = { workspace = true } sp-tracing = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } -frame-election-provider-support = { workspace = true } +substrate-test-utils = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 3cfea8bb3129..189d64ccaa74 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -19,20 +19,20 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } +sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-core = { workspace = true } -log = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } -pallet-scheduler = { workspace = true, default-features = true } pallet-preimage = { workspace = true, default-features = true } +pallet-scheduler = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/democracy/src/benchmarking.rs b/substrate/frame/democracy/src/benchmarking.rs index ee36e9212f52..f9c810e56192 100644 --- a/substrate/frame/democracy/src/benchmarking.rs +++ b/substrate/frame/democracy/src/benchmarking.rs @@ -17,9 +17,11 @@ //! Democracy pallet benchmarking. +#![cfg(feature = "runtime-benchmarks")] + use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelist_account, BenchmarkError}; +use frame_benchmarking::v2::*; use frame_support::{ assert_noop, assert_ok, traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, @@ -94,11 +96,15 @@ fn note_preimage() -> T::Hash { hash } -benchmarks! { - propose { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn propose() -> Result<(), BenchmarkError> { let p = T::MaxProposals::get(); - for i in 0 .. (p - 1) { + for i in 0..(p - 1) { add_proposal::(i)?; } @@ -106,18 +112,22 @@ benchmarks! { let proposal = make_proposal::(0); let value = T::MinimumDeposit::get(); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal, value) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), proposal, value); + assert_eq!(PublicProps::::get().len(), p as usize, "Proposals not created."); + Ok(()) } - second { + #[benchmark] + fn second() -> Result<(), BenchmarkError> { let caller = funded_account::("caller", 0); add_proposal::(0)?; // Create s existing "seconds" // we must reserve one deposit for the `proposal` and one for our benchmarked `second` call. - for i in 0 .. T::MaxDeposits::get() - 2 { + for i in 0..T::MaxDeposits::get() - 2 { let seconder = funded_account::("seconder", i); Democracy::::second(RawOrigin::Signed(seconder).into(), 0)?; } @@ -125,20 +135,32 @@ benchmarks! { let deposits = DepositOf::::get(0).ok_or("Proposal not created")?; assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded"); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), 0) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), 0); + let deposits = DepositOf::::get(0).ok_or("Proposal not created")?; - assert_eq!(deposits.0.len(), (T::MaxDeposits::get()) as usize, "`second` benchmark did not work"); + assert_eq!( + deposits.0.len(), + (T::MaxDeposits::get()) as usize, + "`second` benchmark did not work" + ); + Ok(()) } - vote_new { + #[benchmark] + fn vote_new() -> Result<(), BenchmarkError> { let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); // We need to create existing direct votes - for i in 0 .. T::MaxVotes::get() - 1 { + for i in 0..T::MaxVotes::get() - 1 { let ref_index = add_referendum::(i).0; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; + Democracy::::vote( + RawOrigin::Signed(caller.clone()).into(), + ref_index, + account_vote, + )?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -148,23 +170,32 @@ benchmarks! { let ref_index = add_referendum::(T::MaxVotes::get() - 1).0; whitelist_account!(caller); - }: vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote) - verify { + + #[extrinsic_call] + vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote); + let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was not recorded."); + Ok(()) } - vote_existing { + #[benchmark] + fn vote_existing() -> Result<(), BenchmarkError> { let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); // We need to create existing direct votes for i in 0..T::MaxVotes::get() { let ref_index = add_referendum::(i).0; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; + Democracy::::vote( + RawOrigin::Signed(caller.clone()).into(), + ref_index, + account_vote, + )?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -179,43 +210,50 @@ benchmarks! { // This tests when a user changes a vote whitelist_account!(caller); - }: vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote) - verify { + + #[extrinsic_call] + vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote); + let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added"); - let referendum_info = ReferendumInfoOf::::get(ref_index) - .ok_or("referendum doesn't exist")?; - let tally = match referendum_info { + let referendum_info = + ReferendumInfoOf::::get(ref_index).ok_or("referendum doesn't exist")?; + let tally = match referendum_info { ReferendumInfo::Ongoing(r) => r.tally, _ => return Err("referendum not ongoing".into()), }; assert_eq!(tally.nays, 1000u32.into(), "changed vote was not recorded"); + Ok(()) } - emergency_cancel { - let origin = - T::CancellationOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + #[benchmark] + fn emergency_cancel() -> Result<(), BenchmarkError> { + let origin = T::CancellationOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let (ref_index, _, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); - }: _(origin, ref_index) - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, ref_index); // Referendum has been canceled - assert_noop!( - Democracy::::referendum_status(ref_index), - Error::::ReferendumInvalid, + assert_noop!(Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid,); + assert_last_event::( + crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + } + .into(), ); - assert_last_event::(crate::Event::MetadataCleared { - owner: MetadataOwner::Referendum(ref_index), - hash: preimage_hash, - }.into()); + Ok(()) } - blacklist { + #[benchmark] + fn blacklist() -> Result<(), BenchmarkError> { // Place our proposal at the end to make sure it's worst case. - for i in 0 .. T::MaxProposals::get() - 1 { + for i in 0..T::MaxProposals::get() - 1 { add_proposal::(i)?; } // We should really add a lot of seconds here, but we're not doing it elsewhere. @@ -231,21 +269,24 @@ benchmarks! { )); let origin = T::BlacklistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _(origin, hash, Some(ref_index)) - verify { + #[extrinsic_call] + _(origin as T::RuntimeOrigin, hash, Some(ref_index)); + // Referendum has been canceled - assert_noop!( - Democracy::::referendum_status(ref_index), - Error::::ReferendumInvalid + assert_noop!(Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid); + assert_has_event::( + crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + } + .into(), ); - assert_has_event::(crate::Event::MetadataCleared { - owner: MetadataOwner::Referendum(ref_index), - hash: preimage_hash, - }.into()); + Ok(()) } // Worst case scenario, we external propose a previously blacklisted proposal - external_propose { + #[benchmark] + fn external_propose() -> Result<(), BenchmarkError> { let origin = T::ExternalOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); @@ -258,33 +299,42 @@ benchmarks! { .try_into() .unwrap(); Blacklist::::insert(proposal.hash(), (BlockNumberFor::::zero(), addresses)); - }: _(origin, proposal) - verify { + #[extrinsic_call] + _(origin as T::RuntimeOrigin, proposal); + // External proposal created ensure!(NextExternal::::exists(), "External proposal didn't work"); + Ok(()) } - external_propose_majority { + #[benchmark] + fn external_propose_majority() -> Result<(), BenchmarkError> { let origin = T::ExternalMajorityOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); - }: _(origin, proposal) - verify { + #[extrinsic_call] + _(origin as T::RuntimeOrigin, proposal); + // External proposal created ensure!(NextExternal::::exists(), "External proposal didn't work"); + Ok(()) } - external_propose_default { + #[benchmark] + fn external_propose_default() -> Result<(), BenchmarkError> { let origin = T::ExternalDefaultOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); - }: _(origin, proposal) - verify { + #[extrinsic_call] + _(origin as T::RuntimeOrigin, proposal); + // External proposal created ensure!(NextExternal::::exists(), "External proposal didn't work"); + Ok(()) } - fast_track { + #[benchmark] + fn fast_track() -> Result<(), BenchmarkError> { let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); let proposal = make_proposal::(0); @@ -295,23 +345,30 @@ benchmarks! { assert_ok!(Democracy::::set_metadata( origin_propose, MetadataOwner::External, - Some(preimage_hash))); + Some(preimage_hash) + )); // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; - }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) - verify { + #[extrinsic_call] + _(origin_fast_track as T::RuntimeOrigin, proposal_hash, voting_period, delay.into()); + assert_eq!(ReferendumCount::::get(), 1, "referendum not created"); - assert_last_event::(crate::Event::MetadataTransferred { - prev_owner: MetadataOwner::External, - owner: MetadataOwner::Referendum(0), - hash: preimage_hash, - }.into()); + assert_last_event::( + crate::Event::MetadataTransferred { + prev_owner: MetadataOwner::External, + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + } + .into(), + ); + Ok(()) } - veto_external { + #[benchmark] + fn veto_external() -> Result<(), BenchmarkError> { let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); @@ -323,28 +380,32 @@ benchmarks! { assert_ok!(Democracy::::set_metadata( origin_propose, MetadataOwner::External, - Some(preimage_hash)) - ); + Some(preimage_hash) + )); let mut vetoers: BoundedVec = Default::default(); - for i in 0 .. (T::MaxBlacklisted::get() - 1) { + for i in 0..(T::MaxBlacklisted::get() - 1) { vetoers.try_push(account::("vetoer", i, SEED)).unwrap(); } vetoers.sort(); Blacklist::::insert(proposal_hash, (BlockNumberFor::::zero(), vetoers)); - let origin = T::VetoOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let origin = + T::VetoOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; ensure!(NextExternal::::get().is_some(), "no external proposal"); - }: _(origin, proposal_hash) - verify { + #[extrinsic_call] + _(origin as T::RuntimeOrigin, proposal_hash); + assert!(NextExternal::::get().is_none()); let (_, new_vetoers) = Blacklist::::get(&proposal_hash).ok_or("no blacklist")?; assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added"); + Ok(()) } - cancel_proposal { + #[benchmark] + fn cancel_proposal() -> Result<(), BenchmarkError> { // Place our proposal at the end to make sure it's worst case. - for i in 0 .. T::MaxProposals::get() { + for i in 0..T::MaxProposals::get() { add_proposal::(i)?; } // Add metadata to the first proposal. @@ -353,31 +414,41 @@ benchmarks! { assert_ok!(Democracy::::set_metadata( RawOrigin::Signed(proposer).into(), MetadataOwner::Proposal(0), - Some(preimage_hash))); + Some(preimage_hash) + )); let cancel_origin = T::CancelProposalOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; - }: _(cancel_origin, 0) - verify { - assert_last_event::(crate::Event::MetadataCleared { - owner: MetadataOwner::Proposal(0), - hash: preimage_hash, - }.into()); + #[extrinsic_call] + _(cancel_origin as T::RuntimeOrigin, 0); + + assert_last_event::( + crate::Event::MetadataCleared { + owner: MetadataOwner::Proposal(0), + hash: preimage_hash, + } + .into(), + ); + Ok(()) } - cancel_referendum { + #[benchmark] + fn cancel_referendum() -> Result<(), BenchmarkError> { let (ref_index, _, preimage_hash) = add_referendum::(0); - }: _(RawOrigin::Root, ref_index) - verify { - assert_last_event::(crate::Event::MetadataCleared { - owner: MetadataOwner::Referendum(0), - hash: preimage_hash, - }.into()); - } + #[extrinsic_call] + _(RawOrigin::Root, ref_index); - #[extra] - on_initialize_external { - let r in 0 .. REFERENDUM_COUNT_HINT; + assert_last_event::( + crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + } + .into(), + ); + Ok(()) + } + #[benchmark(extra)] + fn on_initialize_external(r: Linear<0, REFERENDUM_COUNT_HINT>) -> Result<(), BenchmarkError> { for i in 0..r { add_referendum::(i); } @@ -397,14 +468,17 @@ benchmarks! { let block_number = T::LaunchPeriod::get(); - }: { Democracy::::on_initialize(block_number) } - verify { + #[block] + { + Democracy::::on_initialize(block_number); + } + // One extra because of next external assert_eq!(ReferendumCount::::get(), r + 1, "referenda not created"); ensure!(!NextExternal::::exists(), "External wasn't taken"); // All but the new next external should be finished - for i in 0 .. r { + for i in 0..r { if let Some(value) = ReferendumInfoOf::::get(i) { match value { ReferendumInfo::Finished { .. } => (), @@ -412,12 +486,13 @@ benchmarks! { } } } + Ok(()) } - #[extra] - on_initialize_public { - let r in 0 .. (T::MaxVotes::get() - 1); - + #[benchmark(extra)] + fn on_initialize_public( + r: Linear<0, { T::MaxVotes::get() - 1 }>, + ) -> Result<(), BenchmarkError> { for i in 0..r { add_referendum::(i); } @@ -430,13 +505,16 @@ benchmarks! { let block_number = T::LaunchPeriod::get(); - }: { Democracy::::on_initialize(block_number) } - verify { + #[block] + { + Democracy::::on_initialize(block_number); + } + // One extra because of next public assert_eq!(ReferendumCount::::get(), r + 1, "proposal not accepted"); // All should be finished - for i in 0 .. r { + for i in 0..r { if let Some(value) = ReferendumInfoOf::::get(i) { match value { ReferendumInfo::Finished { .. } => (), @@ -444,12 +522,12 @@ benchmarks! { } } } + Ok(()) } // No launch no maturing referenda. - on_initialize_base { - let r in 0 .. (T::MaxVotes::get() - 1); - + #[benchmark] + fn on_initialize_base(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> { for i in 0..r { add_referendum::(i); } @@ -464,22 +542,28 @@ benchmarks! { assert_eq!(ReferendumCount::::get(), r, "referenda not created"); assert_eq!(LowestUnbaked::::get(), 0, "invalid referenda init"); - }: { Democracy::::on_initialize(1u32.into()) } - verify { + #[block] + { + Democracy::::on_initialize(1u32.into()); + } + // All should be on going - for i in 0 .. r { + for i in 0..r { if let Some(value) = ReferendumInfoOf::::get(i) { match value { - ReferendumInfo::Finished { .. } => return Err("Referendum has been finished".into()), + ReferendumInfo::Finished { .. } => + return Err("Referendum has been finished".into()), ReferendumInfo::Ongoing(_) => (), } } } + Ok(()) } - on_initialize_base_with_launch_period { - let r in 0 .. (T::MaxVotes::get() - 1); - + #[benchmark] + fn on_initialize_base_with_launch_period( + r: Linear<0, { T::MaxVotes::get() - 1 }>, + ) -> Result<(), BenchmarkError> { for i in 0..r { add_referendum::(i); } @@ -496,22 +580,26 @@ benchmarks! { let block_number = T::LaunchPeriod::get(); - }: { Democracy::::on_initialize(block_number) } - verify { + #[block] + { + Democracy::::on_initialize(block_number); + } + // All should be on going - for i in 0 .. r { + for i in 0..r { if let Some(value) = ReferendumInfoOf::::get(i) { match value { - ReferendumInfo::Finished { .. } => return Err("Referendum has been finished".into()), + ReferendumInfo::Finished { .. } => + return Err("Referendum has been finished".into()), ReferendumInfo::Ongoing(_) => (), } } } + Ok(()) } - delegate { - let r in 0 .. (T::MaxVotes::get() - 1); - + #[benchmark] + fn delegate(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> { let initial_balance: BalanceOf = 100u32.into(); let delegated_balance: BalanceOf = 1000u32.into(); @@ -538,7 +626,11 @@ benchmarks! { // We need to create existing direct votes for the `new_delegate` for i in 0..r { let ref_index = add_referendum::(i).0; - Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_index, account_vote)?; + Democracy::::vote( + RawOrigin::Signed(new_delegate.clone()).into(), + ref_index, + account_vote, + )?; } let votes = match VotingOf::::get(&new_delegate) { Voting::Direct { votes, .. } => votes, @@ -546,8 +638,15 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes were not recorded."); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), new_delegate_lookup, Conviction::Locked1x, delegated_balance) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + new_delegate_lookup, + Conviction::Locked1x, + delegated_balance, + ); + let (target, balance) = match VotingOf::::get(&caller) { Voting::Delegating { target, balance, .. } => (target, balance), _ => return Err("Votes are not direct".into()), @@ -559,11 +658,11 @@ benchmarks! { _ => return Err("Votes are not direct".into()), }; assert_eq!(delegations.capital, delegated_balance, "delegation was not recorded."); + Ok(()) } - undelegate { - let r in 0 .. (T::MaxVotes::get() - 1); - + #[benchmark] + fn undelegate(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> { let initial_balance: BalanceOf = 100u32.into(); let delegated_balance: BalanceOf = 1000u32.into(); @@ -590,7 +689,7 @@ benchmarks! { Democracy::::vote( RawOrigin::Signed(the_delegate.clone()).into(), ref_index, - account_vote + account_vote, )?; } let votes = match VotingOf::::get(&the_delegate) { @@ -599,31 +698,38 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes were not recorded."); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + // Voting should now be direct match VotingOf::::get(&caller) { Voting::Direct { .. } => (), _ => return Err("undelegation failed".into()), } + Ok(()) } - clear_public_proposals { + #[benchmark] + fn clear_public_proposals() -> Result<(), BenchmarkError> { add_proposal::(0)?; - }: _(RawOrigin::Root) + #[extrinsic_call] + _(RawOrigin::Root); - // Test when unlock will remove locks - unlock_remove { - let r in 0 .. (T::MaxVotes::get() - 1); + Ok(()) + } + // Test when unlock will remove locks + #[benchmark] + fn unlock_remove(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> { let locker = funded_account::("locker", 0); let locker_lookup = T::Lookup::unlookup(locker.clone()); // Populate votes so things are locked let base_balance: BalanceOf = 100u32.into(); let small_vote = account_vote::(base_balance); // Vote and immediately unvote - for i in 0 .. r { + for i in 0..r { let ref_index = add_referendum::(i).0; Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?; Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?; @@ -631,23 +737,25 @@ benchmarks! { let caller = funded_account::("caller", 0); whitelist_account!(caller); - }: unlock(RawOrigin::Signed(caller), locker_lookup) - verify { + + #[extrinsic_call] + unlock(RawOrigin::Signed(caller), locker_lookup); + // Note that we may want to add a `get_lock` api to actually verify let voting = VotingOf::::get(&locker); assert_eq!(voting.locked_balance(), BalanceOf::::zero()); + Ok(()) } // Test when unlock will set a new value - unlock_set { - let r in 0 .. (T::MaxVotes::get() - 1); - + #[benchmark] + fn unlock_set(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> { let locker = funded_account::("locker", 0); let locker_lookup = T::Lookup::unlookup(locker.clone()); // Populate votes so things are locked let base_balance: BalanceOf = 100u32.into(); let small_vote = account_vote::(base_balance); - for i in 0 .. r { + for i in 0..r { let ref_index = add_referendum::(i).0; Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?; } @@ -670,8 +778,10 @@ benchmarks! { let caller = funded_account::("caller", 0); whitelist_account!(caller); - }: unlock(RawOrigin::Signed(caller), locker_lookup) - verify { + + #[extrinsic_call] + unlock(RawOrigin::Signed(caller), locker_lookup); + let votes = match VotingOf::::get(&locker) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), @@ -681,17 +791,21 @@ benchmarks! { let voting = VotingOf::::get(&locker); // Note that we may want to add a `get_lock` api to actually verify assert_eq!(voting.locked_balance(), if r > 0 { base_balance } else { 0u32.into() }); + Ok(()) } - remove_vote { - let r in 1 .. T::MaxVotes::get(); - + #[benchmark] + fn remove_vote(r: Linear<1, { T::MaxVotes::get() }>) -> Result<(), BenchmarkError> { let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); - for i in 0 .. r { + for i in 0..r { let ref_index = add_referendum::(i).0; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; + Democracy::::vote( + RawOrigin::Signed(caller.clone()).into(), + ref_index, + account_vote, + )?; } let votes = match VotingOf::::get(&caller) { @@ -702,26 +816,32 @@ benchmarks! { let ref_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), ref_index) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), ref_index); + let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); + Ok(()) } // Worst case is when target == caller and referendum is ongoing - remove_other_vote { - let r in 1 .. T::MaxVotes::get(); - + #[benchmark] + fn remove_other_vote(r: Linear<1, { T::MaxVotes::get() }>) -> Result<(), BenchmarkError> { let caller = funded_account::("caller", r); let caller_lookup = T::Lookup::unlookup(caller.clone()); let account_vote = account_vote::(100u32.into()); - for i in 0 .. r { + for i in 0..r { let ref_index = add_referendum::(i).0; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; + Democracy::::vote( + RawOrigin::Signed(caller.clone()).into(), + ref_index, + account_vote, + )?; } let votes = match VotingOf::::get(&caller) { @@ -732,68 +852,71 @@ benchmarks! { let ref_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index); + let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); + Ok(()) } - set_external_metadata { + #[benchmark] + fn set_external_metadata() -> Result<(), BenchmarkError> { let origin = T::ExternalOrigin::try_successful_origin() .expect("ExternalOrigin has no successful origin required for the benchmark"); - assert_ok!( - Democracy::::external_propose(origin.clone(), make_proposal::(0)) - ); + assert_ok!(Democracy::::external_propose(origin.clone(), make_proposal::(0))); let owner = MetadataOwner::External; let hash = note_preimage::(); - }: set_metadata(origin, owner.clone(), Some(hash)) - verify { - assert_last_event::(crate::Event::MetadataSet { - owner, - hash, - }.into()); + + #[extrinsic_call] + set_metadata(origin as T::RuntimeOrigin, owner.clone(), Some(hash)); + + assert_last_event::(crate::Event::MetadataSet { owner, hash }.into()); + Ok(()) } - clear_external_metadata { + #[benchmark] + fn clear_external_metadata() -> Result<(), BenchmarkError> { let origin = T::ExternalOrigin::try_successful_origin() .expect("ExternalOrigin has no successful origin required for the benchmark"); - assert_ok!( - Democracy::::external_propose(origin.clone(), make_proposal::(0)) - ); + assert_ok!(Democracy::::external_propose(origin.clone(), make_proposal::(0))); let owner = MetadataOwner::External; - let proposer = funded_account::("proposer", 0); + let _proposer = funded_account::("proposer", 0); let hash = note_preimage::(); assert_ok!(Democracy::::set_metadata(origin.clone(), owner.clone(), Some(hash))); - }: set_metadata(origin, owner.clone(), None) - verify { - assert_last_event::(crate::Event::MetadataCleared { - owner, - hash, - }.into()); + + #[extrinsic_call] + set_metadata(origin as T::RuntimeOrigin, owner.clone(), None); + + assert_last_event::(crate::Event::MetadataCleared { owner, hash }.into()); + Ok(()) } - set_proposal_metadata { + #[benchmark] + fn set_proposal_metadata() -> Result<(), BenchmarkError> { // Place our proposal at the end to make sure it's worst case. - for i in 0 .. T::MaxProposals::get() { + for i in 0..T::MaxProposals::get() { add_proposal::(i)?; } let owner = MetadataOwner::Proposal(0); let proposer = funded_account::("proposer", 0); let hash = note_preimage::(); - }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), Some(hash)) - verify { - assert_last_event::(crate::Event::MetadataSet { - owner, - hash, - }.into()); + + #[extrinsic_call] + set_metadata(RawOrigin::Signed(proposer), owner.clone(), Some(hash)); + + assert_last_event::(crate::Event::MetadataSet { owner, hash }.into()); + Ok(()) } - clear_proposal_metadata { + #[benchmark] + fn clear_proposal_metadata() -> Result<(), BenchmarkError> { // Place our proposal at the end to make sure it's worst case. - for i in 0 .. T::MaxProposals::get() { + for i in 0..T::MaxProposals::get() { add_proposal::(i)?; } let proposer = funded_account::("proposer", 0); @@ -802,33 +925,36 @@ benchmarks! { assert_ok!(Democracy::::set_metadata( RawOrigin::Signed(proposer.clone()).into(), owner.clone(), - Some(hash))); - }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), None) - verify { - assert_last_event::(crate::Event::MetadataCleared { - owner, - hash, - }.into()); + Some(hash) + )); + + #[extrinsic_call] + set_metadata::(RawOrigin::Signed(proposer), owner.clone(), None); + + assert_last_event::(crate::Event::MetadataCleared { owner, hash }.into()); + Ok(()) } - set_referendum_metadata { + #[benchmark] + fn set_referendum_metadata() -> Result<(), BenchmarkError> { // create not ongoing referendum. ReferendumInfoOf::::insert( 0, ReferendumInfo::Finished { end: BlockNumberFor::::zero(), approved: true }, ); let owner = MetadataOwner::Referendum(0); - let caller = funded_account::("caller", 0); + let _caller = funded_account::("caller", 0); let hash = note_preimage::(); - }: set_metadata(RawOrigin::Root.into(), owner.clone(), Some(hash)) - verify { - assert_last_event::(crate::Event::MetadataSet { - owner, - hash, - }.into()); + + #[extrinsic_call] + set_metadata::(RawOrigin::Root, owner.clone(), Some(hash)); + + assert_last_event::(crate::Event::MetadataSet { owner, hash }.into()); + Ok(()) } - clear_referendum_metadata { + #[benchmark] + fn clear_referendum_metadata() -> Result<(), BenchmarkError> { // create not ongoing referendum. ReferendumInfoOf::::insert( 0, @@ -838,17 +964,13 @@ benchmarks! { let hash = note_preimage::(); MetadataOf::::insert(owner.clone(), hash); let caller = funded_account::("caller", 0); - }: set_metadata(RawOrigin::Signed(caller).into(), owner.clone(), None) - verify { - assert_last_event::(crate::Event::MetadataCleared { - owner, - hash, - }.into()); + + #[extrinsic_call] + set_metadata::(RawOrigin::Signed(caller), owner.clone(), None); + + assert_last_event::(crate::Event::MetadataCleared { owner, hash }.into()); + Ok(()) } - impl_benchmark_test_suite!( - Democracy, - crate::tests::new_test_ext(), - crate::tests::Test - ); + impl_benchmark_test_suite!(Democracy, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/substrate/frame/democracy/src/weights.rs b/substrate/frame/democracy/src/weights.rs index 6eb82c631a2a..765ee57f0eb3 100644 --- a/substrate/frame/democracy/src/weights.rs +++ b/substrate/frame/democracy/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_democracy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_democracy -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/democracy/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_democracy +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/democracy/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -96,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4834` // Estimated: `18187` - // Minimum execution time: 42_266_000 picoseconds. - Weight::from_parts(43_382_000, 18187) + // Minimum execution time: 49_681_000 picoseconds. + Weight::from_parts(51_578_000, 18187) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -107,8 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3589` // Estimated: `6695` - // Minimum execution time: 37_765_000 picoseconds. - Weight::from_parts(38_679_000, 6695) + // Minimum execution time: 45_001_000 picoseconds. + Weight::from_parts(45_990_000, 6695) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -124,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3503` // Estimated: `7260` - // Minimum execution time: 56_200_000 picoseconds. - Weight::from_parts(57_320_000, 7260) + // Minimum execution time: 65_095_000 picoseconds. + Weight::from_parts(67_484_000, 7260) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -141,8 +139,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3525` // Estimated: `7260` - // Minimum execution time: 58_633_000 picoseconds. - Weight::from_parts(60_809_000, 7260) + // Minimum execution time: 66_877_000 picoseconds. + Weight::from_parts(68_910_000, 7260) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -156,8 +154,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `399` // Estimated: `3666` - // Minimum execution time: 23_908_000 picoseconds. - Weight::from_parts(24_659_000, 3666) + // Minimum execution time: 29_312_000 picoseconds. + Weight::from_parts(30_040_000, 3666) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -179,8 +177,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5943` // Estimated: `18187` - // Minimum execution time: 100_268_000 picoseconds. - Weight::from_parts(101_309_000, 18187) + // Minimum execution time: 107_932_000 picoseconds. + Weight::from_parts(108_940_000, 18187) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -192,8 +190,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3449` // Estimated: `6703` - // Minimum execution time: 12_143_000 picoseconds. - Weight::from_parts(12_843_000, 6703) + // Minimum execution time: 17_703_000 picoseconds. + Weight::from_parts(18_188_000, 6703) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -203,8 +201,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_792_000 picoseconds. - Weight::from_parts(2_922_000, 0) + // Minimum execution time: 2_672_000 picoseconds. + Weight::from_parts(2_814_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Democracy::NextExternal` (r:0 w:1) @@ -213,8 +211,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_792_000 picoseconds. - Weight::from_parts(2_953_000, 0) + // Minimum execution time: 2_584_000 picoseconds. + Weight::from_parts(2_846_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Democracy::NextExternal` (r:1 w:1) @@ -229,8 +227,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `319` // Estimated: `3518` - // Minimum execution time: 23_948_000 picoseconds. - Weight::from_parts(24_773_000, 3518) + // Minimum execution time: 24_603_000 picoseconds. + Weight::from_parts(25_407_000, 3518) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -244,8 +242,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3552` // Estimated: `6703` - // Minimum execution time: 27_233_000 picoseconds. - Weight::from_parts(28_327_000, 6703) + // Minimum execution time: 31_721_000 picoseconds. + Weight::from_parts(32_785_000, 6703) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -261,8 +259,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5854` // Estimated: `18187` - // Minimum execution time: 82_141_000 picoseconds. - Weight::from_parts(83_511_000, 18187) + // Minimum execution time: 86_981_000 picoseconds. + Weight::from_parts(89_140_000, 18187) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -274,8 +272,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `304` // Estimated: `3518` - // Minimum execution time: 16_650_000 picoseconds. - Weight::from_parts(17_140_000, 3518) + // Minimum execution time: 17_465_000 picoseconds. + Weight::from_parts(18_018_000, 3518) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -290,10 +288,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `277 + r * (86 ±0)` // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 5_308_000 picoseconds. - Weight::from_parts(6_320_667, 1489) - // Standard Error: 6_714 - .saturating_add(Weight::from_parts(3_307_440, 0).saturating_mul(r.into())) + // Minimum execution time: 6_746_000 picoseconds. + Weight::from_parts(7_381_932, 1489) + // Standard Error: 10_311 + .saturating_add(Weight::from_parts(4_107_935, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -316,10 +314,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `277 + r * (86 ±0)` // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 8_287_000 picoseconds. - Weight::from_parts(7_834_729, 18187) - // Standard Error: 7_499 - .saturating_add(Weight::from_parts(3_333_021, 0).saturating_mul(r.into())) + // Minimum execution time: 9_766_000 picoseconds. + Weight::from_parts(9_788_895, 18187) + // Standard Error: 11_913 + .saturating_add(Weight::from_parts(4_130_441, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -338,10 +336,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `863 + r * (108 ±0)` // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 40_681_000 picoseconds. - Weight::from_parts(46_603_677, 19800) - // Standard Error: 7_453 - .saturating_add(Weight::from_parts(4_269_926, 0).saturating_mul(r.into())) + // Minimum execution time: 48_992_000 picoseconds. + Weight::from_parts(55_524_560, 19800) + // Standard Error: 11_278 + .saturating_add(Weight::from_parts(4_987_109, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -357,10 +355,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `526 + r * (108 ±0)` // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 18_176_000 picoseconds. - Weight::from_parts(19_473_041, 13530) - // Standard Error: 6_046 - .saturating_add(Weight::from_parts(4_259_914, 0).saturating_mul(r.into())) + // Minimum execution time: 23_828_000 picoseconds. + Weight::from_parts(23_638_577, 13530) + // Standard Error: 10_946 + .saturating_add(Weight::from_parts(4_971_245, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -373,8 +371,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_828_000 picoseconds. - Weight::from_parts(2_979_000, 0) + // Minimum execution time: 2_759_000 picoseconds. + Weight::from_parts(2_850_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Democracy::VotingOf` (r:1 w:1) @@ -390,10 +388,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `596` // Estimated: `7260` - // Minimum execution time: 24_256_000 picoseconds. - Weight::from_parts(35_489_844, 7260) - // Standard Error: 2_809 - .saturating_add(Weight::from_parts(82_542, 0).saturating_mul(r.into())) + // Minimum execution time: 30_804_000 picoseconds. + Weight::from_parts(42_750_018, 7260) + // Standard Error: 3_300 + .saturating_add(Weight::from_parts(99_997, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -410,10 +408,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `597 + r * (22 ±0)` // Estimated: `7260` - // Minimum execution time: 32_306_000 picoseconds. - Weight::from_parts(35_288_926, 7260) - // Standard Error: 1_742 - .saturating_add(Weight::from_parts(118_566, 0).saturating_mul(r.into())) + // Minimum execution time: 39_946_000 picoseconds. + Weight::from_parts(44_500_306, 7260) + // Standard Error: 1_914 + .saturating_add(Weight::from_parts(116_987, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -426,10 +424,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_269_000 picoseconds. - Weight::from_parts(18_595_547, 7260) - // Standard Error: 1_952 - .saturating_add(Weight::from_parts(122_967, 0).saturating_mul(r.into())) + // Minimum execution time: 21_677_000 picoseconds. + Weight::from_parts(25_329_290, 7260) + // Standard Error: 1_998 + .saturating_add(Weight::from_parts(157_800, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -442,10 +440,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_213_000 picoseconds. - Weight::from_parts(18_870_570, 7260) - // Standard Error: 1_802 - .saturating_add(Weight::from_parts(124_205, 0).saturating_mul(r.into())) + // Minimum execution time: 21_777_000 picoseconds. + Weight::from_parts(26_635_600, 7260) + // Standard Error: 2_697 + .saturating_add(Weight::from_parts(135_641, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -459,10 +457,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn set_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `456` + // Measured: `351` // Estimated: `3556` - // Minimum execution time: 17_827_000 picoseconds. - Weight::from_parts(18_255_000, 3556) + // Minimum execution time: 19_914_000 picoseconds. + Weight::from_parts(20_450_000, 3556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -474,8 +472,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `319` // Estimated: `3518` - // Minimum execution time: 14_205_000 picoseconds. - Weight::from_parts(14_631_000, 3518) + // Minimum execution time: 16_212_000 picoseconds. + Weight::from_parts(16_745_000, 3518) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -489,10 +487,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4988` + // Measured: `4883` // Estimated: `18187` - // Minimum execution time: 40_868_000 picoseconds. - Weight::from_parts(41_688_000, 18187) + // Minimum execution time: 47_225_000 picoseconds. + Weight::from_parts(47_976_000, 18187) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -504,8 +502,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4855` // Estimated: `18187` - // Minimum execution time: 36_573_000 picoseconds. - Weight::from_parts(37_017_000, 18187) + // Minimum execution time: 43_140_000 picoseconds. + Weight::from_parts(43_924_000, 18187) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -517,10 +515,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn set_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 13_741_000 picoseconds. - Weight::from_parts(14_337_000, 3556) + // Minimum execution time: 14_614_000 picoseconds. + Weight::from_parts(15_376_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -532,8 +530,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3666` - // Minimum execution time: 16_358_000 picoseconds. - Weight::from_parts(17_157_000, 3666) + // Minimum execution time: 22_588_000 picoseconds. + Weight::from_parts(23_267_000, 3666) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -553,8 +551,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4834` // Estimated: `18187` - // Minimum execution time: 42_266_000 picoseconds. - Weight::from_parts(43_382_000, 18187) + // Minimum execution time: 49_681_000 picoseconds. + Weight::from_parts(51_578_000, 18187) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -564,8 +562,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3589` // Estimated: `6695` - // Minimum execution time: 37_765_000 picoseconds. - Weight::from_parts(38_679_000, 6695) + // Minimum execution time: 45_001_000 picoseconds. + Weight::from_parts(45_990_000, 6695) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -581,8 +579,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3503` // Estimated: `7260` - // Minimum execution time: 56_200_000 picoseconds. - Weight::from_parts(57_320_000, 7260) + // Minimum execution time: 65_095_000 picoseconds. + Weight::from_parts(67_484_000, 7260) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -598,8 +596,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3525` // Estimated: `7260` - // Minimum execution time: 58_633_000 picoseconds. - Weight::from_parts(60_809_000, 7260) + // Minimum execution time: 66_877_000 picoseconds. + Weight::from_parts(68_910_000, 7260) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -613,8 +611,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `399` // Estimated: `3666` - // Minimum execution time: 23_908_000 picoseconds. - Weight::from_parts(24_659_000, 3666) + // Minimum execution time: 29_312_000 picoseconds. + Weight::from_parts(30_040_000, 3666) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -636,8 +634,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5943` // Estimated: `18187` - // Minimum execution time: 100_268_000 picoseconds. - Weight::from_parts(101_309_000, 18187) + // Minimum execution time: 107_932_000 picoseconds. + Weight::from_parts(108_940_000, 18187) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -649,8 +647,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3449` // Estimated: `6703` - // Minimum execution time: 12_143_000 picoseconds. - Weight::from_parts(12_843_000, 6703) + // Minimum execution time: 17_703_000 picoseconds. + Weight::from_parts(18_188_000, 6703) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -660,8 +658,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_792_000 picoseconds. - Weight::from_parts(2_922_000, 0) + // Minimum execution time: 2_672_000 picoseconds. + Weight::from_parts(2_814_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Democracy::NextExternal` (r:0 w:1) @@ -670,8 +668,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_792_000 picoseconds. - Weight::from_parts(2_953_000, 0) + // Minimum execution time: 2_584_000 picoseconds. + Weight::from_parts(2_846_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Democracy::NextExternal` (r:1 w:1) @@ -686,8 +684,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `319` // Estimated: `3518` - // Minimum execution time: 23_948_000 picoseconds. - Weight::from_parts(24_773_000, 3518) + // Minimum execution time: 24_603_000 picoseconds. + Weight::from_parts(25_407_000, 3518) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -701,8 +699,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3552` // Estimated: `6703` - // Minimum execution time: 27_233_000 picoseconds. - Weight::from_parts(28_327_000, 6703) + // Minimum execution time: 31_721_000 picoseconds. + Weight::from_parts(32_785_000, 6703) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -718,8 +716,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5854` // Estimated: `18187` - // Minimum execution time: 82_141_000 picoseconds. - Weight::from_parts(83_511_000, 18187) + // Minimum execution time: 86_981_000 picoseconds. + Weight::from_parts(89_140_000, 18187) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -731,8 +729,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `304` // Estimated: `3518` - // Minimum execution time: 16_650_000 picoseconds. - Weight::from_parts(17_140_000, 3518) + // Minimum execution time: 17_465_000 picoseconds. + Weight::from_parts(18_018_000, 3518) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -747,10 +745,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `277 + r * (86 ±0)` // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 5_308_000 picoseconds. - Weight::from_parts(6_320_667, 1489) - // Standard Error: 6_714 - .saturating_add(Weight::from_parts(3_307_440, 0).saturating_mul(r.into())) + // Minimum execution time: 6_746_000 picoseconds. + Weight::from_parts(7_381_932, 1489) + // Standard Error: 10_311 + .saturating_add(Weight::from_parts(4_107_935, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -773,10 +771,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `277 + r * (86 ±0)` // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 8_287_000 picoseconds. - Weight::from_parts(7_834_729, 18187) - // Standard Error: 7_499 - .saturating_add(Weight::from_parts(3_333_021, 0).saturating_mul(r.into())) + // Minimum execution time: 9_766_000 picoseconds. + Weight::from_parts(9_788_895, 18187) + // Standard Error: 11_913 + .saturating_add(Weight::from_parts(4_130_441, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -795,10 +793,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `863 + r * (108 ±0)` // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 40_681_000 picoseconds. - Weight::from_parts(46_603_677, 19800) - // Standard Error: 7_453 - .saturating_add(Weight::from_parts(4_269_926, 0).saturating_mul(r.into())) + // Minimum execution time: 48_992_000 picoseconds. + Weight::from_parts(55_524_560, 19800) + // Standard Error: 11_278 + .saturating_add(Weight::from_parts(4_987_109, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -814,10 +812,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `526 + r * (108 ±0)` // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 18_176_000 picoseconds. - Weight::from_parts(19_473_041, 13530) - // Standard Error: 6_046 - .saturating_add(Weight::from_parts(4_259_914, 0).saturating_mul(r.into())) + // Minimum execution time: 23_828_000 picoseconds. + Weight::from_parts(23_638_577, 13530) + // Standard Error: 10_946 + .saturating_add(Weight::from_parts(4_971_245, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -830,8 +828,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_828_000 picoseconds. - Weight::from_parts(2_979_000, 0) + // Minimum execution time: 2_759_000 picoseconds. + Weight::from_parts(2_850_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Democracy::VotingOf` (r:1 w:1) @@ -847,10 +845,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `596` // Estimated: `7260` - // Minimum execution time: 24_256_000 picoseconds. - Weight::from_parts(35_489_844, 7260) - // Standard Error: 2_809 - .saturating_add(Weight::from_parts(82_542, 0).saturating_mul(r.into())) + // Minimum execution time: 30_804_000 picoseconds. + Weight::from_parts(42_750_018, 7260) + // Standard Error: 3_300 + .saturating_add(Weight::from_parts(99_997, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -867,10 +865,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `597 + r * (22 ±0)` // Estimated: `7260` - // Minimum execution time: 32_306_000 picoseconds. - Weight::from_parts(35_288_926, 7260) - // Standard Error: 1_742 - .saturating_add(Weight::from_parts(118_566, 0).saturating_mul(r.into())) + // Minimum execution time: 39_946_000 picoseconds. + Weight::from_parts(44_500_306, 7260) + // Standard Error: 1_914 + .saturating_add(Weight::from_parts(116_987, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -883,10 +881,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_269_000 picoseconds. - Weight::from_parts(18_595_547, 7260) - // Standard Error: 1_952 - .saturating_add(Weight::from_parts(122_967, 0).saturating_mul(r.into())) + // Minimum execution time: 21_677_000 picoseconds. + Weight::from_parts(25_329_290, 7260) + // Standard Error: 1_998 + .saturating_add(Weight::from_parts(157_800, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -899,10 +897,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `761 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_213_000 picoseconds. - Weight::from_parts(18_870_570, 7260) - // Standard Error: 1_802 - .saturating_add(Weight::from_parts(124_205, 0).saturating_mul(r.into())) + // Minimum execution time: 21_777_000 picoseconds. + Weight::from_parts(26_635_600, 7260) + // Standard Error: 2_697 + .saturating_add(Weight::from_parts(135_641, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -916,10 +914,10 @@ impl WeightInfo for () { /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn set_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `456` + // Measured: `351` // Estimated: `3556` - // Minimum execution time: 17_827_000 picoseconds. - Weight::from_parts(18_255_000, 3556) + // Minimum execution time: 19_914_000 picoseconds. + Weight::from_parts(20_450_000, 3556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -931,8 +929,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `319` // Estimated: `3518` - // Minimum execution time: 14_205_000 picoseconds. - Weight::from_parts(14_631_000, 3518) + // Minimum execution time: 16_212_000 picoseconds. + Weight::from_parts(16_745_000, 3518) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -946,10 +944,10 @@ impl WeightInfo for () { /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4988` + // Measured: `4883` // Estimated: `18187` - // Minimum execution time: 40_868_000 picoseconds. - Weight::from_parts(41_688_000, 18187) + // Minimum execution time: 47_225_000 picoseconds. + Weight::from_parts(47_976_000, 18187) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -961,8 +959,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4855` // Estimated: `18187` - // Minimum execution time: 36_573_000 picoseconds. - Weight::from_parts(37_017_000, 18187) + // Minimum execution time: 43_140_000 picoseconds. + Weight::from_parts(43_924_000, 18187) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -974,10 +972,10 @@ impl WeightInfo for () { /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn set_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 13_741_000 picoseconds. - Weight::from_parts(14_337_000, 3556) + // Minimum execution time: 14_614_000 picoseconds. + Weight::from_parts(15_376_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -989,8 +987,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3666` - // Minimum execution time: 16_358_000 picoseconds. - Weight::from_parts(17_157_000, 3666) + // Minimum execution time: 22_588_000 picoseconds. + Weight::from_parts(23_267_000, 3666) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index ff2a997fafe0..9a4a2a839346 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -18,20 +18,20 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } +log = { workspace = true } scale-info = { features = [ "derive", ], workspace = true } -log = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-io = { workspace = true } +frame-election-provider-support = { workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } -sp-runtime = { workspace = true } +sp-io = { workspace = true } sp-npos-elections = { workspace = true } -sp-arithmetic = { workspace = true } -frame-election-provider-support = { workspace = true } +sp-runtime = { workspace = true } # Optional imports for benchmarking frame-benchmarking = { optional = true, workspace = true } @@ -40,14 +40,14 @@ rand = { features = ["alloc", "small_rng"], optional = true, workspace = true } strum = { features = ["derive"], optional = true, workspace = true } [dev-dependencies] +frame-benchmarking = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } sp-core = { workspace = true } sp-io = { workspace = true, default-features = true } sp-npos-elections = { workspace = true } sp-tracing = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -frame-benchmarking = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/election-provider-multi-phase/src/weights.rs b/substrate/frame/election-provider-multi-phase/src/weights.rs index 1398ed047784..2569e46e351e 100644 --- a/substrate/frame/election-provider-multi-phase/src/weights.rs +++ b/substrate/frame/election-provider-multi-phase/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_election_provider_multi_phase` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -84,10 +84,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `1061` + // Measured: `1094` // Estimated: `3481` - // Minimum execution time: 19_436_000 picoseconds. - Weight::from_parts(20_138_000, 3481) + // Minimum execution time: 27_022_000 picoseconds. + Weight::from_parts(27_654_000, 3481) .saturating_add(T::DbWeight::get().reads(8_u64)) } /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) @@ -98,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 8_356_000 picoseconds. - Weight::from_parts(8_708_000, 1633) + // Minimum execution time: 9_613_000 picoseconds. + Weight::from_parts(9_845_000, 1633) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -111,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 9_088_000 picoseconds. - Weight::from_parts(9_382_000, 1633) + // Minimum execution time: 10_404_000 picoseconds. + Weight::from_parts(10_847_000, 1633) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -124,8 +124,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 25_899_000 picoseconds. - Weight::from_parts(26_456_000, 3593) + // Minimum execution time: 26_673_000 picoseconds. + Weight::from_parts(27_349_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -135,8 +135,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_671_000 picoseconds. - Weight::from_parts(18_131_000, 3593) + // Minimum execution time: 19_544_000 picoseconds. + Weight::from_parts(19_818_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -152,10 +152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 251_900_000 picoseconds. - Weight::from_parts(257_174_000, 0) - // Standard Error: 1_606 - .saturating_add(Weight::from_parts(250_961, 0).saturating_mul(v.into())) + // Minimum execution time: 485_154_000 picoseconds. + Weight::from_parts(498_991_000, 0) + // Standard Error: 3_249 + .saturating_add(Weight::from_parts(337_425, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) @@ -182,12 +182,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `371 + a * (768 ±0) + d * (48 ±0)` // Estimated: `3923 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 331_717_000 picoseconds. - Weight::from_parts(29_922_189, 3923) - // Standard Error: 9_972 - .saturating_add(Weight::from_parts(570_967, 0).saturating_mul(a.into())) - // Standard Error: 14_948 - .saturating_add(Weight::from_parts(159_043, 0).saturating_mul(d.into())) + // Minimum execution time: 352_979_000 picoseconds. + Weight::from_parts(383_783_000, 3923) + // Standard Error: 6_259 + .saturating_add(Weight::from_parts(426_032, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) @@ -203,17 +201,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ElectionProviderMultiPhase::SignedSubmissionIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (r:1 w:1) /// Proof: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:0 w:1) /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `927` - // Estimated: `2412` - // Minimum execution time: 44_129_000 picoseconds. - Weight::from_parts(46_420_000, 2412) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Measured: `860` + // Estimated: `2345` + // Minimum execution time: 50_191_000 picoseconds. + Weight::from_parts(51_531_000, 2345) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) @@ -238,12 +234,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `253 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1738 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 5_585_830_000 picoseconds. - Weight::from_parts(5_662_741_000, 1738) - // Standard Error: 17_454 - .saturating_add(Weight::from_parts(352_514, 0).saturating_mul(v.into())) - // Standard Error: 51_723 - .saturating_add(Weight::from_parts(4_182_087, 0).saturating_mul(a.into())) + // Minimum execution time: 5_946_406_000 picoseconds. + Weight::from_parts(6_087_882_000, 1738) + // Standard Error: 20_145 + .saturating_add(Weight::from_parts(348_338, 0).saturating_mul(v.into())) + // Standard Error: 59_699 + .saturating_add(Weight::from_parts(4_596_494, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) @@ -265,12 +261,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `228 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1713 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 4_902_422_000 picoseconds. - Weight::from_parts(5_001_852_000, 1713) + // Minimum execution time: 5_004_146_000 picoseconds. + Weight::from_parts(5_166_030_000, 1713) // Standard Error: 15_536 - .saturating_add(Weight::from_parts(354_309, 0).saturating_mul(v.into())) - // Standard Error: 46_041 - .saturating_add(Weight::from_parts(3_090_094, 0).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(306_715, 0).saturating_mul(v.into())) + // Standard Error: 46_039 + .saturating_add(Weight::from_parts(3_418_885, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) @@ -297,10 +293,10 @@ impl WeightInfo for () { /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `1061` + // Measured: `1094` // Estimated: `3481` - // Minimum execution time: 19_436_000 picoseconds. - Weight::from_parts(20_138_000, 3481) + // Minimum execution time: 27_022_000 picoseconds. + Weight::from_parts(27_654_000, 3481) .saturating_add(RocksDbWeight::get().reads(8_u64)) } /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) @@ -311,8 +307,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 8_356_000 picoseconds. - Weight::from_parts(8_708_000, 1633) + // Minimum execution time: 9_613_000 picoseconds. + Weight::from_parts(9_845_000, 1633) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -324,8 +320,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 9_088_000 picoseconds. - Weight::from_parts(9_382_000, 1633) + // Minimum execution time: 10_404_000 picoseconds. + Weight::from_parts(10_847_000, 1633) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -337,8 +333,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 25_899_000 picoseconds. - Weight::from_parts(26_456_000, 3593) + // Minimum execution time: 26_673_000 picoseconds. + Weight::from_parts(27_349_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -348,8 +344,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_671_000 picoseconds. - Weight::from_parts(18_131_000, 3593) + // Minimum execution time: 19_544_000 picoseconds. + Weight::from_parts(19_818_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -365,10 +361,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 251_900_000 picoseconds. - Weight::from_parts(257_174_000, 0) - // Standard Error: 1_606 - .saturating_add(Weight::from_parts(250_961, 0).saturating_mul(v.into())) + // Minimum execution time: 485_154_000 picoseconds. + Weight::from_parts(498_991_000, 0) + // Standard Error: 3_249 + .saturating_add(Weight::from_parts(337_425, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) @@ -395,12 +391,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `371 + a * (768 ±0) + d * (48 ±0)` // Estimated: `3923 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 331_717_000 picoseconds. - Weight::from_parts(29_922_189, 3923) - // Standard Error: 9_972 - .saturating_add(Weight::from_parts(570_967, 0).saturating_mul(a.into())) - // Standard Error: 14_948 - .saturating_add(Weight::from_parts(159_043, 0).saturating_mul(d.into())) + // Minimum execution time: 352_979_000 picoseconds. + Weight::from_parts(383_783_000, 3923) + // Standard Error: 6_259 + .saturating_add(Weight::from_parts(426_032, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) @@ -416,17 +410,15 @@ impl WeightInfo for () { /// Proof: `ElectionProviderMultiPhase::SignedSubmissionIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (r:1 w:1) /// Proof: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:0 w:1) /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `927` - // Estimated: `2412` - // Minimum execution time: 44_129_000 picoseconds. - Weight::from_parts(46_420_000, 2412) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Measured: `860` + // Estimated: `2345` + // Minimum execution time: 50_191_000 picoseconds. + Weight::from_parts(51_531_000, 2345) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) @@ -451,12 +443,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `253 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1738 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 5_585_830_000 picoseconds. - Weight::from_parts(5_662_741_000, 1738) - // Standard Error: 17_454 - .saturating_add(Weight::from_parts(352_514, 0).saturating_mul(v.into())) - // Standard Error: 51_723 - .saturating_add(Weight::from_parts(4_182_087, 0).saturating_mul(a.into())) + // Minimum execution time: 5_946_406_000 picoseconds. + Weight::from_parts(6_087_882_000, 1738) + // Standard Error: 20_145 + .saturating_add(Weight::from_parts(348_338, 0).saturating_mul(v.into())) + // Standard Error: 59_699 + .saturating_add(Weight::from_parts(4_596_494, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) @@ -478,12 +470,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `228 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1713 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 4_902_422_000 picoseconds. - Weight::from_parts(5_001_852_000, 1713) + // Minimum execution time: 5_004_146_000 picoseconds. + Weight::from_parts(5_166_030_000, 1713) // Standard Error: 15_536 - .saturating_add(Weight::from_parts(354_309, 0).saturating_mul(v.into())) - // Standard Error: 46_041 - .saturating_add(Weight::from_parts(3_090_094, 0).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(306_715, 0).saturating_mul(v.into())) + // Standard Error: 46_039 + .saturating_add(Weight::from_parts(3_418_885, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 771376e06656..5009d3d54d56 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -16,30 +16,30 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -parking_lot = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } log = { workspace = true } +parking_lot = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } -sp-staking = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } sp-npos-elections = { workspace = true } +sp-runtime = { workspace = true, default-features = true } +sp-staking = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } -pallet-election-provider-multi-phase = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } pallet-bags-list = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } +pallet-election-provider-multi-phase = { workspace = true, default-features = true } +pallet-nomination-pools = { workspace = true, default-features = true } pallet-session = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } [features] try-runtime = [ diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 135149694387..26a6345e145f 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -47,7 +47,7 @@ fn log_current_time() { "block: {:?}, session: {:?}, era: {:?}, EPM phase: {:?} ts: {:?}", System::block_number(), Session::current_index(), - Staking::current_era(), + pallet_staking::CurrentEra::::get(), CurrentPhase::::get(), Now::::get() ); @@ -147,30 +147,35 @@ fn mass_slash_doesnt_enter_emergency_phase() { let active_set_size_before_slash = Session::validators().len(); - // Slash more than 1/3 of the active validators - let mut slashed = slash_half_the_active_set(); + // assuming half is above the disabling limit (default 1/3), otherwise test will break + let slashed = slash_half_the_active_set(); let active_set_size_after_slash = Session::validators().len(); // active set should stay the same before and after the slash assert_eq!(active_set_size_before_slash, active_set_size_after_slash); - // Slashed validators are disabled up to a limit - slashed.truncate( - pallet_staking::UpToLimitDisablingStrategy::::disable_limit( - active_set_size_after_slash, - ), - ); - // Find the indices of the disabled validators let active_set = Session::validators(); - let expected_disabled = slashed + let potentially_disabled = slashed .into_iter() .map(|d| active_set.iter().position(|a| *a == d).unwrap() as u32) .collect::>(); + // Ensure that every actually disabled validator is also in the potentially disabled set + // (not necessarily the other way around) + let disabled = Session::disabled_validators(); + for d in disabled.iter() { + assert!(potentially_disabled.contains(d)); + } + + // Ensure no more than disabling limit of validators (default 1/3) is disabled + let disabling_limit = pallet_staking::UpToLimitWithReEnablingDisablingStrategy::< + SLASHING_DISABLING_FACTOR, + >::disable_limit(active_set_size_before_slash); + assert!(disabled.len() == disabling_limit); + assert_eq!(pallet_staking::ForceEra::::get(), pallet_staking::Forcing::NotForcing); - assert_eq!(Session::disabled_validators(), expected_disabled); }); } diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 360f14913fcc..eaab848c1694 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -49,7 +49,7 @@ use pallet_election_provider_multi_phase::{ unsigned::MinerConfig, Call, CurrentPhase, ElectionCompute, GeometricDepositBase, QueuedSolution, SolutionAccuracyOf, }; -use pallet_staking::StakerStatus; +use pallet_staking::{ActiveEra, CurrentEra, ErasStartSessionIndex, StakerStatus}; use parking_lot::RwLock; use std::sync::Arc; @@ -304,7 +304,8 @@ impl pallet_staking::Config for Runtime { type MaxUnlockingChunks = MaxUnlockingChunks; type EventListeners = Pools; type WeightInfo = pallet_staking::weights::SubstrateWeight; - type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type DisablingStrategy = + pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; } @@ -806,11 +807,11 @@ pub(crate) fn start_active_era( } pub(crate) fn active_era() -> EraIndex { - Staking::active_era().unwrap().index + ActiveEra::::get().unwrap().index } pub(crate) fn current_era() -> EraIndex { - Staking::current_era().unwrap() + CurrentEra::::get().unwrap() } // Fast forward until EPM signed phase. @@ -862,11 +863,11 @@ pub(crate) fn on_offence_now( >], slash_fraction: &[Perbill], ) { - let now = Staking::active_era().unwrap().index; + let now = ActiveEra::::get().unwrap().index; let _ = Staking::on_offence( offenders, slash_fraction, - Staking::eras_start_session_index(now).unwrap(), + ErasStartSessionIndex::::get(now).unwrap(), ); } diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index cae20d1b46a4..32fa381e1d27 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -16,14 +16,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-election-provider-solution-type = { workspace = true, default-features = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true } +sp-core = { workspace = true } sp-npos-elections = { workspace = true } sp-runtime = { workspace = true } -sp-core = { workspace = true } [dev-dependencies] rand = { features = ["small_rng"], workspace = true, default-features = true } diff --git a/substrate/frame/election-provider-support/benchmarking/src/inner.rs b/substrate/frame/election-provider-support/benchmarking/src/inner.rs index 8cca0d459eac..7fb8c1bdb729 100644 --- a/substrate/frame/election-provider-support/benchmarking/src/inner.rs +++ b/substrate/frame/election-provider-support/benchmarking/src/inner.rs @@ -20,17 +20,19 @@ use alloc::vec::Vec; use codec::Decode; -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v2::*; use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; - -pub struct Pallet(frame_system::Pallet); -pub trait Config: frame_system::Config {} +use sp_runtime::Perbill; const VOTERS: [u32; 2] = [1_000, 2_000]; const TARGETS: [u32; 2] = [500, 1_000]; const VOTES_PER_VOTER: [u32; 2] = [5, 16]; - const SEED: u32 = 999; + +pub trait Config: frame_system::Config {} + +pub struct Pallet(frame_system::Pallet); + fn set_up_voters_targets( voters_len: u32, targets_len: u32, @@ -54,36 +56,47 @@ fn set_up_voters_targets( (voters, targets) } -benchmarks! { - phragmen { - // number of votes in snapshot. - let v in (VOTERS[0]) .. VOTERS[1]; - // number of targets in snapshot. - let t in (TARGETS[0]) .. TARGETS[1]; - // number of votes per voter (ie the degree). - let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; - - let (voters, targets) = set_up_voters_targets::(v, t, d as usize); - }: { - assert!( - SequentialPhragmen:: - ::solve(d as usize, targets, voters).is_ok() - ); +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn phragmen( + // Number of votes in snapshot. + v: Linear<{ VOTERS[0] }, { VOTERS[1] }>, + // Number of targets in snapshot. + t: Linear<{ TARGETS[0] }, { TARGETS[1] }>, + // Number of votes per voter (ie the degree). + d: Linear<{ VOTES_PER_VOTER[0] }, { VOTES_PER_VOTER[1] }>, + ) { + let (voters, targets) = set_up_voters_targets::(v, t, d as _); + let result; + + #[block] + { + result = SequentialPhragmen::::solve(d as _, targets, voters); + } + + assert!(result.is_ok()); } - phragmms { - // number of votes in snapshot. - let v in (VOTERS[0]) .. VOTERS[1]; - // number of targets in snapshot. - let t in (TARGETS[0]) .. TARGETS[1]; - // number of votes per voter (ie the degree). - let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; - - let (voters, targets) = set_up_voters_targets::(v, t, d as usize); - }: { - assert!( - PhragMMS:: - ::solve(d as usize, targets, voters).is_ok() - ); + #[benchmark] + fn phragmms( + // Number of votes in snapshot. + v: Linear<{ VOTERS[0] }, { VOTERS[1] }>, + // Number of targets in snapshot. + t: Linear<{ TARGETS[0] }, { TARGETS[1] }>, + // Number of votes per voter (ie the degree). + d: Linear<{ VOTES_PER_VOTER[0] }, { VOTES_PER_VOTER[1] }>, + ) { + let (voters, targets) = set_up_voters_targets::(v, t, d as _); + let result; + + #[block] + { + result = PhragMMS::::solve(d as _, targets, voters); + } + + assert!(result.is_ok()); } } diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index e24ed7f079fe..c2f307016f6b 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { features = ["full", "visit"], workspace = true } -quote = { workspace = true } -proc-macro2 = { workspace = true } proc-macro-crate = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { features = ["full", "visit"], workspace = true } [dev-dependencies] codec = { workspace = true, default-features = true } diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 86abbf9677e0..d82a8acb2f84 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -21,14 +21,14 @@ honggfuzz = { workspace = true } rand = { features = ["small_rng", "std"], workspace = true, default-features = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-election-provider-solution-type = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } # used by generate_solution_type: -sp-npos-elections = { workspace = true } frame-support = { workspace = true, default-features = true } +sp-npos-elections = { workspace = true } [[bin]] name = "compact" diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index c1b12b3da4d8..b24ec7bd637e 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -19,11 +19,11 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-npos-elections = { workspace = true } diff --git a/substrate/frame/elections-phragmen/src/benchmarking.rs b/substrate/frame/elections-phragmen/src/benchmarking.rs index 8e762f667b2a..60771fa89ad7 100644 --- a/substrate/frame/elections-phragmen/src/benchmarking.rs +++ b/substrate/frame/elections-phragmen/src/benchmarking.rs @@ -19,47 +19,47 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; - -use frame_benchmarking::v1::{account, benchmarks, whitelist, BenchmarkError, BenchmarkResult}; +use frame_benchmarking::v2::*; use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; use frame_system::RawOrigin; -use crate::Pallet as Elections; +#[cfg(test)] +use crate::tests::MEMBERS; +use crate::*; const BALANCE_FACTOR: u32 = 250; -/// grab new account with infinite balance. +// grab new account with infinite balance. fn endowed_account(name: &'static str, index: u32) -> T::AccountId { let account: T::AccountId = account(name, index, 0); // Fund each account with at-least their stake but still a sane amount as to not mess up // the vote calculation. let amount = default_stake::(T::MaxVoters::get()) * BalanceOf::::from(BALANCE_FACTOR); let _ = T::Currency::make_free_balance_be(&account, amount); - // important to increase the total issuance since T::CurrencyToVote will need it to be sane for - // phragmen to work. + // Important to increase the total issuance since `T::CurrencyToVote` will need it to be sane + // for phragmen to work. let _ = T::Currency::issue(amount); account } -/// Account to lookup type of system trait. +// Account to lookup type of system trait. fn as_lookup(account: T::AccountId) -> AccountIdLookupOf { T::Lookup::unlookup(account) } -/// Get a reasonable amount of stake based on the execution trait's configuration +// Get a reasonable amount of stake based on the execution trait's configuration. fn default_stake(num_votes: u32) -> BalanceOf { let min = T::Currency::minimum_balance(); - Elections::::deposit_of(num_votes as usize).max(min) + Pallet::::deposit_of(num_votes as usize).max(min) } -/// Get the current number of candidates. +// Get the current number of candidates. fn candidate_count() -> u32 { Candidates::::decode_len().unwrap_or(0usize) as u32 } -/// Add `c` new candidates. +// Add `c` new candidates. fn submit_candidates( c: u32, prefix: &'static str, @@ -67,7 +67,7 @@ fn submit_candidates( (0..c) .map(|i| { let account = endowed_account::(prefix, i); - Elections::::submit_candidacy( + Pallet::::submit_candidacy( RawOrigin::Signed(account.clone()).into(), candidate_count::(), ) @@ -77,7 +77,7 @@ fn submit_candidates( .collect::>() } -/// Add `c` new candidates with self vote. +// Add `c` new candidates with self vote. fn submit_candidates_with_self_vote( c: u32, prefix: &'static str, @@ -90,17 +90,17 @@ fn submit_candidates_with_self_vote( Ok(candidates) } -/// Submit one voter. +// Submit one voter. fn submit_voter( caller: T::AccountId, votes: Vec, stake: BalanceOf, ) -> DispatchResultWithPostInfo { - Elections::::vote(RawOrigin::Signed(caller).into(), votes, stake) + Pallet::::vote(RawOrigin::Signed(caller).into(), votes, stake) } -/// create `num_voter` voters who randomly vote for at most `votes` of `all_candidates` if -/// available. +// Create `num_voter` voters who randomly vote for at most `votes` of `all_candidates` if +// available. fn distribute_voters( mut all_candidates: Vec, num_voters: u32, @@ -117,12 +117,12 @@ fn distribute_voters( Ok(()) } -/// Fill the seats of members and runners-up up until `m`. Note that this might include either only -/// members, or members and runners-up. +// Fill the seats of members and runners-up up until `m`. Note that this might include either only +// members, or members and runners-up. fn fill_seats_up_to(m: u32) -> Result, &'static str> { let _ = submit_candidates_with_self_vote::(m, "fill_seats_up_to")?; assert_eq!(Candidates::::get().len() as u32, m, "wrong number of candidates."); - Elections::::do_phragmen(); + Pallet::::do_phragmen(); assert_eq!(Candidates::::get().len(), 0, "some candidates remaining."); assert_eq!( Members::::get().len() + RunnersUp::::get().len(), @@ -136,7 +136,7 @@ fn fill_seats_up_to(m: u32) -> Result, &'static str .collect()) } -/// removes all the storage items to reverse any genesis state. +// Removes all the storage items to reverse any genesis state. fn clean() { Members::::kill(); Candidates::::kill(); @@ -145,10 +145,13 @@ fn clean() { Voting::::remove_all(None); } -benchmarks! { +#[benchmarks] +mod benchmarks { + use super::*; + // -- Signed ones - vote_equal { - let v in 1 .. T::MaxVotesPerVoter::get(); + #[benchmark] + fn vote_equal(v: Linear<1, { T::MaxVotesPerVoter::get() }>) -> Result<(), BenchmarkError> { clean::(); // create a bunch of candidates. @@ -157,65 +160,81 @@ benchmarks! { let caller = endowed_account::("caller", 0); let stake = default_stake::(v); - // original votes. + // Original votes. let mut votes = all_candidates; submit_voter::(caller.clone(), votes.clone(), stake)?; - // new votes. + // New votes. votes.rotate_left(1); whitelist!(caller); - }: vote(RawOrigin::Signed(caller), votes, stake) - vote_more { - let v in 2 .. T::MaxVotesPerVoter::get(); + #[extrinsic_call] + vote(RawOrigin::Signed(caller), votes, stake); + + Ok(()) + } + + #[benchmark] + fn vote_more(v: Linear<2, { T::MaxVotesPerVoter::get() }>) -> Result<(), BenchmarkError> { clean::(); - // create a bunch of candidates. + // Create a bunch of candidates. let all_candidates = submit_candidates::(v, "candidates")?; let caller = endowed_account::("caller", 0); // Multiply the stake with 10 since we want to be able to divide it by 10 again. - let stake = default_stake::(v) * BalanceOf::::from(10u32); + let stake = default_stake::(v) * BalanceOf::::from(10_u32); - // original votes. + // Original votes. let mut votes = all_candidates.iter().skip(1).cloned().collect::>(); - submit_voter::(caller.clone(), votes.clone(), stake / BalanceOf::::from(10u32))?; + submit_voter::(caller.clone(), votes.clone(), stake / BalanceOf::::from(10_u32))?; - // new votes. + // New votes. votes = all_candidates; assert!(votes.len() > Voting::::get(caller.clone()).votes.len()); whitelist!(caller); - }: vote(RawOrigin::Signed(caller), votes, stake / BalanceOf::::from(10u32)) - vote_less { - let v in 2 .. T::MaxVotesPerVoter::get(); + #[extrinsic_call] + vote(RawOrigin::Signed(caller), votes, stake / BalanceOf::::from(10_u32)); + + Ok(()) + } + + #[benchmark] + fn vote_less(v: Linear<2, { T::MaxVotesPerVoter::get() }>) -> Result<(), BenchmarkError> { clean::(); - // create a bunch of candidates. + // Create a bunch of candidates. let all_candidates = submit_candidates::(v, "candidates")?; let caller = endowed_account::("caller", 0); let stake = default_stake::(v); - // original votes. + // Original votes. let mut votes = all_candidates; submit_voter::(caller.clone(), votes.clone(), stake)?; - // new votes. + // New votes. votes = votes.into_iter().skip(1).collect::>(); assert!(votes.len() < Voting::::get(caller.clone()).votes.len()); whitelist!(caller); - }: vote(RawOrigin::Signed(caller), votes, stake) - remove_voter { - // we fix the number of voted candidates to max + #[extrinsic_call] + vote(RawOrigin::Signed(caller), votes, stake); + + Ok(()) + } + + #[benchmark] + fn remove_voter() -> Result<(), BenchmarkError> { + // We fix the number of voted candidates to max. let v = T::MaxVotesPerVoter::get(); clean::(); - // create a bunch of candidates. + // Create a bunch of candidates. let all_candidates = submit_candidates::(v, "candidates")?; let caller = endowed_account::("caller", 0); @@ -224,207 +243,245 @@ benchmarks! { submit_voter::(caller.clone(), all_candidates, stake)?; whitelist!(caller); - }: _(RawOrigin::Signed(caller)) - submit_candidacy { - // number of already existing candidates. - let c in 1 .. T::MaxCandidates::get(); - // we fix the number of members to the number of desired members and runners-up. We'll be in - // this state almost always. + #[extrinsic_call] + _(RawOrigin::Signed(caller)); + + Ok(()) + } + + #[benchmark] + fn submit_candidacy( + // Number of already existing candidates. + c: Linear<1, { T::MaxCandidates::get() }>, + ) -> Result<(), BenchmarkError> { + // We fix the number of members to the number of desired members and runners-up. + // We'll be in this state almost always. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); clean::(); - let stake = default_stake::(c); - // create m members and runners combined. + // Create `m` members and runners combined. let _ = fill_seats_up_to::(m)?; - // create previous candidates; + // Create previous candidates. let _ = submit_candidates::(c, "candidates")?; - // we assume worse case that: extrinsic is successful and candidate is not duplicate. + // We assume worse case that: extrinsic is successful and candidate is not duplicate. let candidate_account = endowed_account::("caller", 0); whitelist!(candidate_account); - }: _(RawOrigin::Signed(candidate_account.clone()), candidate_count::()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(candidate_account), candidate_count::()); + + // Reset members in between benchmark tests. #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } + MEMBERS.with(|m| *m.borrow_mut() = vec![]); + + Ok(()) } - renounce_candidacy_candidate { - // this will check members, runners-up and candidate for removal. Members and runners-up are - // limited by the runtime bound, nonetheless we fill them by `m`. - // number of already existing candidates. - let c in 1 .. T::MaxCandidates::get(); - // we fix the number of members to the number of desired members and runners-up. We'll be in - // this state almost always. + #[benchmark] + fn renounce_candidacy_candidate( + // This will check members, runners-up and candidate for removal. + // Members and runners-up are limited by the runtime bound, nonetheless we fill them by + // `m`. + // Number of already existing candidates. + c: Linear<1, { T::MaxCandidates::get() }>, + ) -> Result<(), BenchmarkError> { + // We fix the number of members to the number of desired members and runners-up. + // We'll be in this state almost always. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); clean::(); - // create m members and runners combined. + // Create `m` members and runners combined. let _ = fill_seats_up_to::(m)?; let all_candidates = submit_candidates::(c, "caller")?; let bailing = all_candidates[0].clone(); // Should be ("caller", 0) let count = candidate_count::(); whitelist!(bailing); - }: renounce_candidacy(RawOrigin::Signed(bailing), Renouncing::Candidate(count)) - verify { + + #[extrinsic_call] + renounce_candidacy(RawOrigin::Signed(bailing), Renouncing::Candidate(count)); + + // Reset members in between benchmark tests. #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } + MEMBERS.with(|m| *m.borrow_mut() = vec![]); + + Ok(()) } - renounce_candidacy_members { - // removing members and runners will be cheaper than a candidate. - // we fix the number of members to when members and runners-up to the desired. We'll be in - // this state almost always. + #[benchmark] + fn renounce_candidacy_members() -> Result<(), BenchmarkError> { + // Removing members and runners will be cheaper than a candidate. + // We fix the number of members to when members and runners-up to the desired. + // We'll be in this state almost always. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); clean::(); - // create m members and runners combined. + // Create `m` members and runners combined. let members_and_runners_up = fill_seats_up_to::(m)?; let bailing = members_and_runners_up[0].clone(); - assert!(Elections::::is_member(&bailing)); + assert!(Pallet::::is_member(&bailing)); whitelist!(bailing); - }: renounce_candidacy(RawOrigin::Signed(bailing.clone()), Renouncing::Member) - verify { + + #[extrinsic_call] + renounce_candidacy(RawOrigin::Signed(bailing.clone()), Renouncing::Member); + + // Reset members in between benchmark tests. #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } + MEMBERS.with(|m| *m.borrow_mut() = vec![]); + + Ok(()) } - renounce_candidacy_runners_up { - // removing members and runners will be cheaper than a candidate. - // we fix the number of members to when members and runners-up to the desired. We'll be in - // this state almost always. + #[benchmark] + fn renounce_candidacy_runners_up() -> Result<(), BenchmarkError> { + // Removing members and runners will be cheaper than a candidate. + // We fix the number of members to when members and runners-up to the desired. + // We'll be in this state almost always. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); clean::(); - // create m members and runners combined. + // Create `m` members and runners combined. let members_and_runners_up = fill_seats_up_to::(m)?; let bailing = members_and_runners_up[T::DesiredMembers::get() as usize + 1].clone(); - assert!(Elections::::is_runner_up(&bailing)); + assert!(Pallet::::is_runner_up(&bailing)); whitelist!(bailing); - }: renounce_candidacy(RawOrigin::Signed(bailing.clone()), Renouncing::RunnerUp) - verify { + + #[extrinsic_call] + renounce_candidacy(RawOrigin::Signed(bailing.clone()), Renouncing::RunnerUp); + + // Reset members in between benchmark tests. #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } + MEMBERS.with(|m| *m.borrow_mut() = vec![]); + + Ok(()) } // We use the max block weight for this extrinsic for now. See below. - remove_member_without_replacement {}: { - Err(BenchmarkError::Override( - BenchmarkResult::from_weight(T::BlockWeights::get().max_block) - ))?; + #[benchmark] + fn remove_member_without_replacement() -> Result<(), BenchmarkError> { + #[block] + { + Err(BenchmarkError::Override(BenchmarkResult::from_weight( + T::BlockWeights::get().max_block, + )))?; + } + + Ok(()) } - remove_member_with_replacement { - // easy case. We have a runner up. Nothing will have that much of an impact. m will be - // number of members and runners. There is always at least one runner. + #[benchmark] + fn remove_member_with_replacement() -> Result<(), BenchmarkError> { + // Easy case. + // We have a runner up. + // Nothing will have that much of an impact. + // `m` will be number of members and runners. + // There is always at least one runner. let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get(); clean::(); let _ = fill_seats_up_to::(m)?; - let removing = as_lookup::(Elections::::members_ids()[0].clone()); - }: remove_member(RawOrigin::Root, removing, true, false) - verify { - // must still have enough members. + let removing = as_lookup::(Pallet::::members_ids()[0].clone()); + + #[extrinsic_call] + remove_member(RawOrigin::Root, removing, true, false); + + // Must still have enough members. assert_eq!(Members::::get().len() as u32, T::DesiredMembers::get()); + + // Reset members in between benchmark tests. #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } + MEMBERS.with(|m| *m.borrow_mut() = vec![]); - clean_defunct_voters { - // total number of voters. - let v in (T::MaxVoters::get() / 2) .. T::MaxVoters::get(); - // those that are defunct and need removal. - let d in 0 .. (T::MaxVoters::get() / 2); + Ok(()) + } - // remove any previous stuff. + #[benchmark] + fn clean_defunct_voters( + // Total number of voters. + v: Linear<{ T::MaxVoters::get() / 2 }, { T::MaxVoters::get() }>, + // Those that are defunct and need removal. + d: Linear<0, { T::MaxVoters::get() / 2 }>, + ) -> Result<(), BenchmarkError> { + // Remove any previous stuff. clean::(); let all_candidates = submit_candidates::(T::MaxCandidates::get(), "candidates")?; distribute_voters::(all_candidates, v, T::MaxVotesPerVoter::get() as usize)?; - // all candidates leave. + // All candidates leave. Candidates::::kill(); - // now everyone is defunct - assert!(Voting::::iter().all(|(_, v)| Elections::::is_defunct_voter(&v.votes))); + // Now everyone is defunct. + assert!(Voting::::iter().all(|(_, v)| Pallet::::is_defunct_voter(&v.votes))); assert_eq!(Voting::::iter().count() as u32, v); - let root = RawOrigin::Root; - }: _(root, v, d) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, v, d); + assert_eq!(Voting::::iter().count() as u32, v - d); + + Ok(()) } - election_phragmen { - // This is just to focus on phragmen in the context of this module. We always select 20 - // members, this is hard-coded in the runtime and cannot be trivially changed at this stage. - // Yet, change the number of voters, candidates and edge per voter to see the impact. Note - // that we give all candidates a self vote to make sure they are all considered. - let c in 1 .. T::MaxCandidates::get(); - let v in 1 .. T::MaxVoters::get(); - let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * T::MaxVotesPerVoter::get(); + #[benchmark] + fn election_phragmen( + // This is just to focus on phragmen in the context of this module. + // We always select 20 members, this is hard-coded in the runtime and cannot be trivially + // changed at this stage. Yet, change the number of voters, candidates and edge per voter + // to see the impact. Note that we give all candidates a self vote to make sure they are + // all considered. + c: Linear<1, { T::MaxCandidates::get() }>, + v: Linear<1, { T::MaxVoters::get() }>, + e: Linear<{ T::MaxVoters::get() }, { T::MaxVoters::get() * T::MaxVotesPerVoter::get() }>, + ) -> Result<(), BenchmarkError> { clean::(); - // so we have a situation with v and e. we want e to basically always be in the range of `e - // -> e * T::MaxVotesPerVoter::get()`, but we cannot express that now with the benchmarks. - // So what we do is: when c is being iterated, v, and e are max and fine. when v is being - // iterated, e is being set to max and this is a problem. In these cases, we cap e to a - // lower value, namely v * T::MaxVotesPerVoter::get(). when e is being iterated, v is at - // max, and again fine. all in all, votes_per_voter can never be more than - // T::MaxVotesPerVoter::get(). Note that this might cause `v` to be an overestimate. + // So we have a situation with `v` and `e`. + // We want `e` to basically always be in the range of + // `e -> e * T::MaxVotesPerVoter::get()`, but we cannot express that now with the + // benchmarks. So what we do is: when `c` is being iterated, `v`, and `e` are max and + // fine. When `v` is being iterated, `e` is being set to max and this is a problem. + // In these cases, we cap `e` to a lower value, namely `v * T::MaxVotesPerVoter::get()`. + // When `e` is being iterated, `v` is at max, and again fine. + // All in all, `votes_per_voter` can never be more than `T::MaxVotesPerVoter::get()`. + // Note that this might cause `v` to be an overestimate. let votes_per_voter = (e / v).min(T::MaxVotesPerVoter::get()); let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; - let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; - }: { - Elections::::on_initialize(T::TermDuration::get()); - } - verify { + let _ = + distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; + + #[block] + { + Pallet::::on_initialize(T::TermDuration::get()); + } + assert_eq!(Members::::get().len() as u32, T::DesiredMembers::get().min(c)); assert_eq!( RunnersUp::::get().len() as u32, T::DesiredRunnersUp::get().min(c.saturating_sub(T::DesiredMembers::get())), ); + // reset members in between benchmark tests. #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } + MEMBERS.with(|m| *m.borrow_mut() = vec![]); + + Ok(()) } - impl_benchmark_test_suite!( - Elections, - crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7), - crate::tests::Test, + impl_benchmark_test_suite! { + Pallet, + tests::ExtBuilder::default().desired_members(13).desired_runners_up(7), + tests::Test, exec_name = build_and_execute, - ); + } } diff --git a/substrate/frame/elections-phragmen/src/weights.rs b/substrate/frame/elections-phragmen/src/weights.rs index fb2e10f9f066..f71106a47978 100644 --- a/substrate/frame/elections-phragmen/src/weights.rs +++ b/substrate/frame/elections-phragmen/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_elections_phragmen` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -83,12 +83,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `403 + v * (80 ±0)` + // Measured: `436 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 30_160_000 picoseconds. - Weight::from_parts(31_473_640, 4764) - // Standard Error: 3_581 - .saturating_add(Weight::from_parts(135_663, 0).saturating_mul(v.into())) + // Minimum execution time: 39_685_000 picoseconds. + Weight::from_parts(40_878_043, 4764) + // Standard Error: 3_272 + .saturating_add(Weight::from_parts(168_519, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) @@ -108,12 +108,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `371 + v * (80 ±0)` + // Measured: `404 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 41_429_000 picoseconds. - Weight::from_parts(42_684_714, 4764) - // Standard Error: 4_828 - .saturating_add(Weight::from_parts(173_254, 0).saturating_mul(v.into())) + // Minimum execution time: 51_703_000 picoseconds. + Weight::from_parts(53_305_901, 4764) + // Standard Error: 5_269 + .saturating_add(Weight::from_parts(167_784, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) @@ -133,12 +133,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `403 + v * (80 ±0)` + // Measured: `436 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 41_013_000 picoseconds. - Weight::from_parts(42_555_632, 4764) - // Standard Error: 4_627 - .saturating_add(Weight::from_parts(162_225, 0).saturating_mul(v.into())) + // Minimum execution time: 51_554_000 picoseconds. + Weight::from_parts(53_523_254, 4764) + // Standard Error: 5_642 + .saturating_add(Weight::from_parts(156_053, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) @@ -151,10 +151,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn remove_voter() -> Weight { // Proof Size summary in bytes: - // Measured: `925` + // Measured: `958` // Estimated: `4764` - // Minimum execution time: 43_431_000 picoseconds. - Weight::from_parts(44_500_000, 4764) + // Minimum execution time: 51_835_000 picoseconds. + Weight::from_parts(56_349_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -167,12 +167,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1570 + c * (48 ±0)` - // Estimated: `3055 + c * (48 ±0)` - // Minimum execution time: 34_520_000 picoseconds. - Weight::from_parts(35_911_881, 3055) - // Standard Error: 1_885 - .saturating_add(Weight::from_parts(123_837, 0).saturating_mul(c.into())) + // Measured: `1603 + c * (48 ±0)` + // Estimated: `3088 + c * (48 ±0)` + // Minimum execution time: 40_974_000 picoseconds. + Weight::from_parts(42_358_018, 3088) + // Standard Error: 1_472 + .saturating_add(Weight::from_parts(85_881, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -182,12 +182,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `285 + c * (48 ±0)` - // Estimated: `1770 + c * (48 ±0)` - // Minimum execution time: 28_020_000 picoseconds. - Weight::from_parts(29_227_248, 1770) - // Standard Error: 1_202 - .saturating_add(Weight::from_parts(83_328, 0).saturating_mul(c.into())) + // Measured: `318 + c * (48 ±0)` + // Estimated: `1803 + c * (48 ±0)` + // Minimum execution time: 33_286_000 picoseconds. + Weight::from_parts(34_809_065, 1803) + // Standard Error: 1_507 + .saturating_add(Weight::from_parts(67_115, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -204,10 +204,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` - // Estimated: `3418` - // Minimum execution time: 42_489_000 picoseconds. - Weight::from_parts(43_710_000, 3418) + // Measured: `1999` + // Estimated: `3484` + // Minimum execution time: 49_223_000 picoseconds. + Weight::from_parts(50_790_000, 3484) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -215,10 +215,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn renounce_candidacy_runners_up() -> Weight { // Proof Size summary in bytes: - // Measured: `880` - // Estimated: `2365` - // Minimum execution time: 29_228_000 picoseconds. - Weight::from_parts(30_343_000, 2365) + // Measured: `913` + // Estimated: `2398` + // Minimum execution time: 36_995_000 picoseconds. + Weight::from_parts(37_552_000, 2398) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -245,10 +245,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` + // Measured: `1999` // Estimated: `3593` - // Minimum execution time: 46_909_000 picoseconds. - Weight::from_parts(47_907_000, 3593) + // Minimum execution time: 54_506_000 picoseconds. + Weight::from_parts(55_765_000, 3593) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -271,13 +271,13 @@ impl WeightInfo for SubstrateWeight { fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + d * (818 ±0) + v * (57 ±0)` - // Estimated: `24906 + d * (3774 ±0) + v * (24 ±0)` - // Minimum execution time: 5_175_000 picoseconds. - Weight::from_parts(5_797_000, 24906) - // Standard Error: 10_951 - .saturating_add(Weight::from_parts(39_675, 0).saturating_mul(v.into())) - // Standard Error: 23_850 - .saturating_add(Weight::from_parts(53_959_224, 0).saturating_mul(d.into())) + // Estimated: `24939 + d * (3774 ±1) + v * (24 ±0)` + // Minimum execution time: 7_043_000 picoseconds. + Weight::from_parts(7_628_000, 24939) + // Standard Error: 17_891 + .saturating_add(Weight::from_parts(357_049, 0).saturating_mul(v.into())) + // Standard Error: 38_964 + .saturating_add(Weight::from_parts(61_698_254, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(d.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(d.into()))) @@ -308,13 +308,13 @@ impl WeightInfo for SubstrateWeight { fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + e * (28 ±0) + v * (606 ±0)` - // Estimated: `178920 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` - // Minimum execution time: 1_136_994_000 picoseconds. - Weight::from_parts(1_142_143_000, 178920) - // Standard Error: 595_387 - .saturating_add(Weight::from_parts(19_373_386, 0).saturating_mul(v.into())) - // Standard Error: 38_201 - .saturating_add(Weight::from_parts(797_696, 0).saturating_mul(e.into())) + // Estimated: `179052 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_343_974_000 picoseconds. + Weight::from_parts(1_352_233_000, 179052) + // Standard Error: 597_762 + .saturating_add(Weight::from_parts(20_404_086, 0).saturating_mul(v.into())) + // Standard Error: 38_353 + .saturating_add(Weight::from_parts(793_851, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) @@ -343,12 +343,12 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `403 + v * (80 ±0)` + // Measured: `436 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 30_160_000 picoseconds. - Weight::from_parts(31_473_640, 4764) - // Standard Error: 3_581 - .saturating_add(Weight::from_parts(135_663, 0).saturating_mul(v.into())) + // Minimum execution time: 39_685_000 picoseconds. + Weight::from_parts(40_878_043, 4764) + // Standard Error: 3_272 + .saturating_add(Weight::from_parts(168_519, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) @@ -368,12 +368,12 @@ impl WeightInfo for () { /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `371 + v * (80 ±0)` + // Measured: `404 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 41_429_000 picoseconds. - Weight::from_parts(42_684_714, 4764) - // Standard Error: 4_828 - .saturating_add(Weight::from_parts(173_254, 0).saturating_mul(v.into())) + // Minimum execution time: 51_703_000 picoseconds. + Weight::from_parts(53_305_901, 4764) + // Standard Error: 5_269 + .saturating_add(Weight::from_parts(167_784, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) @@ -393,12 +393,12 @@ impl WeightInfo for () { /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `403 + v * (80 ±0)` + // Measured: `436 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 41_013_000 picoseconds. - Weight::from_parts(42_555_632, 4764) - // Standard Error: 4_627 - .saturating_add(Weight::from_parts(162_225, 0).saturating_mul(v.into())) + // Minimum execution time: 51_554_000 picoseconds. + Weight::from_parts(53_523_254, 4764) + // Standard Error: 5_642 + .saturating_add(Weight::from_parts(156_053, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) @@ -411,10 +411,10 @@ impl WeightInfo for () { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn remove_voter() -> Weight { // Proof Size summary in bytes: - // Measured: `925` + // Measured: `958` // Estimated: `4764` - // Minimum execution time: 43_431_000 picoseconds. - Weight::from_parts(44_500_000, 4764) + // Minimum execution time: 51_835_000 picoseconds. + Weight::from_parts(56_349_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -427,12 +427,12 @@ impl WeightInfo for () { /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1570 + c * (48 ±0)` - // Estimated: `3055 + c * (48 ±0)` - // Minimum execution time: 34_520_000 picoseconds. - Weight::from_parts(35_911_881, 3055) - // Standard Error: 1_885 - .saturating_add(Weight::from_parts(123_837, 0).saturating_mul(c.into())) + // Measured: `1603 + c * (48 ±0)` + // Estimated: `3088 + c * (48 ±0)` + // Minimum execution time: 40_974_000 picoseconds. + Weight::from_parts(42_358_018, 3088) + // Standard Error: 1_472 + .saturating_add(Weight::from_parts(85_881, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -442,12 +442,12 @@ impl WeightInfo for () { /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `285 + c * (48 ±0)` - // Estimated: `1770 + c * (48 ±0)` - // Minimum execution time: 28_020_000 picoseconds. - Weight::from_parts(29_227_248, 1770) - // Standard Error: 1_202 - .saturating_add(Weight::from_parts(83_328, 0).saturating_mul(c.into())) + // Measured: `318 + c * (48 ±0)` + // Estimated: `1803 + c * (48 ±0)` + // Minimum execution time: 33_286_000 picoseconds. + Weight::from_parts(34_809_065, 1803) + // Standard Error: 1_507 + .saturating_add(Weight::from_parts(67_115, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) @@ -464,10 +464,10 @@ impl WeightInfo for () { /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` - // Estimated: `3418` - // Minimum execution time: 42_489_000 picoseconds. - Weight::from_parts(43_710_000, 3418) + // Measured: `1999` + // Estimated: `3484` + // Minimum execution time: 49_223_000 picoseconds. + Weight::from_parts(50_790_000, 3484) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -475,10 +475,10 @@ impl WeightInfo for () { /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn renounce_candidacy_runners_up() -> Weight { // Proof Size summary in bytes: - // Measured: `880` - // Estimated: `2365` - // Minimum execution time: 29_228_000 picoseconds. - Weight::from_parts(30_343_000, 2365) + // Measured: `913` + // Estimated: `2398` + // Minimum execution time: 36_995_000 picoseconds. + Weight::from_parts(37_552_000, 2398) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -505,10 +505,10 @@ impl WeightInfo for () { /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` + // Measured: `1999` // Estimated: `3593` - // Minimum execution time: 46_909_000 picoseconds. - Weight::from_parts(47_907_000, 3593) + // Minimum execution time: 54_506_000 picoseconds. + Weight::from_parts(55_765_000, 3593) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -531,13 +531,13 @@ impl WeightInfo for () { fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + d * (818 ±0) + v * (57 ±0)` - // Estimated: `24906 + d * (3774 ±0) + v * (24 ±0)` - // Minimum execution time: 5_175_000 picoseconds. - Weight::from_parts(5_797_000, 24906) - // Standard Error: 10_951 - .saturating_add(Weight::from_parts(39_675, 0).saturating_mul(v.into())) - // Standard Error: 23_850 - .saturating_add(Weight::from_parts(53_959_224, 0).saturating_mul(d.into())) + // Estimated: `24939 + d * (3774 ±1) + v * (24 ±0)` + // Minimum execution time: 7_043_000 picoseconds. + Weight::from_parts(7_628_000, 24939) + // Standard Error: 17_891 + .saturating_add(Weight::from_parts(357_049, 0).saturating_mul(v.into())) + // Standard Error: 38_964 + .saturating_add(Weight::from_parts(61_698_254, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(d.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(d.into()))) @@ -568,13 +568,13 @@ impl WeightInfo for () { fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + e * (28 ±0) + v * (606 ±0)` - // Estimated: `178920 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` - // Minimum execution time: 1_136_994_000 picoseconds. - Weight::from_parts(1_142_143_000, 178920) - // Standard Error: 595_387 - .saturating_add(Weight::from_parts(19_373_386, 0).saturating_mul(v.into())) - // Standard Error: 38_201 - .saturating_add(Weight::from_parts(797_696, 0).saturating_mul(e.into())) + // Estimated: `179052 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_343_974_000 picoseconds. + Weight::from_parts(1_352_233_000, 179052) + // Standard Error: 597_762 + .saturating_add(Weight::from_parts(20_404_086, 0).saturating_mul(v.into())) + // Standard Error: 38_353 + .saturating_add(Weight::from_parts(793_851, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 0c6ad5ef0978..9eac53f0d98b 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -18,14 +18,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] pallet-default-config-example = { workspace = true } pallet-dev-mode = { workspace = true } +pallet-example-authorization-tx-extension = { workspace = true } pallet-example-basic = { workspace = true } pallet-example-frame-crate = { workspace = true } pallet-example-kitchensink = { workspace = true } pallet-example-offchain-worker = { workspace = true } -pallet-example-split = { workspace = true } pallet-example-single-block-migrations = { workspace = true } +pallet-example-split = { workspace = true } pallet-example-tasks = { workspace = true } -pallet-example-authorization-tx-extension = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/examples/authorization-tx-extension/src/extensions.rs b/substrate/frame/examples/authorization-tx-extension/src/extensions.rs index d1e56916d3a2..dcbe171c183a 100644 --- a/substrate/frame/examples/authorization-tx-extension/src/extensions.rs +++ b/substrate/frame/examples/authorization-tx-extension/src/extensions.rs @@ -18,7 +18,7 @@ use core::{fmt, marker::PhantomData}; use codec::{Decode, Encode}; -use frame_support::{traits::OriginTrait, Parameter}; +use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, Parameter}; use scale_info::TypeInfo; use sp_runtime::{ impl_tx_ext_default, @@ -94,6 +94,7 @@ where _len: usize, _self_implicit: Self::Implicit, inherited_implication: &impl codec::Encode, + _source: TransactionSource, ) -> ValidateResult { // If the extension is inactive, just move on in the pipeline. let Some(auth) = &self.inner else { diff --git a/substrate/frame/examples/authorization-tx-extension/src/tests.rs b/substrate/frame/examples/authorization-tx-extension/src/tests.rs index 7ede549a2f13..5579e7a98416 100644 --- a/substrate/frame/examples/authorization-tx-extension/src/tests.rs +++ b/substrate/frame/examples/authorization-tx-extension/src/tests.rs @@ -24,8 +24,9 @@ use frame_support::{ pallet_prelude::{InvalidTransaction, TransactionValidityError}, }; use pallet_verify_signature::VerifySignature; -use sp_keyring::AccountKeyring; +use sp_keyring::Sr25519Keyring; use sp_runtime::{ + generic::ExtensionVersion, traits::{Applyable, Checkable, IdentityLookup, TransactionExtension}, MultiSignature, MultiSigner, }; @@ -35,11 +36,12 @@ use crate::{extensions::AuthorizeCoownership, mock::*, pallet_assets}; #[test] fn create_asset_works() { new_test_ext().execute_with(|| { - let alice_keyring = AccountKeyring::Alice; + let alice_keyring = Sr25519Keyring::Alice; let alice_account = AccountId::from(alice_keyring.public()); // Simple call to create asset with Id `42`. let create_asset_call = RuntimeCall::Assets(pallet_assets::Call::create_asset { asset_id: 42 }); + let ext_version: ExtensionVersion = 0; // Create extension that will be used for dispatch. let initial_nonce = 23; let tx_ext = ( @@ -52,7 +54,7 @@ fn create_asset_works() { // Create the transaction signature, to be used in the top level `VerifyMultiSignature` // extension. let tx_sign = MultiSignature::Sr25519( - (&create_asset_call, &tx_ext, tx_ext.implicit().unwrap()) + (&(ext_version, &create_asset_call), &tx_ext, tx_ext.implicit().unwrap()) .using_encoded(|e| alice_keyring.sign(&sp_io::hashing::blake2_256(e))), ); // Add the signature to the extension. @@ -97,15 +99,16 @@ fn create_asset_works() { #[test] fn create_coowned_asset_works() { new_test_ext().execute_with(|| { - let alice_keyring = AccountKeyring::Alice; - let bob_keyring = AccountKeyring::Bob; - let charlie_keyring = AccountKeyring::Charlie; + let alice_keyring = Sr25519Keyring::Alice; + let bob_keyring = Sr25519Keyring::Bob; + let charlie_keyring = Sr25519Keyring::Charlie; let alice_account = AccountId::from(alice_keyring.public()); let bob_account = AccountId::from(bob_keyring.public()); let charlie_account = AccountId::from(charlie_keyring.public()); // Simple call to create asset with Id `42`. let create_asset_call = RuntimeCall::Assets(pallet_assets::Call::create_asset { asset_id: 42 }); + let ext_version: ExtensionVersion = 0; // Create the inner transaction extension, to be signed by our coowners, Alice and Bob. let inner_ext: InnerTxExtension = ( frame_system::CheckGenesis::::new(), @@ -113,7 +116,8 @@ fn create_coowned_asset_works() { frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), ); // Create the payload Alice and Bob need to sign. - let inner_payload = (&create_asset_call, &inner_ext, inner_ext.implicit().unwrap()); + let inner_payload = + (&(ext_version, &create_asset_call), &inner_ext, inner_ext.implicit().unwrap()); // Create Alice's signature. let alice_inner_sig = MultiSignature::Sr25519( inner_payload.using_encoded(|e| alice_keyring.sign(&sp_io::hashing::blake2_256(e))), @@ -138,7 +142,7 @@ fn create_coowned_asset_works() { // Create Charlie's transaction signature, to be used in the top level // `VerifyMultiSignature` extension. let tx_sign = MultiSignature::Sr25519( - (&create_asset_call, &tx_ext, tx_ext.implicit().unwrap()) + (&(ext_version, &create_asset_call), &tx_ext, tx_ext.implicit().unwrap()) .using_encoded(|e| charlie_keyring.sign(&sp_io::hashing::blake2_256(e))), ); // Add the signature to the extension. @@ -185,13 +189,14 @@ fn create_coowned_asset_works() { #[test] fn inner_authorization_works() { new_test_ext().execute_with(|| { - let alice_keyring = AccountKeyring::Alice; - let bob_keyring = AccountKeyring::Bob; - let charlie_keyring = AccountKeyring::Charlie; + let alice_keyring = Sr25519Keyring::Alice; + let bob_keyring = Sr25519Keyring::Bob; + let charlie_keyring = Sr25519Keyring::Charlie; let charlie_account = AccountId::from(charlie_keyring.public()); // Simple call to create asset with Id `42`. let create_asset_call = RuntimeCall::Assets(pallet_assets::Call::create_asset { asset_id: 42 }); + let ext_version: ExtensionVersion = 0; // Create the inner transaction extension, to be signed by our coowners, Alice and Bob. They // are going to sign this transaction as a mortal one. let inner_ext: InnerTxExtension = ( @@ -227,7 +232,7 @@ fn inner_authorization_works() { // Create Charlie's transaction signature, to be used in the top level // `VerifyMultiSignature` extension. let tx_sign = MultiSignature::Sr25519( - (&create_asset_call, &tx_ext, tx_ext.implicit().unwrap()) + (&(ext_version, &create_asset_call), &tx_ext, tx_ext.implicit().unwrap()) .using_encoded(|e| charlie_keyring.sign(&sp_io::hashing::blake2_256(e))), ); // Add the signature to the extension that Charlie signed. diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index f7e2b653c2d1..1deb82cc6ea5 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -18,12 +18,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-balances = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index 2f1b32d964e4..efdf4332e329 100644 --- a/substrate/frame/examples/basic/src/lib.rs +++ b/substrate/frame/examples/basic/src/lib.rs @@ -61,6 +61,7 @@ use codec::{Decode, Encode}; use core::marker::PhantomData; use frame_support::{ dispatch::{ClassifyDispatch, DispatchClass, DispatchResult, Pays, PaysFee, WeighData}, + pallet_prelude::TransactionSource, traits::IsSubType, weights::Weight, }; @@ -508,6 +509,7 @@ where len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult::RuntimeCall> { // if the transaction is too big, just drop it. if len > 200 { diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index 8e33d3d0a348..5ec253ebecf4 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -28,6 +28,7 @@ use sp_core::H256; // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sp_runtime::{ traits::{BlakeTwo256, DispatchTransaction, IdentityLookup}, + transaction_validity::TransactionSource::External, BuildStorage, }; // Reexport crate as its pallet name for construct_runtime. @@ -146,7 +147,7 @@ fn signed_ext_watch_dummy_works() { assert_eq!( WatchDummy::(PhantomData) - .validate_only(Some(1).into(), &call, &info, 150) + .validate_only(Some(1).into(), &call, &info, 150, External, 0) .unwrap() .0 .priority, @@ -154,7 +155,7 @@ fn signed_ext_watch_dummy_works() { ); assert_eq!( WatchDummy::(PhantomData) - .validate_only(Some(1).into(), &call, &info, 250) + .validate_only(Some(1).into(), &call, &info, 250, External, 0) .unwrap_err(), InvalidTransaction::ExhaustsResources.into(), ); diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index fa376b4f9136..87485aa08ef0 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/examples/default-config/src/lib.rs b/substrate/frame/examples/default-config/src/lib.rs index ccdcd4968598..f690bffe0998 100644 --- a/substrate/frame/examples/default-config/src/lib.rs +++ b/substrate/frame/examples/default-config/src/lib.rs @@ -62,10 +62,10 @@ pub mod pallet { type OverwrittenDefaultValue: Get; /// An input parameter that relies on `::AccountId`. This can - /// too have a default, as long as as it is present in `frame_system::DefaultConfig`. + /// too have a default, as long as it is present in `frame_system::DefaultConfig`. type CanDeriveDefaultFromSystem: Get; - /// We might chose to declare as one that doesn't have a default, for whatever semantical + /// We might choose to declare as one that doesn't have a default, for whatever semantical /// reason. #[pallet::no_default] type HasNoDefault: Get; diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index 6625fb3a5851..7589abb929d5 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-balances = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/examples/multi-block-migrations/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml index 98569964a9c9..6e8e89784266 100644 --- a/substrate/frame/examples/multi-block-migrations/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -pallet-migrations = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } log = { workspace = true } +pallet-migrations = { workspace = true } scale-info = { workspace = true } sp-io = { workspace = true } diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs index 6a5cf2ac5936..a436d6a8ab40 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs @@ -33,7 +33,7 @@ // --pallet // pallet_example_mbm // --extrinsic -// +// // --template // substrate/.maintain/frame-weight-template.hbs // --output diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index a5664dd912d4..fabdfb0f9e0c 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } lite-json = { workspace = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-keystore = { optional = true, workspace = true } diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index 755beb8b82ec..df5cf02594f6 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -240,7 +240,7 @@ fn should_submit_signed_transaction_on_chain() { let tx = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert!(matches!(tx.preamble, sp_runtime::generic::Preamble::Signed(0, (), 0, (),))); + assert!(matches!(tx.preamble, sp_runtime::generic::Preamble::Signed(0, (), (),))); assert_eq!(tx.function, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); }); } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index 26a3a9fff753..4df8693e0f37 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -13,18 +13,18 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -docify = { workspace = true } -log = { workspace = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } -frame-support = { workspace = true } +docify = { workspace = true } frame-executive = { workspace = true } +frame-support = { workspace = true } frame-system = { workspace = true } frame-try-runtime = { optional = true, workspace = true } +log = { workspace = true } pallet-balances = { workspace = true } -sp-runtime = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } +sp-runtime = { workspace = true } sp-version = { workspace = true } [features] diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index 00695ceddf19..48f4d9e66e9c 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -22,9 +22,9 @@ scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-core = { workspace = true } frame-benchmarking = { optional = true, workspace = true } diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index 76d084f49d9f..ee24a9fef13d 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -20,11 +20,11 @@ aquamarine = { workspace = true } codec = { features = [ "derive", ], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } frame-try-runtime = { optional = true, workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index c1d0e80551c2..98a9655074e7 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -22,23 +22,23 @@ scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +frame-election-provider-support = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-staking = { workspace = true } -frame-election-provider-support = { workspace = true } frame-benchmarking = { optional = true, workspace = true } docify = { workspace = true } [dev-dependencies] +pallet-balances = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } sp-core = { workspace = true } -substrate-test-utils = { workspace = true } sp-tracing = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } +substrate-test-utils = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/fast-unstake/src/benchmarking.rs b/substrate/frame/fast-unstake/src/benchmarking.rs index d01ff715ca4f..750f348c4596 100644 --- a/substrate/frame/fast-unstake/src/benchmarking.rs +++ b/substrate/frame/fast-unstake/src/benchmarking.rs @@ -19,9 +19,9 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{types::*, Pallet as FastUnstake, *}; +use crate::{types::*, *}; use alloc::{vec, vec::Vec}; -use frame_benchmarking::v1::{benchmarks, whitelist_account, BenchmarkError}; +use frame_benchmarking::v2::*; use frame_support::{ assert_ok, traits::{Currency, EnsureOrigin, Get, Hooks}, @@ -89,22 +89,21 @@ fn setup_staking(v: u32, until: EraIndex) { fn on_idle_full_block() { let remaining_weight = ::BlockWeights::get().max_block; - FastUnstake::::on_idle(Zero::zero(), remaining_weight); + Pallet::::on_idle(Zero::zero(), remaining_weight); } -benchmarks! { +#[benchmarks] +mod benchmarks { + use super::*; // on_idle, we don't check anyone, but fully unbond them. - on_idle_unstake { - let b in 1 .. T::BatchSize::get(); - + #[benchmark] + fn on_idle_unstake(b: Linear<1, { T::BatchSize::get() }>) { ErasToCheckPerBlock::::put(1); for who in create_unexposed_batch::(b).into_iter() { - assert_ok!(FastUnstake::::register_fast_unstake( - RawOrigin::Signed(who.clone()).into(), - )); + assert_ok!(Pallet::::register_fast_unstake(RawOrigin::Signed(who.clone()).into(),)); } - // run on_idle once. This will check era 0. + // Run on_idle once. This will check era 0. assert_eq!(Head::::get(), None); on_idle_full_block::(); @@ -116,21 +115,19 @@ benchmarks! { .. }) if checked.len() == 1 && stashes.len() as u32 == b )); + + #[block] + { + on_idle_full_block::(); + } + + assert_eq!(fast_unstake_events::().last(), Some(&Event::BatchFinished { size: b })); } - : { - on_idle_full_block::(); - } - verify { - assert!(matches!( - fast_unstake_events::().last(), - Some(Event::BatchFinished { size: b }) - )); - } - // on_idle, when we check some number of eras and the queue is already set. - on_idle_check { - let v in 1 .. 256; - let b in 1 .. T::BatchSize::get(); + #[benchmark] + fn on_idle_check(v: Linear<1, 256>, b: Linear<1, { T::BatchSize::get() }>) { + // on_idle: When we check some number of eras and the queue is already set. + let u = T::MaxErasToCheckPerBlock::get().min(T::Staking::bonding_duration()); ErasToCheckPerBlock::::put(u); @@ -139,64 +136,73 @@ benchmarks! { // setup staking with v validators and u eras of data (0..=u+1) setup_staking::(v, u); - let stashes = create_unexposed_batch::(b).into_iter().map(|s| { - assert_ok!(FastUnstake::::register_fast_unstake( - RawOrigin::Signed(s.clone()).into(), - )); - (s, T::Deposit::get()) - }).collect::>(); + let stashes = create_unexposed_batch::(b) + .into_iter() + .map(|s| { + assert_ok!( + Pallet::::register_fast_unstake(RawOrigin::Signed(s.clone()).into(),) + ); + (s, T::Deposit::get()) + }) + .collect::>(); // no one is queued thus far. assert_eq!(Head::::get(), None); - Head::::put(UnstakeRequest { stashes: stashes.clone().try_into().unwrap(), checked: Default::default() }); - } - : { - on_idle_full_block::(); - } - verify { + Head::::put(UnstakeRequest { + stashes: stashes.clone().try_into().unwrap(), + checked: Default::default(), + }); + + #[block] + { + on_idle_full_block::(); + } + let checked = (1..=u).rev().collect::>(); let request = Head::::get().unwrap(); assert_eq!(checked, request.checked.into_inner()); - assert!(matches!( - fast_unstake_events::().last(), - Some(Event::BatchChecked { .. }) - )); + assert!(matches!(fast_unstake_events::().last(), Some(Event::BatchChecked { .. }))); assert!(stashes.iter().all(|(s, _)| request.stashes.iter().any(|(ss, _)| ss == s))); } - register_fast_unstake { + #[benchmark] + fn register_fast_unstake() { ErasToCheckPerBlock::::put(1); let who = create_unexposed_batch::(1).get(0).cloned().unwrap(); whitelist_account!(who); assert_eq!(Queue::::count(), 0); - } - :_(RawOrigin::Signed(who.clone())) - verify { + #[extrinsic_call] + _(RawOrigin::Signed(who.clone())); + assert_eq!(Queue::::count(), 1); } - deregister { + #[benchmark] + fn deregister() { ErasToCheckPerBlock::::put(1); let who = create_unexposed_batch::(1).get(0).cloned().unwrap(); - assert_ok!(FastUnstake::::register_fast_unstake( - RawOrigin::Signed(who.clone()).into(), - )); + assert_ok!(Pallet::::register_fast_unstake(RawOrigin::Signed(who.clone()).into(),)); assert_eq!(Queue::::count(), 1); whitelist_account!(who); - } - :_(RawOrigin::Signed(who.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(who.clone())); + assert_eq!(Queue::::count(), 0); } - control { + #[benchmark] + fn control() -> Result<(), BenchmarkError> { let origin = ::ControlOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, T::MaxErasToCheckPerBlock::get()); + + Ok(()) } - : _(origin, T::MaxErasToCheckPerBlock::get()) - verify {} - impl_benchmark_test_suite!(Pallet, crate::mock::ExtBuilder::default().build(), crate::mock::Runtime) + impl_benchmark_test_suite!(Pallet, mock::ExtBuilder::default().build(), mock::Runtime); } diff --git a/substrate/frame/fast-unstake/src/weights.rs b/substrate/frame/fast-unstake/src/weights.rs index dc875e93229e..efa2a67ae35d 100644 --- a/substrate/frame/fast-unstake/src/weights.rs +++ b/substrate/frame/fast-unstake/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_fast_unstake` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -79,6 +79,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:64 w:64) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:64 w:64) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:64 w:64) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:64 w:0) @@ -94,16 +96,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1475 + b * (452 ±0)` + // Measured: `1575 + b * (452 ±0)` // Estimated: `7253 + b * (3774 ±0)` - // Minimum execution time: 84_536_000 picoseconds. - Weight::from_parts(41_949_894, 7253) - // Standard Error: 28_494 - .saturating_add(Weight::from_parts(52_945_820, 0).saturating_mul(b.into())) + // Minimum execution time: 99_430_000 picoseconds. + Weight::from_parts(47_845_798, 7253) + // Standard Error: 35_454 + .saturating_add(Weight::from_parts(61_016_013, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().reads((9_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) } /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) @@ -126,14 +128,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1879 + b * (55 ±0) + v * (10055 ±0)` + // Measured: `1912 + b * (55 ±0) + v * (10055 ±0)` // Estimated: `7253 + b * (56 ±0) + v * (12531 ±0)` - // Minimum execution time: 1_745_807_000 picoseconds. - Weight::from_parts(1_757_648_000, 7253) - // Standard Error: 12_994_693 - .saturating_add(Weight::from_parts(416_410_247, 0).saturating_mul(v.into())) - // Standard Error: 51_993_247 - .saturating_add(Weight::from_parts(1_654_551_441, 0).saturating_mul(b.into())) + // Minimum execution time: 1_839_591_000 picoseconds. + Weight::from_parts(1_849_618_000, 7253) + // Standard Error: 13_246_289 + .saturating_add(Weight::from_parts(424_466_486, 0).saturating_mul(v.into())) + // Standard Error: 52_999_911 + .saturating_add(Weight::from_parts(1_664_762_641, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -164,6 +166,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -172,11 +176,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn register_fast_unstake() -> Weight { // Proof Size summary in bytes: - // Measured: `1955` + // Measured: `2020` // Estimated: `7253` - // Minimum execution time: 136_437_000 picoseconds. - Weight::from_parts(138_827_000, 7253) - .saturating_add(T::DbWeight::get().reads(15_u64)) + // Minimum execution time: 151_529_000 picoseconds. + Weight::from_parts(155_498_000, 7253) + .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) @@ -193,10 +197,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `1350` + // Measured: `1383` // Estimated: `7253` - // Minimum execution time: 45_337_000 picoseconds. - Weight::from_parts(47_359_000, 7253) + // Minimum execution time: 55_859_000 picoseconds. + Weight::from_parts(56_949_000, 7253) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -206,8 +210,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_258_000 picoseconds. - Weight::from_parts(2_406_000, 0) + // Minimum execution time: 2_226_000 picoseconds. + Weight::from_parts(2_356_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -232,6 +236,8 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:64 w:64) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:64 w:64) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:64 w:64) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:64 w:0) @@ -247,16 +253,16 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1475 + b * (452 ±0)` + // Measured: `1575 + b * (452 ±0)` // Estimated: `7253 + b * (3774 ±0)` - // Minimum execution time: 84_536_000 picoseconds. - Weight::from_parts(41_949_894, 7253) - // Standard Error: 28_494 - .saturating_add(Weight::from_parts(52_945_820, 0).saturating_mul(b.into())) + // Minimum execution time: 99_430_000 picoseconds. + Weight::from_parts(47_845_798, 7253) + // Standard Error: 35_454 + .saturating_add(Weight::from_parts(61_016_013, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((8_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().reads((9_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().writes((6_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) } /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) @@ -279,14 +285,14 @@ impl WeightInfo for () { /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1879 + b * (55 ±0) + v * (10055 ±0)` + // Measured: `1912 + b * (55 ±0) + v * (10055 ±0)` // Estimated: `7253 + b * (56 ±0) + v * (12531 ±0)` - // Minimum execution time: 1_745_807_000 picoseconds. - Weight::from_parts(1_757_648_000, 7253) - // Standard Error: 12_994_693 - .saturating_add(Weight::from_parts(416_410_247, 0).saturating_mul(v.into())) - // Standard Error: 51_993_247 - .saturating_add(Weight::from_parts(1_654_551_441, 0).saturating_mul(b.into())) + // Minimum execution time: 1_839_591_000 picoseconds. + Weight::from_parts(1_849_618_000, 7253) + // Standard Error: 13_246_289 + .saturating_add(Weight::from_parts(424_466_486, 0).saturating_mul(v.into())) + // Standard Error: 52_999_911 + .saturating_add(Weight::from_parts(1_664_762_641, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -317,6 +323,8 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -325,11 +333,11 @@ impl WeightInfo for () { /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn register_fast_unstake() -> Weight { // Proof Size summary in bytes: - // Measured: `1955` + // Measured: `2020` // Estimated: `7253` - // Minimum execution time: 136_437_000 picoseconds. - Weight::from_parts(138_827_000, 7253) - .saturating_add(RocksDbWeight::get().reads(15_u64)) + // Minimum execution time: 151_529_000 picoseconds. + Weight::from_parts(155_498_000, 7253) + .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) @@ -346,10 +354,10 @@ impl WeightInfo for () { /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `1350` + // Measured: `1383` // Estimated: `7253` - // Minimum execution time: 45_337_000 picoseconds. - Weight::from_parts(47_359_000, 7253) + // Minimum execution time: 55_859_000 picoseconds. + Weight::from_parts(56_949_000, 7253) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -359,8 +367,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_258_000 picoseconds. - Weight::from_parts(2_406_000, 0) + // Minimum execution time: 2_226_000 picoseconds. + Weight::from_parts(2_356_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 6717176ffc95..317a9ea8b760 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -18,15 +18,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blake2 = { workspace = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } -log = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } +sp-inherents = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-inherents = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } diff --git a/substrate/frame/glutton/src/weights.rs b/substrate/frame/glutton/src/weights.rs index d9e6ebd9d8a9..825ab922408f 100644 --- a/substrate/frame/glutton/src/weights.rs +++ b/substrate/frame/glutton/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_glutton` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -72,12 +72,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `86` + // Measured: `113` // Estimated: `1489` - // Minimum execution time: 8_453_000 picoseconds. - Weight::from_parts(5_470_386, 1489) - // Standard Error: 4_723 - .saturating_add(Weight::from_parts(10_418_732, 0).saturating_mul(n.into())) + // Minimum execution time: 9_697_000 picoseconds. + Weight::from_parts(9_901_000, 1489) + // Standard Error: 4_104 + .saturating_add(Weight::from_parts(10_452_607, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -89,12 +89,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `119` + // Measured: `146` // Estimated: `1489` - // Minimum execution time: 8_646_000 picoseconds. - Weight::from_parts(7_948_965, 1489) - // Standard Error: 2_154 - .saturating_add(Weight::from_parts(1_197_352, 0).saturating_mul(n.into())) + // Minimum execution time: 9_630_000 picoseconds. + Weight::from_parts(9_800_000, 1489) + // Standard Error: 1_222 + .saturating_add(Weight::from_parts(1_172_845, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -104,22 +104,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 643_000 picoseconds. - Weight::from_parts(4_035_744, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(105_406, 0).saturating_mul(i.into())) + // Minimum execution time: 666_000 picoseconds. + Weight::from_parts(1_717_806, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(106_571, 0).saturating_mul(i.into())) } /// Storage: `Glutton::TrashData` (r:5000 w:0) /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5000]`. fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `119114 + i * (1022 ±0)` + // Measured: `119141 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 228_000 picoseconds. - Weight::from_parts(62_060_711, 990) - // Standard Error: 5_638 - .saturating_add(Weight::from_parts(5_970_065, 0).saturating_mul(i.into())) + // Minimum execution time: 408_000 picoseconds. + Weight::from_parts(389_107_502, 990) + // Standard Error: 8_027 + .saturating_add(Weight::from_parts(7_091_830, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } @@ -131,10 +131,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `1900497` + // Measured: `1900524` // Estimated: `5239782` - // Minimum execution time: 57_557_511_000 picoseconds. - Weight::from_parts(57_644_868_000, 5239782) + // Minimum execution time: 58_810_751_000 picoseconds. + Weight::from_parts(59_238_169_000, 5239782) .saturating_add(T::DbWeight::get().reads(1739_u64)) } /// Storage: `Glutton::Storage` (r:1 w:0) @@ -145,10 +145,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `9547` + // Measured: `9574` // Estimated: `16070` - // Minimum execution time: 101_362_469_000 picoseconds. - Weight::from_parts(101_583_065_000, 16070) + // Minimum execution time: 100_387_946_000 picoseconds. + Weight::from_parts(100_470_819_000, 16070) .saturating_add(T::DbWeight::get().reads(7_u64)) } /// Storage: `Glutton::Storage` (r:1 w:0) @@ -157,10 +157,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn empty_on_idle() -> Weight { // Proof Size summary in bytes: - // Measured: `86` + // Measured: `113` // Estimated: `1493` - // Minimum execution time: 5_118_000 picoseconds. - Weight::from_parts(5_320_000, 1493) + // Minimum execution time: 6_587_000 picoseconds. + Weight::from_parts(6_835_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Glutton::Compute` (r:0 w:1) @@ -169,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_925_000 picoseconds. - Weight::from_parts(6_193_000, 0) + // Minimum execution time: 5_238_000 picoseconds. + Weight::from_parts(5_466_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Glutton::Storage` (r:0 w:1) @@ -179,8 +179,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_912_000 picoseconds. - Weight::from_parts(6_170_000, 0) + // Minimum execution time: 5_136_000 picoseconds. + Weight::from_parts(5_437_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -194,12 +194,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `86` + // Measured: `113` // Estimated: `1489` - // Minimum execution time: 8_453_000 picoseconds. - Weight::from_parts(5_470_386, 1489) - // Standard Error: 4_723 - .saturating_add(Weight::from_parts(10_418_732, 0).saturating_mul(n.into())) + // Minimum execution time: 9_697_000 picoseconds. + Weight::from_parts(9_901_000, 1489) + // Standard Error: 4_104 + .saturating_add(Weight::from_parts(10_452_607, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -211,12 +211,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `119` + // Measured: `146` // Estimated: `1489` - // Minimum execution time: 8_646_000 picoseconds. - Weight::from_parts(7_948_965, 1489) - // Standard Error: 2_154 - .saturating_add(Weight::from_parts(1_197_352, 0).saturating_mul(n.into())) + // Minimum execution time: 9_630_000 picoseconds. + Weight::from_parts(9_800_000, 1489) + // Standard Error: 1_222 + .saturating_add(Weight::from_parts(1_172_845, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -226,22 +226,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 643_000 picoseconds. - Weight::from_parts(4_035_744, 0) - // Standard Error: 14 - .saturating_add(Weight::from_parts(105_406, 0).saturating_mul(i.into())) + // Minimum execution time: 666_000 picoseconds. + Weight::from_parts(1_717_806, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(106_571, 0).saturating_mul(i.into())) } /// Storage: `Glutton::TrashData` (r:5000 w:0) /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5000]`. fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `119114 + i * (1022 ±0)` + // Measured: `119141 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 228_000 picoseconds. - Weight::from_parts(62_060_711, 990) - // Standard Error: 5_638 - .saturating_add(Weight::from_parts(5_970_065, 0).saturating_mul(i.into())) + // Minimum execution time: 408_000 picoseconds. + Weight::from_parts(389_107_502, 990) + // Standard Error: 8_027 + .saturating_add(Weight::from_parts(7_091_830, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } @@ -253,10 +253,10 @@ impl WeightInfo for () { /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `1900497` + // Measured: `1900524` // Estimated: `5239782` - // Minimum execution time: 57_557_511_000 picoseconds. - Weight::from_parts(57_644_868_000, 5239782) + // Minimum execution time: 58_810_751_000 picoseconds. + Weight::from_parts(59_238_169_000, 5239782) .saturating_add(RocksDbWeight::get().reads(1739_u64)) } /// Storage: `Glutton::Storage` (r:1 w:0) @@ -267,10 +267,10 @@ impl WeightInfo for () { /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: - // Measured: `9547` + // Measured: `9574` // Estimated: `16070` - // Minimum execution time: 101_362_469_000 picoseconds. - Weight::from_parts(101_583_065_000, 16070) + // Minimum execution time: 100_387_946_000 picoseconds. + Weight::from_parts(100_470_819_000, 16070) .saturating_add(RocksDbWeight::get().reads(7_u64)) } /// Storage: `Glutton::Storage` (r:1 w:0) @@ -279,10 +279,10 @@ impl WeightInfo for () { /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn empty_on_idle() -> Weight { // Proof Size summary in bytes: - // Measured: `86` + // Measured: `113` // Estimated: `1493` - // Minimum execution time: 5_118_000 picoseconds. - Weight::from_parts(5_320_000, 1493) + // Minimum execution time: 6_587_000 picoseconds. + Weight::from_parts(6_835_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Glutton::Compute` (r:0 w:1) @@ -291,8 +291,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_925_000 picoseconds. - Weight::from_parts(6_193_000, 0) + // Minimum execution time: 5_238_000 picoseconds. + Weight::from_parts(5_466_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Glutton::Storage` (r:0 w:1) @@ -301,8 +301,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_912_000 picoseconds. - Weight::from_parts(6_170_000, 0) + // Minimum execution time: 5_136_000 picoseconds. + Weight::from_parts(5_437_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index 86ace358d05d..4072d65b6267 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -17,13 +17,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-authorship = { workspace = true } pallet-session = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } sp-application-crypto = { features = ["serde"], workspace = true } sp-consensus-grandpa = { features = ["serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index cf4c29003a71..87369c23948c 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -297,7 +297,7 @@ pub fn start_session(session_index: SessionIndex) { pub fn start_era(era_index: EraIndex) { start_session((era_index * 3).into()); - assert_eq!(Staking::current_era(), Some(era_index)); + assert_eq!(pallet_staking::CurrentEra::::get(), Some(era_index)); } pub fn initialize_block(number: u64, parent_hash: H256) { diff --git a/substrate/frame/grandpa/src/tests.rs b/substrate/frame/grandpa/src/tests.rs index e1e963ce564a..383f77f00de7 100644 --- a/substrate/frame/grandpa/src/tests.rs +++ b/substrate/frame/grandpa/src/tests.rs @@ -319,7 +319,7 @@ fn report_equivocation_current_set_works() { let authorities = test_authorities(); new_test_ext_raw_authorities(authorities).execute_with(|| { - assert_eq!(Staking::current_era(), Some(0)); + assert_eq!(pallet_staking::CurrentEra::::get(), Some(0)); assert_eq!(Session::current_index(), 0); start_era(1); diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index bf974221b857..4ea7f797d9ee 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive", "max-encoded-len"], workspace = true } enumflags2 = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 11b43f958c4e..6a71e831cca1 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -421,6 +421,10 @@ pub mod pallet { RegistrarAdded { registrar_index: RegistrarIndex }, /// A sub-identity was added to an identity and the deposit paid. SubIdentityAdded { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf }, + /// An account's sub-identities were set (in bulk). + SubIdentitiesSet { main: T::AccountId, number_of_subs: u32, new_deposit: BalanceOf }, + /// A given sub-account's associated name was changed by its super-identity. + SubIdentityRenamed { sub: T::AccountId, main: T::AccountId }, /// A sub-identity was removed from an identity and the deposit freed. SubIdentityRemoved { sub: T::AccountId, main: T::AccountId, deposit: BalanceOf }, /// A sub-identity was cleared, and the given deposit repatriated from the @@ -591,6 +595,12 @@ pub mod pallet { SubsOf::::insert(&sender, (new_deposit, ids)); } + Self::deposit_event(Event::SubIdentitiesSet { + main: sender, + number_of_subs: new_subs as u32, + new_deposit, + }); + Ok(Some( T::WeightInfo::set_subs_old(old_ids.len() as u32) // P: Real number of old accounts removed. // S: New subs added @@ -992,7 +1002,9 @@ pub mod pallet { let sub = T::Lookup::lookup(sub)?; ensure!(IdentityOf::::contains_key(&sender), Error::::NoIdentity); ensure!(SuperOf::::get(&sub).map_or(false, |x| x.0 == sender), Error::::NotOwned); - SuperOf::::insert(&sub, (sender, data)); + SuperOf::::insert(&sub, (&sender, data)); + + Self::deposit_event(Event::SubIdentityRenamed { main: sender, sub }); Ok(()) } diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index a095085a8188..7bf5b2a72760 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -273,6 +273,10 @@ fn editing_subaccounts_should_work() { // rename first sub account assert_ok!(Identity::rename_sub(RuntimeOrigin::signed(ten.clone()), one.clone(), data(11))); + System::assert_last_event(tests::RuntimeEvent::Identity(Event::SubIdentityRenamed { + main: ten.clone(), + sub: one.clone(), + })); assert_eq!(SuperOf::::get(one.clone()), Some((ten.clone(), data(11)))); assert_eq!(SuperOf::::get(two.clone()), Some((ten.clone(), data(2)))); assert_eq!(Balances::free_balance(ten.clone()), 1000 - id_deposit - 2 * sub_deposit); @@ -546,6 +550,13 @@ fn setting_subaccounts_should_work() { assert_ok!(Identity::set_identity(RuntimeOrigin::signed(ten.clone()), Box::new(ten_info))); assert_eq!(Balances::free_balance(ten.clone()), 1000 - id_deposit); assert_ok!(Identity::set_subs(RuntimeOrigin::signed(ten.clone()), subs.clone())); + + System::assert_last_event(tests::RuntimeEvent::Identity(Event::SubIdentitiesSet { + main: ten.clone(), + number_of_subs: 1, + new_deposit: sub_deposit, + })); + assert_eq!(Balances::free_balance(ten.clone()), 1000 - id_deposit - sub_deposit); assert_eq!( SubsOf::::get(ten.clone()), diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index a74cca9dc8ec..f1ede9213280 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_identity` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -69,13 +69,13 @@ pub trait WeightInfo { fn quit_sub(s: u32, ) -> Weight; fn add_username_authority() -> Weight; fn remove_username_authority() -> Weight; - fn set_username_for(p: u32) -> Weight; + fn set_username_for(p: u32, ) -> Weight; fn accept_username() -> Weight; - fn remove_expired_approval(p: u32) -> Weight; + fn remove_expired_approval(p: u32, ) -> Weight; fn set_primary_username() -> Weight; fn unbind_username() -> Weight; fn remove_username() -> Weight; - fn kill_username(p: u32) -> Weight; + fn kill_username(p: u32, ) -> Weight; fn migration_v2_authority_step() -> Weight; fn migration_v2_username_step() -> Weight; fn migration_v2_identity_step() -> Weight; @@ -94,29 +94,29 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_696_000 picoseconds. - Weight::from_parts(9_620_793, 2626) - // Standard Error: 1_909 - .saturating_add(Weight::from_parts(94_977, 0).saturating_mul(r.into())) + // Minimum execution time: 9_510_000 picoseconds. + Weight::from_parts(10_180_808, 2626) + // Standard Error: 1_519 + .saturating_add(Weight::from_parts(97_439, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6978 + r * (5 ±0)` - // Estimated: `11037` - // Minimum execution time: 110_950_000 picoseconds. - Weight::from_parts(112_705_139, 11037) - // Standard Error: 6_475 - .saturating_add(Weight::from_parts(212_737, 0).saturating_mul(r.into())) + // Measured: `6977 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 121_544_000 picoseconds. + Weight::from_parts(123_405_465, 11003) + // Standard Error: 10_028 + .saturating_add(Weight::from_parts(280_726, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:100 w:100) @@ -125,11 +125,11 @@ impl WeightInfo for SubstrateWeight { fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11037 + s * (2589 ±0)` - // Minimum execution time: 9_440_000 picoseconds. - Weight::from_parts(23_266_871, 11037) - // Standard Error: 10_640 - .saturating_add(Weight::from_parts(3_663_971, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 13_867_000 picoseconds. + Weight::from_parts(26_900_535, 11003) + // Standard Error: 5_334 + .saturating_add(Weight::from_parts(3_798_050, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -137,7 +137,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:0 w:100) @@ -146,11 +146,11 @@ impl WeightInfo for SubstrateWeight { fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 9_588_000 picoseconds. - Weight::from_parts(22_403_362, 11037) - // Standard Error: 3_359 - .saturating_add(Weight::from_parts(1_557_280, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 13_911_000 picoseconds. + Weight::from_parts(31_349_327, 11003) + // Standard Error: 4_045 + .saturating_add(Weight::from_parts(1_503_129, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -158,21 +158,21 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:0 w:100) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 55_387_000 picoseconds. - Weight::from_parts(52_575_769, 11037) - // Standard Error: 17_705 - .saturating_add(Weight::from_parts(268_160, 0).saturating_mul(r.into())) - // Standard Error: 3_454 - .saturating_add(Weight::from_parts(1_576_194, 0).saturating_mul(s.into())) + // Measured: `7069 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11003` + // Minimum execution time: 61_520_000 picoseconds. + Weight::from_parts(63_655_763, 11003) + // Standard Error: 12_100 + .saturating_add(Weight::from_parts(174_203, 0).saturating_mul(r.into())) + // Standard Error: 2_361 + .saturating_add(Weight::from_parts(1_480_283, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -180,30 +180,30 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Identity::Registrars` (r:1 w:0) /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6968 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 78_243_000 picoseconds. - Weight::from_parts(80_404_226, 11037) - // Standard Error: 5_153 - .saturating_add(Weight::from_parts(149_799, 0).saturating_mul(r.into())) + // Measured: `6967 + r * (57 ±0)` + // Estimated: `11003` + // Minimum execution time: 85_411_000 picoseconds. + Weight::from_parts(87_137_905, 11003) + // Standard Error: 5_469 + .saturating_add(Weight::from_parts(189_201, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6999` - // Estimated: `11037` - // Minimum execution time: 73_360_000 picoseconds. - Weight::from_parts(76_216_374, 11037) - // Standard Error: 15_603 - .saturating_add(Weight::from_parts(189_080, 0).saturating_mul(r.into())) + // Measured: `6998` + // Estimated: `11003` + // Minimum execution time: 83_034_000 picoseconds. + Weight::from_parts(84_688_145, 11003) + // Standard Error: 4_493 + .saturating_add(Weight::from_parts(126_412, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -214,10 +214,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_287_000 picoseconds. - Weight::from_parts(6_721_854, 2626) - // Standard Error: 1_488 - .saturating_add(Weight::from_parts(96_288, 0).saturating_mul(r.into())) + // Minimum execution time: 6_984_000 picoseconds. + Weight::from_parts(7_653_398, 2626) + // Standard Error: 1_328 + .saturating_add(Weight::from_parts(83_290, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -228,10 +228,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_441_000 picoseconds. - Weight::from_parts(6_864_863, 2626) - // Standard Error: 1_403 - .saturating_add(Weight::from_parts(85_123, 0).saturating_mul(r.into())) + // Minimum execution time: 10_608_000 picoseconds. + Weight::from_parts(11_047_553, 2626) + // Standard Error: 1_253 + .saturating_add(Weight::from_parts(76_665, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -242,33 +242,33 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_249_000 picoseconds. - Weight::from_parts(6_658_251, 2626) - // Standard Error: 1_443 - .saturating_add(Weight::from_parts(92_586, 0).saturating_mul(r.into())) + // Minimum execution time: 10_291_000 picoseconds. + Weight::from_parts(10_787_424, 2626) + // Standard Error: 1_267 + .saturating_add(Weight::from_parts(88_833, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Identity::Registrars` (r:1 w:0) /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7046 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 97_969_000 picoseconds. - Weight::from_parts(101_366_385, 11037) - // Standard Error: 19_594 - .saturating_add(Weight::from_parts(103_251, 0).saturating_mul(r.into())) + // Measured: `7045 + r * (57 ±0)` + // Estimated: `11003` + // Minimum execution time: 105_178_000 picoseconds. + Weight::from_parts(107_276_823, 11003) + // Standard Error: 7_063 + .saturating_add(Weight::from_parts(149_499, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:0 w:100) @@ -277,20 +277,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 73_785_000 picoseconds. - Weight::from_parts(73_606_063, 11037) - // Standard Error: 26_433 - .saturating_add(Weight::from_parts(230_018, 0).saturating_mul(r.into())) - // Standard Error: 5_157 - .saturating_add(Weight::from_parts(1_483_326, 0).saturating_mul(s.into())) + // Measured: `7276 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11003` + // Minimum execution time: 76_175_000 picoseconds. + Weight::from_parts(77_692_045, 11003) + // Standard Error: 14_176 + .saturating_add(Weight::from_parts(201_431, 0).saturating_mul(r.into())) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(1_499_834, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:1 w:1) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) @@ -299,32 +299,32 @@ impl WeightInfo for SubstrateWeight { fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11037` - // Minimum execution time: 27_304_000 picoseconds. - Weight::from_parts(31_677_329, 11037) - // Standard Error: 1_388 - .saturating_add(Weight::from_parts(102_193, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 29_756_000 picoseconds. + Weight::from_parts(38_457_195, 11003) + // Standard Error: 2_153 + .saturating_add(Weight::from_parts(114_749, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:1 w:1) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `11037` - // Minimum execution time: 12_925_000 picoseconds. - Weight::from_parts(14_756_477, 11037) - // Standard Error: 646 - .saturating_add(Weight::from_parts(36_734, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 21_627_000 picoseconds. + Weight::from_parts(24_786_470, 11003) + // Standard Error: 837 + .saturating_add(Weight::from_parts(63_553, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:1 w:1) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) @@ -333,11 +333,11 @@ impl WeightInfo for SubstrateWeight { fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11037` - // Minimum execution time: 30_475_000 picoseconds. - Weight::from_parts(33_821_774, 11037) - // Standard Error: 1_012 - .saturating_add(Weight::from_parts(87_704, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 37_768_000 picoseconds. + Weight::from_parts(41_759_997, 11003) + // Standard Error: 1_157 + .saturating_add(Weight::from_parts(97_679, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -352,116 +352,225 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 22_841_000 picoseconds. - Weight::from_parts(25_781_412, 6723) - // Standard Error: 1_145 - .saturating_add(Weight::from_parts(84_692, 0).saturating_mul(s.into())) + // Minimum execution time: 29_539_000 picoseconds. + Weight::from_parts(31_966_337, 6723) + // Standard Error: 1_076 + .saturating_add(Weight::from_parts(94_311, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) - /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:0 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn add_username_authority() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_983_000 picoseconds. - Weight::from_parts(7_388_000, 0) + // Minimum execution time: 6_783_000 picoseconds. + Weight::from_parts(7_098_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) - /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `80` + // Measured: `79` // Estimated: `3517` - // Minimum execution time: 9_717_000 picoseconds. - Weight::from_parts(10_322_000, 3517) + // Minimum execution time: 10_772_000 picoseconds. + Weight::from_parts(11_136_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) - /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:1 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) /// Storage: `Identity::PendingUsernames` (r:1 w:0) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for(_p: u32) -> Weight { + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 1]`. + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `11037` - // Minimum execution time: 70_714_000 picoseconds. - Weight::from_parts(74_990_000, 11037) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `181` + // Estimated: `3593` + // Minimum execution time: 68_832_000 picoseconds. + Weight::from_parts(91_310_781, 3593) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::AccountOfUsername` (r:0 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:0 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `11037` - // Minimum execution time: 21_996_000 picoseconds. - Weight::from_parts(22_611_000, 11037) + // Measured: `116` + // Estimated: `3567` + // Minimum execution time: 21_196_000 picoseconds. + Weight::from_parts(21_755_000, 3567) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval(_p: u32) -> Weight { + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 1]`. + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `3550` - // Minimum execution time: 16_880_000 picoseconds. - Weight::from_parts(28_371_000, 3550) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `309` + // Estimated: `3593` + // Minimum execution time: 19_371_000 picoseconds. + Weight::from_parts(62_390_200, 3593) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:1 w:0) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:0 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `257` - // Estimated: `11037` - // Minimum execution time: 16_771_000 picoseconds. - Weight::from_parts(17_333_000, 11037) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `172` + // Estimated: `3563` + // Minimum execution time: 13_890_000 picoseconds. + Weight::from_parts(14_307_000, 3563) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Identity::UsernameInfoOf` (r:1 w:0) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::UnbindingUsernames` (r:1 w:1) + /// Proof: `Identity::UnbindingUsernames` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn unbind_username() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `236` + // Estimated: `3563` + // Minimum execution time: 22_126_000 picoseconds. + Weight::from_parts(23_177_000, 3563) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Identity::UnbindingUsernames` (r:1 w:1) + /// Proof: `Identity::UnbindingUsernames` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:1 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `297` + // Estimated: `3563` + // Minimum execution time: 27_513_000 picoseconds. + Weight::from_parts(28_389_000, 3563) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - fn kill_username(_p: u32) -> Weight { - Weight::zero() + /// Storage: `Identity::UsernameInfoOf` (r:1 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::UnbindingUsernames` (r:1 w:1) + /// Proof: `Identity::UnbindingUsernames` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 1]`. + fn kill_username(_p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `470` + // Estimated: `3593` + // Minimum execution time: 25_125_000 picoseconds. + Weight::from_parts(55_315_063, 3593) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:2 w:0) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:2 w:0) + /// Storage: `Identity::AuthorityOf` (r:0 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn migration_v2_authority_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `147` + // Estimated: `6087` + // Minimum execution time: 9_218_000 picoseconds. + Weight::from_parts(9_560_000, 6087) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:2 w:0) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:2 w:0) + /// Storage: `Identity::UsernameInfoOf` (r:0 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) fn migration_v2_username_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `159` + // Estimated: `6099` + // Minimum execution time: 9_090_000 picoseconds. + Weight::from_parts(9_456_000, 6099) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Identity::IdentityOf` (r:2 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:0 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn migration_v2_identity_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `7062` + // Estimated: `21016` + // Minimum execution time: 64_909_000 picoseconds. + Weight::from_parts(65_805_000, 21016) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: `Identity::PendingUsernames` (r:2 w:1) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) fn migration_v2_pending_username_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `201` + // Estimated: `6144` + // Minimum execution time: 8_518_000 picoseconds. + Weight::from_parts(8_933_000, 6144) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Identity::AuthorityOf` (r:2 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:1 w:1) fn migration_v2_cleanup_authority_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `288` + // Estimated: `6044` + // Minimum execution time: 16_108_000 picoseconds. + Weight::from_parts(16_597_000, 6044) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Identity::UsernameInfoOf` (r:2 w:0) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:1 w:1) fn migration_v2_cleanup_username_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `290` + // Estimated: `6136` + // Minimum execution time: 11_336_000 picoseconds. + Weight::from_parts(11_938_000, 6136) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -474,29 +583,29 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_696_000 picoseconds. - Weight::from_parts(9_620_793, 2626) - // Standard Error: 1_909 - .saturating_add(Weight::from_parts(94_977, 0).saturating_mul(r.into())) + // Minimum execution time: 9_510_000 picoseconds. + Weight::from_parts(10_180_808, 2626) + // Standard Error: 1_519 + .saturating_add(Weight::from_parts(97_439, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6978 + r * (5 ±0)` - // Estimated: `11037` - // Minimum execution time: 110_950_000 picoseconds. - Weight::from_parts(112_705_139, 11037) - // Standard Error: 6_475 - .saturating_add(Weight::from_parts(212_737, 0).saturating_mul(r.into())) + // Measured: `6977 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 121_544_000 picoseconds. + Weight::from_parts(123_405_465, 11003) + // Standard Error: 10_028 + .saturating_add(Weight::from_parts(280_726, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:100 w:100) @@ -505,11 +614,11 @@ impl WeightInfo for () { fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11037 + s * (2589 ±0)` - // Minimum execution time: 9_440_000 picoseconds. - Weight::from_parts(23_266_871, 11037) - // Standard Error: 10_640 - .saturating_add(Weight::from_parts(3_663_971, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 13_867_000 picoseconds. + Weight::from_parts(26_900_535, 11003) + // Standard Error: 5_334 + .saturating_add(Weight::from_parts(3_798_050, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -517,7 +626,7 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:0 w:100) @@ -526,11 +635,11 @@ impl WeightInfo for () { fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 9_588_000 picoseconds. - Weight::from_parts(22_403_362, 11037) - // Standard Error: 3_359 - .saturating_add(Weight::from_parts(1_557_280, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 13_911_000 picoseconds. + Weight::from_parts(31_349_327, 11003) + // Standard Error: 4_045 + .saturating_add(Weight::from_parts(1_503_129, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) @@ -538,21 +647,21 @@ impl WeightInfo for () { /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:0 w:100) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 55_387_000 picoseconds. - Weight::from_parts(52_575_769, 11037) - // Standard Error: 17_705 - .saturating_add(Weight::from_parts(268_160, 0).saturating_mul(r.into())) - // Standard Error: 3_454 - .saturating_add(Weight::from_parts(1_576_194, 0).saturating_mul(s.into())) + // Measured: `7069 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11003` + // Minimum execution time: 61_520_000 picoseconds. + Weight::from_parts(63_655_763, 11003) + // Standard Error: 12_100 + .saturating_add(Weight::from_parts(174_203, 0).saturating_mul(r.into())) + // Standard Error: 2_361 + .saturating_add(Weight::from_parts(1_480_283, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -560,30 +669,30 @@ impl WeightInfo for () { /// Storage: `Identity::Registrars` (r:1 w:0) /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6968 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 78_243_000 picoseconds. - Weight::from_parts(80_404_226, 11037) - // Standard Error: 5_153 - .saturating_add(Weight::from_parts(149_799, 0).saturating_mul(r.into())) + // Measured: `6967 + r * (57 ±0)` + // Estimated: `11003` + // Minimum execution time: 85_411_000 picoseconds. + Weight::from_parts(87_137_905, 11003) + // Standard Error: 5_469 + .saturating_add(Weight::from_parts(189_201, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6999` - // Estimated: `11037` - // Minimum execution time: 73_360_000 picoseconds. - Weight::from_parts(76_216_374, 11037) - // Standard Error: 15_603 - .saturating_add(Weight::from_parts(189_080, 0).saturating_mul(r.into())) + // Measured: `6998` + // Estimated: `11003` + // Minimum execution time: 83_034_000 picoseconds. + Weight::from_parts(84_688_145, 11003) + // Standard Error: 4_493 + .saturating_add(Weight::from_parts(126_412, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -594,10 +703,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_287_000 picoseconds. - Weight::from_parts(6_721_854, 2626) - // Standard Error: 1_488 - .saturating_add(Weight::from_parts(96_288, 0).saturating_mul(r.into())) + // Minimum execution time: 6_984_000 picoseconds. + Weight::from_parts(7_653_398, 2626) + // Standard Error: 1_328 + .saturating_add(Weight::from_parts(83_290, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -608,10 +717,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_441_000 picoseconds. - Weight::from_parts(6_864_863, 2626) - // Standard Error: 1_403 - .saturating_add(Weight::from_parts(85_123, 0).saturating_mul(r.into())) + // Minimum execution time: 10_608_000 picoseconds. + Weight::from_parts(11_047_553, 2626) + // Standard Error: 1_253 + .saturating_add(Weight::from_parts(76_665, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -622,33 +731,33 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_249_000 picoseconds. - Weight::from_parts(6_658_251, 2626) - // Standard Error: 1_443 - .saturating_add(Weight::from_parts(92_586, 0).saturating_mul(r.into())) + // Minimum execution time: 10_291_000 picoseconds. + Weight::from_parts(10_787_424, 2626) + // Standard Error: 1_267 + .saturating_add(Weight::from_parts(88_833, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Identity::Registrars` (r:1 w:0) /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7046 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 97_969_000 picoseconds. - Weight::from_parts(101_366_385, 11037) - // Standard Error: 19_594 - .saturating_add(Weight::from_parts(103_251, 0).saturating_mul(r.into())) + // Measured: `7045 + r * (57 ±0)` + // Estimated: `11003` + // Minimum execution time: 105_178_000 picoseconds. + Weight::from_parts(107_276_823, 11003) + // Standard Error: 7_063 + .saturating_add(Weight::from_parts(149_499, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:0 w:100) @@ -657,20 +766,20 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 73_785_000 picoseconds. - Weight::from_parts(73_606_063, 11037) - // Standard Error: 26_433 - .saturating_add(Weight::from_parts(230_018, 0).saturating_mul(r.into())) - // Standard Error: 5_157 - .saturating_add(Weight::from_parts(1_483_326, 0).saturating_mul(s.into())) + // Measured: `7276 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11003` + // Minimum execution time: 76_175_000 picoseconds. + Weight::from_parts(77_692_045, 11003) + // Standard Error: 14_176 + .saturating_add(Weight::from_parts(201_431, 0).saturating_mul(r.into())) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(1_499_834, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:1 w:1) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) @@ -679,32 +788,32 @@ impl WeightInfo for () { fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11037` - // Minimum execution time: 27_304_000 picoseconds. - Weight::from_parts(31_677_329, 11037) - // Standard Error: 1_388 - .saturating_add(Weight::from_parts(102_193, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 29_756_000 picoseconds. + Weight::from_parts(38_457_195, 11003) + // Standard Error: 2_153 + .saturating_add(Weight::from_parts(114_749, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:1 w:1) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `11037` - // Minimum execution time: 12_925_000 picoseconds. - Weight::from_parts(14_756_477, 11037) - // Standard Error: 646 - .saturating_add(Weight::from_parts(36_734, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 21_627_000 picoseconds. + Weight::from_parts(24_786_470, 11003) + // Standard Error: 837 + .saturating_add(Weight::from_parts(63_553, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SuperOf` (r:1 w:1) /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) @@ -713,11 +822,11 @@ impl WeightInfo for () { fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11037` - // Minimum execution time: 30_475_000 picoseconds. - Weight::from_parts(33_821_774, 11037) - // Standard Error: 1_012 - .saturating_add(Weight::from_parts(87_704, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 37_768_000 picoseconds. + Weight::from_parts(41_759_997, 11003) + // Standard Error: 1_157 + .saturating_add(Weight::from_parts(97_679, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -732,115 +841,224 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 22_841_000 picoseconds. - Weight::from_parts(25_781_412, 6723) - // Standard Error: 1_145 - .saturating_add(Weight::from_parts(84_692, 0).saturating_mul(s.into())) + // Minimum execution time: 29_539_000 picoseconds. + Weight::from_parts(31_966_337, 6723) + // Standard Error: 1_076 + .saturating_add(Weight::from_parts(94_311, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) - /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:0 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn add_username_authority() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_983_000 picoseconds. - Weight::from_parts(7_388_000, 0) + // Minimum execution time: 6_783_000 picoseconds. + Weight::from_parts(7_098_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) - /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `80` + // Measured: `79` // Estimated: `3517` - // Minimum execution time: 9_717_000 picoseconds. - Weight::from_parts(10_322_000, 3517) + // Minimum execution time: 10_772_000 picoseconds. + Weight::from_parts(11_136_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) - /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:1 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) /// Storage: `Identity::PendingUsernames` (r:1 w:0) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for(_p: u32) -> Weight { + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 1]`. + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `11037` - // Minimum execution time: 70_714_000 picoseconds. - Weight::from_parts(74_990_000, 11037) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `181` + // Estimated: `3593` + // Minimum execution time: 68_832_000 picoseconds. + Weight::from_parts(91_310_781, 3593) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::AccountOfUsername` (r:0 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:0 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `11037` - // Minimum execution time: 21_996_000 picoseconds. - Weight::from_parts(22_611_000, 11037) + // Measured: `116` + // Estimated: `3567` + // Minimum execution time: 21_196_000 picoseconds. + Weight::from_parts(21_755_000, 3567) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval(_p: u32) -> Weight { + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 1]`. + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `3550` - // Minimum execution time: 16_880_000 picoseconds. - Weight::from_parts(28_371_000, 3550) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `309` + // Estimated: `3593` + // Minimum execution time: 19_371_000 picoseconds. + Weight::from_parts(62_390_200, 3593) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:1 w:0) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:0 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `257` - // Estimated: `11037` - // Minimum execution time: 16_771_000 picoseconds. - Weight::from_parts(17_333_000, 11037) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `172` + // Estimated: `3563` + // Minimum execution time: 13_890_000 picoseconds. + Weight::from_parts(14_307_000, 3563) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Identity::UsernameInfoOf` (r:1 w:0) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Identity::UnbindingUsernames` (r:1 w:1) + /// Proof: `Identity::UnbindingUsernames` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) fn unbind_username() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `236` + // Estimated: `3563` + // Minimum execution time: 22_126_000 picoseconds. + Weight::from_parts(23_177_000, 3563) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Identity::UnbindingUsernames` (r:1 w:1) + /// Proof: `Identity::UnbindingUsernames` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameInfoOf` (r:1 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `297` + // Estimated: `3563` + // Minimum execution time: 27_513_000 picoseconds. + Weight::from_parts(28_389_000, 3563) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - fn kill_username(_p: u32) -> Weight { - Weight::zero() + /// Storage: `Identity::UsernameInfoOf` (r:1 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:1 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::UnbindingUsernames` (r:1 w:1) + /// Proof: `Identity::UnbindingUsernames` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: `Identity::AuthorityOf` (r:1 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 1]`. + fn kill_username(_p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `470` + // Estimated: `3593` + // Minimum execution time: 25_125_000 picoseconds. + Weight::from_parts(55_315_063, 3593) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:2 w:0) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:2 w:0) + /// Storage: `Identity::AuthorityOf` (r:0 w:1) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn migration_v2_authority_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `147` + // Estimated: `6087` + // Minimum execution time: 9_218_000 picoseconds. + Weight::from_parts(9_560_000, 6087) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:2 w:0) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:2 w:0) + /// Storage: `Identity::UsernameInfoOf` (r:0 w:1) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) fn migration_v2_username_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `159` + // Estimated: `6099` + // Minimum execution time: 9_090_000 picoseconds. + Weight::from_parts(9_456_000, 6099) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Identity::IdentityOf` (r:2 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Storage: `Identity::UsernameOf` (r:0 w:1) + /// Proof: `Identity::UsernameOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn migration_v2_identity_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `7062` + // Estimated: `21016` + // Minimum execution time: 64_909_000 picoseconds. + Weight::from_parts(65_805_000, 21016) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: `Identity::PendingUsernames` (r:2 w:1) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) fn migration_v2_pending_username_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `201` + // Estimated: `6144` + // Minimum execution time: 8_518_000 picoseconds. + Weight::from_parts(8_933_000, 6144) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Identity::AuthorityOf` (r:2 w:0) + /// Proof: `Identity::AuthorityOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f99622d1423cdd16f5c33e2b531c34a53d` (r:1 w:1) fn migration_v2_cleanup_authority_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `288` + // Estimated: `6044` + // Minimum execution time: 16_108_000 picoseconds. + Weight::from_parts(16_597_000, 6044) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Identity::UsernameInfoOf` (r:2 w:0) + /// Proof: `Identity::UsernameInfoOf` (`max_values`: None, `max_size`: Some(98), added: 2573, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x2aeddc77fe58c98d50bd37f1b90840f97c182fead9255863460affdd63116be3` (r:1 w:1) fn migration_v2_cleanup_username_step() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `290` + // Estimated: `6136` + // Minimum execution time: 11_336_000 picoseconds. + Weight::from_parts(11_938_000, 6136) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 6c32c8ae898e..179c4c3ce3b1 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -17,12 +17,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-authorship = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } sp-application-crypto = { features = ["serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } sp-io = { workspace = true } diff --git a/substrate/frame/im-online/src/benchmarking.rs b/substrate/frame/im-online/src/benchmarking.rs index d8170d4817e3..439720bcab38 100644 --- a/substrate/frame/im-online/src/benchmarking.rs +++ b/substrate/frame/im-online/src/benchmarking.rs @@ -19,9 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; - -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v2::*; use frame_support::{traits::UnfilteredDispatchable, WeakBoundedVec}; use frame_system::RawOrigin; use sp_runtime::{ @@ -29,7 +27,7 @@ use sp_runtime::{ transaction_validity::TransactionSource, }; -use crate::Pallet as ImOnline; +use crate::*; const MAX_KEYS: u32 = 1000; @@ -64,34 +62,55 @@ pub fn create_heartbeat( Ok((input_heartbeat, signature)) } -benchmarks! { - #[extra] - heartbeat { - let k in 1 .. MAX_KEYS; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark(extra)] + fn heartbeat(k: Linear<1, MAX_KEYS>) -> Result<(), BenchmarkError> { let (input_heartbeat, signature) = create_heartbeat::(k)?; - }: _(RawOrigin::None, input_heartbeat, signature) - #[extra] - validate_unsigned { - let k in 1 .. MAX_KEYS; + #[extrinsic_call] + _(RawOrigin::None, input_heartbeat, signature); + + Ok(()) + } + + #[benchmark(extra)] + fn validate_unsigned(k: Linear<1, MAX_KEYS>) -> Result<(), BenchmarkError> { let (input_heartbeat, signature) = create_heartbeat::(k)?; let call = Call::heartbeat { heartbeat: input_heartbeat, signature }; - }: { - ImOnline::::validate_unsigned(TransactionSource::InBlock, &call) - .map_err(<&str>::from)?; + + #[block] + { + Pallet::::validate_unsigned(TransactionSource::InBlock, &call) + .map_err(<&str>::from)?; + } + + Ok(()) } - validate_unsigned_and_then_heartbeat { - let k in 1 .. MAX_KEYS; + #[benchmark] + fn validate_unsigned_and_then_heartbeat(k: Linear<1, MAX_KEYS>) -> Result<(), BenchmarkError> { let (input_heartbeat, signature) = create_heartbeat::(k)?; let call = Call::heartbeat { heartbeat: input_heartbeat, signature }; let call_enc = call.encode(); - }: { - ImOnline::::validate_unsigned(TransactionSource::InBlock, &call).map_err(<&str>::from)?; - as Decode>::decode(&mut &*call_enc) - .expect("call is encoded above, encoding must be correct") - .dispatch_bypass_filter(RawOrigin::None.into())?; + + #[block] + { + Pallet::::validate_unsigned(TransactionSource::InBlock, &call) + .map_err(<&str>::from)?; + as Decode>::decode(&mut &*call_enc) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(RawOrigin::None.into())?; + } + + Ok(()) } - impl_benchmark_test_suite!(ImOnline, crate::mock::new_test_ext(), crate::mock::Runtime); + impl_benchmark_test_suite! { + Pallet, + mock::new_test_ext(), + mock::Runtime + } } diff --git a/substrate/frame/im-online/src/weights.rs b/substrate/frame/im-online/src/weights.rs index 105a36fb209f..6fde451caf9e 100644 --- a/substrate/frame/im-online/src/weights.rs +++ b/substrate/frame/im-online/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_im_online` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -72,10 +72,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `327 + k * (32 ±0)` // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 64_011_000 picoseconds. - Weight::from_parts(80_632_380, 321487) - // Standard Error: 676 - .saturating_add(Weight::from_parts(34_921, 0).saturating_mul(k.into())) + // Minimum execution time: 70_883_000 picoseconds. + Weight::from_parts(93_034_812, 321487) + // Standard Error: 811 + .saturating_add(Weight::from_parts(37_349, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) @@ -99,10 +99,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `327 + k * (32 ±0)` // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 64_011_000 picoseconds. - Weight::from_parts(80_632_380, 321487) - // Standard Error: 676 - .saturating_add(Weight::from_parts(34_921, 0).saturating_mul(k.into())) + // Minimum execution time: 70_883_000 picoseconds. + Weight::from_parts(93_034_812, 321487) + // Standard Error: 811 + .saturating_add(Weight::from_parts(37_349, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index d81b2d5cabf1..a0030b5b0edf 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -17,10 +17,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-keyring = { optional = true, workspace = true } diff --git a/substrate/frame/indices/src/benchmarking.rs b/substrate/frame/indices/src/benchmarking.rs index bd173815cb34..28f5e3bf5cf0 100644 --- a/substrate/frame/indices/src/benchmarking.rs +++ b/substrate/frame/indices/src/benchmarking.rs @@ -19,26 +19,31 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use crate::*; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; -use crate::Pallet as Indices; - const SEED: u32 = 0; -benchmarks! { - claim { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn claim() { let account_index = T::AccountIndex::from(SEED); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - }: _(RawOrigin::Signed(caller.clone()), account_index) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), account_index); + assert_eq!(Accounts::::get(account_index).unwrap().0, caller); } - transfer { + #[benchmark] + fn transfer() -> Result<(), BenchmarkError> { let account_index = T::AccountIndex::from(SEED); // Setup accounts let caller: T::AccountId = whitelisted_caller(); @@ -47,25 +52,33 @@ benchmarks! { let recipient_lookup = T::Lookup::unlookup(recipient.clone()); T::Currency::make_free_balance_be(&recipient, BalanceOf::::max_value()); // Claim the index - Indices::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; - }: _(RawOrigin::Signed(caller.clone()), recipient_lookup, account_index) - verify { + Pallet::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), recipient_lookup, account_index); + assert_eq!(Accounts::::get(account_index).unwrap().0, recipient); + Ok(()) } - free { + #[benchmark] + fn free() -> Result<(), BenchmarkError> { let account_index = T::AccountIndex::from(SEED); // Setup accounts let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Claim the index - Indices::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; - }: _(RawOrigin::Signed(caller.clone()), account_index) - verify { + Pallet::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), account_index); + assert_eq!(Accounts::::get(account_index), None); + Ok(()) } - force_transfer { + #[benchmark] + fn force_transfer() -> Result<(), BenchmarkError> { let account_index = T::AccountIndex::from(SEED); // Setup accounts let original: T::AccountId = account("original", 0, SEED); @@ -74,25 +87,32 @@ benchmarks! { let recipient_lookup = T::Lookup::unlookup(recipient.clone()); T::Currency::make_free_balance_be(&recipient, BalanceOf::::max_value()); // Claim the index - Indices::::claim(RawOrigin::Signed(original).into(), account_index)?; - }: _(RawOrigin::Root, recipient_lookup, account_index, false) - verify { + Pallet::::claim(RawOrigin::Signed(original).into(), account_index)?; + + #[extrinsic_call] + _(RawOrigin::Root, recipient_lookup, account_index, false); + assert_eq!(Accounts::::get(account_index).unwrap().0, recipient); + Ok(()) } - freeze { + #[benchmark] + fn freeze() -> Result<(), BenchmarkError> { let account_index = T::AccountIndex::from(SEED); // Setup accounts let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Claim the index - Indices::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; - }: _(RawOrigin::Signed(caller.clone()), account_index) - verify { + Pallet::::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), account_index); + assert_eq!(Accounts::::get(account_index).unwrap().2, true); + Ok(()) } // TODO in another PR: lookup and unlookup trait weights (not critical) - impl_benchmark_test_suite!(Indices, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, mock::new_test_ext(), mock::Test); } diff --git a/substrate/frame/indices/src/weights.rs b/substrate/frame/indices/src/weights.rs index e1bc90c9b128..567e9bab54bd 100644 --- a/substrate/frame/indices/src/weights.rs +++ b/substrate/frame/indices/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_indices` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -67,8 +67,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3534` - // Minimum execution time: 22_026_000 picoseconds. - Weight::from_parts(22_522_000, 3534) + // Minimum execution time: 23_283_000 picoseconds. + Weight::from_parts(24_326_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -78,10 +78,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `275` + // Measured: `312` // Estimated: `3593` - // Minimum execution time: 34_160_000 picoseconds. - Weight::from_parts(35_138_000, 3593) + // Minimum execution time: 40_906_000 picoseconds. + Weight::from_parts(42_117_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -91,8 +91,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 23_736_000 picoseconds. - Weight::from_parts(24_247_000, 3534) + // Minimum execution time: 27_419_000 picoseconds. + Weight::from_parts(28_544_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -104,8 +104,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `275` // Estimated: `3593` - // Minimum execution time: 25_810_000 picoseconds. - Weight::from_parts(26_335_000, 3593) + // Minimum execution time: 30_098_000 picoseconds. + Weight::from_parts(31_368_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -115,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 24_502_000 picoseconds. - Weight::from_parts(25_425_000, 3534) + // Minimum execution time: 30_356_000 picoseconds. + Weight::from_parts(31_036_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -130,8 +130,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3534` - // Minimum execution time: 22_026_000 picoseconds. - Weight::from_parts(22_522_000, 3534) + // Minimum execution time: 23_283_000 picoseconds. + Weight::from_parts(24_326_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -141,10 +141,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `275` + // Measured: `312` // Estimated: `3593` - // Minimum execution time: 34_160_000 picoseconds. - Weight::from_parts(35_138_000, 3593) + // Minimum execution time: 40_906_000 picoseconds. + Weight::from_parts(42_117_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -154,8 +154,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 23_736_000 picoseconds. - Weight::from_parts(24_247_000, 3534) + // Minimum execution time: 27_419_000 picoseconds. + Weight::from_parts(28_544_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -167,8 +167,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `275` // Estimated: `3593` - // Minimum execution time: 25_810_000 picoseconds. - Weight::from_parts(26_335_000, 3593) + // Minimum execution time: 30_098_000 picoseconds. + Weight::from_parts(31_368_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -178,8 +178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 24_502_000 picoseconds. - Weight::from_parts(25_425_000, 3534) + // Minimum execution time: 30_356_000 picoseconds. + Weight::from_parts(31_036_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index 1a47030812da..1682b52dfbf4 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -17,10 +17,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -safe-mix = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +safe-mix = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index eb6e0b703d08..23eb19c7ffa7 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/lottery/src/weights.rs b/substrate/frame/lottery/src/weights.rs index 0ab7f64509cd..cac6136a9ba9 100644 --- a/substrate/frame/lottery/src/weights.rs +++ b/substrate/frame/lottery/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_lottery` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -82,10 +82,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `492` + // Measured: `526` // Estimated: `3997` - // Minimum execution time: 60_979_000 picoseconds. - Weight::from_parts(63_452_000, 3997) + // Minimum execution time: 67_624_000 picoseconds. + Weight::from_parts(69_671_000, 3997) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -96,10 +96,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_245_000 picoseconds. - Weight::from_parts(6_113_777, 0) - // Standard Error: 3_280 - .saturating_add(Weight::from_parts(349_366, 0).saturating_mul(n.into())) + // Minimum execution time: 4_828_000 picoseconds. + Weight::from_parts(5_618_456, 0) + // Standard Error: 3_095 + .saturating_add(Weight::from_parts(367_041, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Lottery::Lottery` (r:1 w:1) @@ -110,10 +110,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn start_lottery() -> Weight { // Proof Size summary in bytes: - // Measured: `194` + // Measured: `181` // Estimated: `3593` - // Minimum execution time: 29_131_000 picoseconds. - Weight::from_parts(29_722_000, 3593) + // Minimum execution time: 29_189_000 picoseconds. + Weight::from_parts(29_952_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -123,8 +123,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `252` // Estimated: `1514` - // Minimum execution time: 6_413_000 picoseconds. - Weight::from_parts(6_702_000, 1514) + // Minimum execution time: 7_320_000 picoseconds. + Weight::from_parts(7_805_000, 1514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -140,10 +140,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn on_initialize_end() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `677` // Estimated: `6196` - // Minimum execution time: 65_913_000 picoseconds. - Weight::from_parts(66_864_000, 6196) + // Minimum execution time: 72_030_000 picoseconds. + Weight::from_parts(73_116_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -161,10 +161,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `677` // Estimated: `6196` - // Minimum execution time: 66_950_000 picoseconds. - Weight::from_parts(68_405_000, 6196) + // Minimum execution time: 73_263_000 picoseconds. + Weight::from_parts(74_616_000, 6196) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -192,10 +192,10 @@ impl WeightInfo for () { /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `492` + // Measured: `526` // Estimated: `3997` - // Minimum execution time: 60_979_000 picoseconds. - Weight::from_parts(63_452_000, 3997) + // Minimum execution time: 67_624_000 picoseconds. + Weight::from_parts(69_671_000, 3997) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -206,10 +206,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_245_000 picoseconds. - Weight::from_parts(6_113_777, 0) - // Standard Error: 3_280 - .saturating_add(Weight::from_parts(349_366, 0).saturating_mul(n.into())) + // Minimum execution time: 4_828_000 picoseconds. + Weight::from_parts(5_618_456, 0) + // Standard Error: 3_095 + .saturating_add(Weight::from_parts(367_041, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Lottery::Lottery` (r:1 w:1) @@ -220,10 +220,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn start_lottery() -> Weight { // Proof Size summary in bytes: - // Measured: `194` + // Measured: `181` // Estimated: `3593` - // Minimum execution time: 29_131_000 picoseconds. - Weight::from_parts(29_722_000, 3593) + // Minimum execution time: 29_189_000 picoseconds. + Weight::from_parts(29_952_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -233,8 +233,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `252` // Estimated: `1514` - // Minimum execution time: 6_413_000 picoseconds. - Weight::from_parts(6_702_000, 1514) + // Minimum execution time: 7_320_000 picoseconds. + Weight::from_parts(7_805_000, 1514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -250,10 +250,10 @@ impl WeightInfo for () { /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn on_initialize_end() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `677` // Estimated: `6196` - // Minimum execution time: 65_913_000 picoseconds. - Weight::from_parts(66_864_000, 6196) + // Minimum execution time: 72_030_000 picoseconds. + Weight::from_parts(73_116_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -271,10 +271,10 @@ impl WeightInfo for () { /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `677` // Estimated: `6196` - // Minimum execution time: 66_950_000 picoseconds. - Weight::from_parts(68_405_000, 6196) + // Minimum execution time: 73_263_000 picoseconds. + Weight::from_parts(74_616_000, 6196) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 67aa3503ac0a..738d09b4b354 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } sp-io = { workspace = true } sp-runtime = { features = ["serde"], workspace = true } diff --git a/substrate/frame/membership/src/benchmarking.rs b/substrate/frame/membership/src/benchmarking.rs index 515be7eb5386..d752abaae866 100644 --- a/substrate/frame/membership/src/benchmarking.rs +++ b/substrate/frame/membership/src/benchmarking.rs @@ -99,7 +99,7 @@ benchmarks_instance_pallet! { assert!(!Members::::get().contains(&remove)); assert!(Members::::get().contains(&add)); // prime is rejigged - assert!(Prime::::get().is_some() && T::MembershipChanged::get_prime().is_some()); + assert!(Prime::::get().is_some()); #[cfg(test)] crate::mock::clean(); } @@ -119,7 +119,7 @@ benchmarks_instance_pallet! { new_members.sort(); assert_eq!(Members::::get(), new_members); // prime is rejigged - assert!(Prime::::get().is_some() && T::MembershipChanged::get_prime().is_some()); + assert!(Prime::::get().is_some()); #[cfg(test)] crate::mock::clean(); } @@ -157,7 +157,6 @@ benchmarks_instance_pallet! { )); } verify { assert!(Prime::::get().is_some()); - assert!(::get_prime().is_some()); #[cfg(test)] crate::mock::clean(); } diff --git a/substrate/frame/membership/src/weights.rs b/substrate/frame/membership/src/weights.rs index 10e9c9afa582..2185319676c5 100644 --- a/substrate/frame/membership/src/weights.rs +++ b/substrate/frame/membership/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_membership` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -76,10 +76,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `207 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 12_827_000 picoseconds. - Weight::from_parts(13_743_651, 4687) - // Standard Error: 622 - .saturating_add(Weight::from_parts(35_417, 0).saturating_mul(m.into())) + // Minimum execution time: 17_738_000 picoseconds. + Weight::from_parts(18_805_035, 4687) + // Standard Error: 796 + .saturating_add(Weight::from_parts(26_172, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -99,10 +99,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_197_000 picoseconds. - Weight::from_parts(16_172_409, 4687) - // Standard Error: 650 - .saturating_add(Weight::from_parts(35_790, 0).saturating_mul(m.into())) + // Minimum execution time: 20_462_000 picoseconds. + Weight::from_parts(21_560_127, 4687) + // Standard Error: 581 + .saturating_add(Weight::from_parts(18_475, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -122,10 +122,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_558_000 picoseconds. - Weight::from_parts(16_370_827, 4687) - // Standard Error: 603 - .saturating_add(Weight::from_parts(45_739, 0).saturating_mul(m.into())) + // Minimum execution time: 20_345_000 picoseconds. + Weight::from_parts(21_400_566, 4687) + // Standard Error: 711 + .saturating_add(Weight::from_parts(39_733, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -145,10 +145,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_086_000 picoseconds. - Weight::from_parts(16_444_101, 4687) - // Standard Error: 967 - .saturating_add(Weight::from_parts(143_947, 0).saturating_mul(m.into())) + // Minimum execution time: 20_149_000 picoseconds. + Weight::from_parts(21_579_056, 4687) + // Standard Error: 693 + .saturating_add(Weight::from_parts(121_676, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -168,10 +168,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 16_146_000 picoseconds. - Weight::from_parts(17_269_755, 4687) - // Standard Error: 660 - .saturating_add(Weight::from_parts(42_082, 0).saturating_mul(m.into())) + // Minimum execution time: 21_033_000 picoseconds. + Weight::from_parts(21_867_983, 4687) + // Standard Error: 1_003 + .saturating_add(Weight::from_parts(44_414, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -187,10 +187,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `31 + m * (32 ±0)` // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 5_937_000 picoseconds. - Weight::from_parts(6_501_085, 4687) - // Standard Error: 323 - .saturating_add(Weight::from_parts(18_285, 0).saturating_mul(m.into())) + // Minimum execution time: 6_849_000 picoseconds. + Weight::from_parts(7_199_679, 4687) + // Standard Error: 199 + .saturating_add(Weight::from_parts(9_242, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -203,8 +203,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_533_000 picoseconds. - Weight::from_parts(2_807_000, 0) + // Minimum execution time: 2_297_000 picoseconds. + Weight::from_parts(2_540_000, 0) .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -224,10 +224,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `207 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 12_827_000 picoseconds. - Weight::from_parts(13_743_651, 4687) - // Standard Error: 622 - .saturating_add(Weight::from_parts(35_417, 0).saturating_mul(m.into())) + // Minimum execution time: 17_738_000 picoseconds. + Weight::from_parts(18_805_035, 4687) + // Standard Error: 796 + .saturating_add(Weight::from_parts(26_172, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -247,10 +247,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_197_000 picoseconds. - Weight::from_parts(16_172_409, 4687) - // Standard Error: 650 - .saturating_add(Weight::from_parts(35_790, 0).saturating_mul(m.into())) + // Minimum execution time: 20_462_000 picoseconds. + Weight::from_parts(21_560_127, 4687) + // Standard Error: 581 + .saturating_add(Weight::from_parts(18_475, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -270,10 +270,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_558_000 picoseconds. - Weight::from_parts(16_370_827, 4687) - // Standard Error: 603 - .saturating_add(Weight::from_parts(45_739, 0).saturating_mul(m.into())) + // Minimum execution time: 20_345_000 picoseconds. + Weight::from_parts(21_400_566, 4687) + // Standard Error: 711 + .saturating_add(Weight::from_parts(39_733, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -293,10 +293,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_086_000 picoseconds. - Weight::from_parts(16_444_101, 4687) - // Standard Error: 967 - .saturating_add(Weight::from_parts(143_947, 0).saturating_mul(m.into())) + // Minimum execution time: 20_149_000 picoseconds. + Weight::from_parts(21_579_056, 4687) + // Standard Error: 693 + .saturating_add(Weight::from_parts(121_676, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -316,10 +316,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `311 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 16_146_000 picoseconds. - Weight::from_parts(17_269_755, 4687) - // Standard Error: 660 - .saturating_add(Weight::from_parts(42_082, 0).saturating_mul(m.into())) + // Minimum execution time: 21_033_000 picoseconds. + Weight::from_parts(21_867_983, 4687) + // Standard Error: 1_003 + .saturating_add(Weight::from_parts(44_414, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -335,10 +335,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `31 + m * (32 ±0)` // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 5_937_000 picoseconds. - Weight::from_parts(6_501_085, 4687) - // Standard Error: 323 - .saturating_add(Weight::from_parts(18_285, 0).saturating_mul(m.into())) + // Minimum execution time: 6_849_000 picoseconds. + Weight::from_parts(7_199_679, 4687) + // Standard Error: 199 + .saturating_add(Weight::from_parts(9_242, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) @@ -351,8 +351,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_533_000 picoseconds. - Weight::from_parts(2_807_000, 0) + // Minimum execution time: 2_297_000 picoseconds. + Weight::from_parts(2_540_000, 0) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 4daa394a82d7..04f5ab64100d 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -16,11 +16,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-mmr-primitives = { workspace = true } @@ -28,8 +28,8 @@ sp-runtime = { workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } itertools = { workspace = true } +sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index a6de61d70abf..7b0de7c1e4ff 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -13,15 +13,15 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } +environmental = { workspace = true } +log = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } -log = { workspace = true } -environmental = { workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -sp-arithmetic = { workspace = true } sp-weights = { workspace = true } frame-benchmarking = { optional = true, workspace = true } @@ -29,10 +29,10 @@ frame-support = { workspace = true } frame-system = { workspace = true } [dev-dependencies] -sp-crypto-hashing = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } rand_distr = { workspace = true } +sp-crypto-hashing = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/message-queue/src/weights.rs b/substrate/frame/message-queue/src/weights.rs index 46fd52194bf2..7d36cb755106 100644 --- a/substrate/frame/message-queue/src/weights.rs +++ b/substrate/frame/message-queue/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_message_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -74,8 +74,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `301` // Estimated: `6038` - // Minimum execution time: 11_674_000 picoseconds. - Weight::from_parts(12_105_000, 6038) + // Minimum execution time: 17_093_000 picoseconds. + Weight::from_parts(17_612_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -87,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `301` // Estimated: `6038` - // Minimum execution time: 10_262_000 picoseconds. - Weight::from_parts(10_654_000, 6038) + // Minimum execution time: 15_482_000 picoseconds. + Weight::from_parts(16_159_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -98,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3514` - // Minimum execution time: 4_363_000 picoseconds. - Weight::from_parts(4_589_000, 3514) + // Minimum execution time: 4_911_000 picoseconds. + Weight::from_parts(5_177_000, 3514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -109,8 +109,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_220_000 picoseconds. - Weight::from_parts(6_622_000, 69049) + // Minimum execution time: 7_108_000 picoseconds. + Weight::from_parts(7_477_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -120,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_342_000 picoseconds. - Weight::from_parts(6_727_000, 69049) + // Minimum execution time: 7_435_000 picoseconds. + Weight::from_parts(7_669_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -133,8 +133,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 112_729_000 picoseconds. - Weight::from_parts(114_076_000, 0) + // Minimum execution time: 173_331_000 picoseconds. + Weight::from_parts(174_170_000, 0) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) @@ -145,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `246` // Estimated: `3514` - // Minimum execution time: 6_836_000 picoseconds. - Weight::from_parts(6_986_000, 3514) + // Minimum execution time: 11_817_000 picoseconds. + Weight::from_parts(12_351_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -158,8 +158,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 50_733_000 picoseconds. - Weight::from_parts(51_649_000, 69049) + // Minimum execution time: 60_883_000 picoseconds. + Weight::from_parts(62_584_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -171,8 +171,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 67_335_000 picoseconds. - Weight::from_parts(68_347_000, 69049) + // Minimum execution time: 77_569_000 picoseconds. + Weight::from_parts(79_165_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -184,8 +184,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 77_610_000 picoseconds. - Weight::from_parts(80_338_000, 69049) + // Minimum execution time: 120_786_000 picoseconds. + Weight::from_parts(122_457_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -201,8 +201,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `301` // Estimated: `6038` - // Minimum execution time: 11_674_000 picoseconds. - Weight::from_parts(12_105_000, 6038) + // Minimum execution time: 17_093_000 picoseconds. + Weight::from_parts(17_612_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -214,8 +214,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `301` // Estimated: `6038` - // Minimum execution time: 10_262_000 picoseconds. - Weight::from_parts(10_654_000, 6038) + // Minimum execution time: 15_482_000 picoseconds. + Weight::from_parts(16_159_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -225,8 +225,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3514` - // Minimum execution time: 4_363_000 picoseconds. - Weight::from_parts(4_589_000, 3514) + // Minimum execution time: 4_911_000 picoseconds. + Weight::from_parts(5_177_000, 3514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -236,8 +236,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_220_000 picoseconds. - Weight::from_parts(6_622_000, 69049) + // Minimum execution time: 7_108_000 picoseconds. + Weight::from_parts(7_477_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -247,8 +247,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_342_000 picoseconds. - Weight::from_parts(6_727_000, 69049) + // Minimum execution time: 7_435_000 picoseconds. + Weight::from_parts(7_669_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -260,8 +260,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 112_729_000 picoseconds. - Weight::from_parts(114_076_000, 0) + // Minimum execution time: 173_331_000 picoseconds. + Weight::from_parts(174_170_000, 0) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) @@ -272,8 +272,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `246` // Estimated: `3514` - // Minimum execution time: 6_836_000 picoseconds. - Weight::from_parts(6_986_000, 3514) + // Minimum execution time: 11_817_000 picoseconds. + Weight::from_parts(12_351_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -285,8 +285,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 50_733_000 picoseconds. - Weight::from_parts(51_649_000, 69049) + // Minimum execution time: 60_883_000 picoseconds. + Weight::from_parts(62_584_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -298,8 +298,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 67_335_000 picoseconds. - Weight::from_parts(68_347_000, 69049) + // Minimum execution time: 77_569_000 picoseconds. + Weight::from_parts(79_165_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -311,8 +311,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 77_610_000 picoseconds. - Weight::from_parts(80_338_000, 69049) + // Minimum execution time: 120_786_000 picoseconds. + Weight::from_parts(122_457_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/metadata-hash-extension/Cargo.toml b/substrate/frame/metadata-hash-extension/Cargo.toml index bca2c3ffb198..c7a417795ffe 100644 --- a/substrate/frame/metadata-hash-extension/Cargo.toml +++ b/substrate/frame/metadata-hash-extension/Cargo.toml @@ -11,22 +11,22 @@ description = "FRAME signed extension for verifying the metadata hash" [dependencies] array-bytes = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } -sp-runtime = { features = ["serde"], workspace = true } +const-hex = { workspace = true } +docify = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } log = { workspace = true } -docify = { workspace = true } -const-hex = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +sp-runtime = { features = ["serde"], workspace = true } [dev-dependencies] -substrate-wasm-builder = { features = ["metadata-hash"], workspace = true, default-features = true } -substrate-test-runtime-client = { workspace = true } -sp-api = { workspace = true, default-features = true } -sp-transaction-pool = { workspace = true, default-features = true } +frame-metadata = { features = ["current", "unstable"], workspace = true, default-features = true } merkleized-metadata = { workspace = true } -frame-metadata = { features = ["current"], workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } +substrate-wasm-builder = { features = ["metadata-hash"], workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index a32e48e65280..469592780beb 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -11,8 +11,8 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { features = ["derive"], workspace = true } cfg-if = { workspace = true } +codec = { features = ["derive"], workspace = true } docify = { workspace = true } impl-trait-for-tuples = { workspace = true } log = { workspace = true, default-features = true } diff --git a/substrate/frame/migrations/src/weights.rs b/substrate/frame/migrations/src/weights.rs index 6f5ac9715376..49ae379dba02 100644 --- a/substrate/frame/migrations/src/weights.rs +++ b/substrate/frame/migrations/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_migrations` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -74,10 +74,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn onboard_new_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `309` // Estimated: `67035` - // Minimum execution time: 7_762_000 picoseconds. - Weight::from_parts(8_100_000, 67035) + // Minimum execution time: 9_520_000 picoseconds. + Weight::from_parts(9_934_000, 67035) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -87,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `67035` - // Minimum execution time: 2_077_000 picoseconds. - Weight::from_parts(2_138_000, 67035) + // Minimum execution time: 2_993_000 picoseconds. + Weight::from_parts(3_088_000, 67035) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -97,10 +97,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn exec_migration_completed() -> Weight { // Proof Size summary in bytes: - // Measured: `134` - // Estimated: `3599` - // Minimum execution time: 5_868_000 picoseconds. - Weight::from_parts(6_143_000, 3599) + // Measured: `167` + // Estimated: `3632` + // Minimum execution time: 7_042_000 picoseconds. + Weight::from_parts(7_272_000, 3632) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,10 +110,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_skipped_historic() -> Weight { // Proof Size summary in bytes: - // Measured: `330` - // Estimated: `3795` - // Minimum execution time: 10_283_000 picoseconds. - Weight::from_parts(10_964_000, 3795) + // Measured: `363` + // Estimated: `3828` + // Minimum execution time: 16_522_000 picoseconds. + Weight::from_parts(17_082_000, 3828) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -122,10 +122,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_advance() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 9_900_000 picoseconds. - Weight::from_parts(10_396_000, 3741) + // Measured: `309` + // Estimated: `3774` + // Minimum execution time: 12_445_000 picoseconds. + Weight::from_parts(12_797_000, 3774) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -134,10 +134,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_complete() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 11_411_000 picoseconds. - Weight::from_parts(11_956_000, 3741) + // Measured: `309` + // Estimated: `3774` + // Minimum execution time: 14_057_000 picoseconds. + Weight::from_parts(14_254_000, 3774) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,10 +149,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn exec_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 12_398_000 picoseconds. - Weight::from_parts(12_910_000, 3741) + // Measured: `309` + // Estimated: `3774` + // Minimum execution time: 14_578_000 picoseconds. + Weight::from_parts(14_825_000, 3774) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -160,8 +160,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 166_000 picoseconds. - Weight::from_parts(193_000, 0) + // Minimum execution time: 169_000 picoseconds. + Weight::from_parts(197_000, 0) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) @@ -169,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_686_000 picoseconds. - Weight::from_parts(2_859_000, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_798_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) @@ -179,8 +179,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_070_000 picoseconds. - Weight::from_parts(3_250_000, 0) + // Minimum execution time: 3_069_000 picoseconds. + Weight::from_parts(3_293_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) @@ -189,10 +189,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn force_onboard_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `251` + // Measured: `284` // Estimated: `67035` - // Minimum execution time: 5_901_000 picoseconds. - Weight::from_parts(6_320_000, 67035) + // Minimum execution time: 7_674_000 picoseconds. + Weight::from_parts(8_000_000, 67035) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) @@ -202,10 +202,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1122 + n * (271 ±0)` // Estimated: `3834 + n * (2740 ±0)` - // Minimum execution time: 15_952_000 picoseconds. - Weight::from_parts(14_358_665, 3834) - // Standard Error: 3_358 - .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + // Minimum execution time: 16_937_000 picoseconds. + Weight::from_parts(15_713_121, 3834) + // Standard Error: 2_580 + .saturating_add(Weight::from_parts(1_424_239, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -221,10 +221,10 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn onboard_new_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `309` // Estimated: `67035` - // Minimum execution time: 7_762_000 picoseconds. - Weight::from_parts(8_100_000, 67035) + // Minimum execution time: 9_520_000 picoseconds. + Weight::from_parts(9_934_000, 67035) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -234,8 +234,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `67035` - // Minimum execution time: 2_077_000 picoseconds. - Weight::from_parts(2_138_000, 67035) + // Minimum execution time: 2_993_000 picoseconds. + Weight::from_parts(3_088_000, 67035) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -244,10 +244,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn exec_migration_completed() -> Weight { // Proof Size summary in bytes: - // Measured: `134` - // Estimated: `3599` - // Minimum execution time: 5_868_000 picoseconds. - Weight::from_parts(6_143_000, 3599) + // Measured: `167` + // Estimated: `3632` + // Minimum execution time: 7_042_000 picoseconds. + Weight::from_parts(7_272_000, 3632) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -257,10 +257,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_skipped_historic() -> Weight { // Proof Size summary in bytes: - // Measured: `330` - // Estimated: `3795` - // Minimum execution time: 10_283_000 picoseconds. - Weight::from_parts(10_964_000, 3795) + // Measured: `363` + // Estimated: `3828` + // Minimum execution time: 16_522_000 picoseconds. + Weight::from_parts(17_082_000, 3828) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -269,10 +269,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_advance() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 9_900_000 picoseconds. - Weight::from_parts(10_396_000, 3741) + // Measured: `309` + // Estimated: `3774` + // Minimum execution time: 12_445_000 picoseconds. + Weight::from_parts(12_797_000, 3774) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -281,10 +281,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_complete() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 11_411_000 picoseconds. - Weight::from_parts(11_956_000, 3741) + // Measured: `309` + // Estimated: `3774` + // Minimum execution time: 14_057_000 picoseconds. + Weight::from_parts(14_254_000, 3774) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -296,10 +296,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn exec_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 12_398_000 picoseconds. - Weight::from_parts(12_910_000, 3741) + // Measured: `309` + // Estimated: `3774` + // Minimum execution time: 14_578_000 picoseconds. + Weight::from_parts(14_825_000, 3774) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -307,8 +307,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 166_000 picoseconds. - Weight::from_parts(193_000, 0) + // Minimum execution time: 169_000 picoseconds. + Weight::from_parts(197_000, 0) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) @@ -316,8 +316,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_686_000 picoseconds. - Weight::from_parts(2_859_000, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_798_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) @@ -326,8 +326,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_070_000 picoseconds. - Weight::from_parts(3_250_000, 0) + // Minimum execution time: 3_069_000 picoseconds. + Weight::from_parts(3_293_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) @@ -336,10 +336,10 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn force_onboard_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `251` + // Measured: `284` // Estimated: `67035` - // Minimum execution time: 5_901_000 picoseconds. - Weight::from_parts(6_320_000, 67035) + // Minimum execution time: 7_674_000 picoseconds. + Weight::from_parts(8_000_000, 67035) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) @@ -349,10 +349,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1122 + n * (271 ±0)` // Estimated: `3834 + n * (2740 ±0)` - // Minimum execution time: 15_952_000 picoseconds. - Weight::from_parts(14_358_665, 3834) - // Standard Error: 3_358 - .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + // Minimum execution time: 16_937_000 picoseconds. + Weight::from_parts(15_713_121, 3834) + // Standard Error: 2_580 + .saturating_add(Weight::from_parts(1_424_239, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index c96be908faef..0d175617c9c2 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame = { workspace = true, features = ["experimental", "runtime"] } +scale-info = { features = ["derive"], workspace = true } # third party log = { workspace = true } diff --git a/substrate/frame/multisig/src/lib.rs b/substrate/frame/multisig/src/lib.rs index 4a30b5c119b9..869b4adc2adc 100644 --- a/substrate/frame/multisig/src/lib.rs +++ b/substrate/frame/multisig/src/lib.rs @@ -77,6 +77,9 @@ macro_rules! log { type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +pub type BlockNumberFor = + <::BlockNumberProvider as BlockNumberProvider>::BlockNumber; + /// A global extrinsic index, formed as the extrinsic index within a block, together with that /// block's height. This allows a transaction in which a multisig operation of a particular /// composite was created to be uniquely identified. @@ -153,6 +156,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; + + /// Provider for the block number. Normally this is the `frame_system` pallet. + type BlockNumberProvider: BlockNumberProvider; } /// The in-code storage version. @@ -235,7 +241,7 @@ pub mod pallet { } #[pallet::hooks] - impl Hooks> for Pallet {} + impl Hooks> for Pallet {} #[pallet::call] impl Pallet { @@ -626,7 +632,7 @@ impl Pallet { /// The current `Timepoint`. pub fn timepoint() -> Timepoint> { Timepoint { - height: >::block_number(), + height: T::BlockNumberProvider::current_block_number(), index: >::extrinsic_index().unwrap_or_default(), } } diff --git a/substrate/frame/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs index c5a98845270c..4065ce73f905 100644 --- a/substrate/frame/multisig/src/tests.rs +++ b/substrate/frame/multisig/src/tests.rs @@ -66,6 +66,7 @@ impl Config for Test { type DepositFactor = ConstU64<1>; type MaxSignatories = ConstU32<3>; type WeightInfo = (); + type BlockNumberProvider = frame_system::Pallet; } use pallet_balances::Call as BalancesCall; diff --git a/substrate/frame/multisig/src/weights.rs b/substrate/frame/multisig/src/weights.rs index fb263116ea62..5c14922e0ef0 100644 --- a/substrate/frame/multisig/src/weights.rs +++ b/substrate/frame/multisig/src/weights.rs @@ -294,4 +294,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } -} +} \ No newline at end of file diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index 6a064204b895..7f6df86ed0e5 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -17,13 +17,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-assets = { workspace = true } pallet-nfts = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/nft-fractionalization/src/benchmarking.rs b/substrate/frame/nft-fractionalization/src/benchmarking.rs index 811b5fe1b317..433019280f20 100644 --- a/substrate/frame/nft-fractionalization/src/benchmarking.rs +++ b/substrate/frame/nft-fractionalization/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_support::{ assert_ok, traits::{ @@ -77,20 +77,37 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { assert_eq!(event, &system_event); } -benchmarks! { - where_clause { - where - T::Nfts: Create, frame_system::pallet_prelude::BlockNumberFor::, T::NftCollectionId>> - + Mutate, - } - - fractionalize { +#[benchmarks( + where + T::Nfts: + Create< + T::AccountId, + CollectionConfig, + frame_system::pallet_prelude::BlockNumberFor::, + T::NftCollectionId> + > + + Mutate, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn fractionalize() { let asset = T::BenchmarkHelper::asset(0); let collection = T::BenchmarkHelper::collection(0); let nft = T::BenchmarkHelper::nft(0); let (caller, caller_lookup) = mint_nft::(nft); - }: _(SystemOrigin::Signed(caller.clone()), collection, nft, asset.clone(), caller_lookup, 1000u32.into()) - verify { + + #[extrinsic_call] + _( + SystemOrigin::Signed(caller.clone()), + collection, + nft, + asset.clone(), + caller_lookup, + 1000u32.into(), + ); + assert_last_event::( Event::NftFractionalized { nft_collection: collection, @@ -98,34 +115,39 @@ benchmarks! { fractions: 1000u32.into(), asset, beneficiary: caller, - }.into() + } + .into(), ); } - unify { + #[benchmark] + fn unify() { let asset = T::BenchmarkHelper::asset(0); let collection = T::BenchmarkHelper::collection(0); let nft = T::BenchmarkHelper::nft(0); let (caller, caller_lookup) = mint_nft::(nft); - NftFractionalization::::fractionalize( + + assert_ok!(NftFractionalization::::fractionalize( SystemOrigin::Signed(caller.clone()).into(), collection, nft, asset.clone(), caller_lookup.clone(), 1000u32.into(), - )?; - }: _(SystemOrigin::Signed(caller.clone()), collection, nft, asset.clone(), caller_lookup) - verify { + )); + + #[extrinsic_call] + _(SystemOrigin::Signed(caller.clone()), collection, nft, asset.clone(), caller_lookup); + assert_last_event::( - Event::NftUnified { - nft_collection: collection, - nft, - asset, - beneficiary: caller, - }.into() + Event::NftUnified { nft_collection: collection, nft, asset, beneficiary: caller } + .into(), ); } - impl_benchmark_test_suite!(NftFractionalization, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!( + NftFractionalization, + crate::mock::new_test_ext(), + crate::mock::Test + ); } diff --git a/substrate/frame/nft-fractionalization/src/mock.rs b/substrate/frame/nft-fractionalization/src/mock.rs index 50b41b5fc64e..762c1776e30f 100644 --- a/substrate/frame/nft-fractionalization/src/mock.rs +++ b/substrate/frame/nft-fractionalization/src/mock.rs @@ -115,6 +115,7 @@ impl pallet_nfts::Config for Test { type OffchainSignature = Signature; type OffchainPublic = AccountPublic; type WeightInfo = (); + type BlockNumberProvider = frame_system::Pallet; pallet_nfts::runtime_benchmarks_enabled! { type Helper = (); } diff --git a/substrate/frame/nft-fractionalization/src/weights.rs b/substrate/frame/nft-fractionalization/src/weights.rs index bee6484d856e..a55d01eb4f2d 100644 --- a/substrate/frame/nft-fractionalization/src/weights.rs +++ b/substrate/frame/nft-fractionalization/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_nft_fractionalization` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -61,13 +61,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::NextAssetId` (r:1 w:0) + /// Proof: `Assets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:1 w:1) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -78,11 +80,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn fractionalize() -> Weight { // Proof Size summary in bytes: - // Measured: `609` + // Measured: `661` // Estimated: `4326` - // Minimum execution time: 174_545_000 picoseconds. - Weight::from_parts(177_765_000, 4326) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 186_614_000 picoseconds. + Weight::from_parts(192_990_000, 4326) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) @@ -102,7 +104,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) @@ -113,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1422` // Estimated: `4326` - // Minimum execution time: 128_211_000 picoseconds. - Weight::from_parts(131_545_000, 4326) + // Minimum execution time: 140_234_000 picoseconds. + Weight::from_parts(144_124_000, 4326) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -125,13 +127,15 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nfts::Attribute` (r:1 w:1) /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) /// Storage: `Nfts::Collection` (r:1 w:1) /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::NextAssetId` (r:1 w:0) + /// Proof: `Assets::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:1 w:1) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -142,11 +146,11 @@ impl WeightInfo for () { /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) fn fractionalize() -> Weight { // Proof Size summary in bytes: - // Measured: `609` + // Measured: `661` // Estimated: `4326` - // Minimum execution time: 174_545_000 picoseconds. - Weight::from_parts(177_765_000, 4326) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 186_614_000 picoseconds. + Weight::from_parts(192_990_000, 4326) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) @@ -166,7 +170,7 @@ impl WeightInfo for () { /// Storage: `Nfts::Item` (r:1 w:1) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nfts::Account` (r:0 w:1) /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) @@ -177,8 +181,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1422` // Estimated: `4326` - // Minimum execution time: 128_211_000 picoseconds. - Weight::from_parts(131_545_000, 4326) + // Minimum execution time: 140_234_000 picoseconds. + Weight::from_parts(144_124_000, 4326) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index a97b49e56524..18895018e1c5 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } enumflags2 = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/nfts/src/benchmarking.rs b/substrate/frame/nfts/src/benchmarking.rs index bc81096b459d..81828be5fa09 100644 --- a/substrate/frame/nfts/src/benchmarking.rs +++ b/substrate/frame/nfts/src/benchmarking.rs @@ -29,7 +29,7 @@ use frame_support::{ traits::{EnsureOrigin, Get, UnfilteredDispatchable}, BoundedVec, }; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin as SystemOrigin}; +use frame_system::RawOrigin as SystemOrigin; use sp_runtime::traits::{Bounded, One}; use crate::Pallet as Nfts; @@ -577,7 +577,7 @@ benchmarks_instance_pallet! { let (item, ..) = mint_item::(0); let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); - let deadline = BlockNumberFor::::max_value(); + let deadline = BlockNumberFor::::max_value(); }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup, Some(deadline)) verify { assert_last_event::(Event::TransferApproved { collection, item, owner: caller, delegate, deadline: Some(deadline) }.into()); @@ -589,7 +589,7 @@ benchmarks_instance_pallet! { let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); - let deadline = BlockNumberFor::::max_value(); + let deadline = BlockNumberFor::::max_value(); Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Signed(caller.clone()), collection, item, delegate_lookup) verify { @@ -602,7 +602,7 @@ benchmarks_instance_pallet! { let delegate: T::AccountId = account("delegate", 0, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); let origin = SystemOrigin::Signed(caller.clone()).into(); - let deadline = BlockNumberFor::::max_value(); + let deadline = BlockNumberFor::::max_value(); Nfts::::approve_transfer(origin, collection, item, delegate_lookup.clone(), Some(deadline))?; }: _(SystemOrigin::Signed(caller.clone()), collection, item) verify { @@ -712,10 +712,10 @@ benchmarks_instance_pallet! { let price_direction = PriceDirection::Receive; let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; let duration = T::MaxDeadlineDuration::get(); - frame_system::Pallet::::set_block_number(One::one()); + T::BlockNumberProvider::set_block_number(One::one()); }: _(SystemOrigin::Signed(caller.clone()), collection, item1, collection, Some(item2), Some(price_with_direction.clone()), duration) verify { - let current_block = frame_system::Pallet::::block_number(); + let current_block = T::BlockNumberProvider::current_block_number(); assert_last_event::(Event::SwapCreated { offered_collection: collection, offered_item: item1, @@ -735,7 +735,7 @@ benchmarks_instance_pallet! { let duration = T::MaxDeadlineDuration::get(); let price_direction = PriceDirection::Receive; let price_with_direction = PriceWithDirection { amount: price, direction: price_direction }; - frame_system::Pallet::::set_block_number(One::one()); + T::BlockNumberProvider::set_block_number(One::one()); Nfts::::create_swap(origin, collection, item1, collection, Some(item2), Some(price_with_direction.clone()), duration)?; }: _(SystemOrigin::Signed(caller.clone()), collection, item1) verify { @@ -761,7 +761,7 @@ benchmarks_instance_pallet! { let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); let origin = SystemOrigin::Signed(caller.clone()); - frame_system::Pallet::::set_block_number(One::one()); + T::BlockNumberProvider::set_block_number(One::one()); Nfts::::transfer(origin.clone().into(), collection, item2, target_lookup)?; Nfts::::create_swap( origin.clone().into(), @@ -774,7 +774,7 @@ benchmarks_instance_pallet! { )?; }: _(SystemOrigin::Signed(target.clone()), collection, item2, collection, item1, Some(price_with_direction.clone())) verify { - let current_block = frame_system::Pallet::::block_number(); + let current_block = T::BlockNumberProvider::current_block_number(); assert_last_event::(Event::SwapClaimed { sent_collection: collection, sent_item: item2, @@ -822,7 +822,7 @@ benchmarks_instance_pallet! { let target: T::AccountId = account("target", 0, SEED); T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); - frame_system::Pallet::::set_block_number(One::one()); + T::BlockNumberProvider::set_block_number(One::one()); }: _(SystemOrigin::Signed(target.clone()), Box::new(mint_data), signature.into(), caller) verify { let metadata: BoundedVec<_, _> = metadata.try_into().unwrap(); @@ -865,7 +865,7 @@ benchmarks_instance_pallet! { let message = Encode::encode(&pre_signed_data); let signature = T::Helper::sign(&signer_public, &message); - frame_system::Pallet::::set_block_number(One::one()); + T::BlockNumberProvider::set_block_number(One::one()); }: _(SystemOrigin::Signed(item_owner.clone()), pre_signed_data, signature.into(), signer.clone()) verify { assert_last_event::( diff --git a/substrate/frame/nfts/src/features/approvals.rs b/substrate/frame/nfts/src/features/approvals.rs index 053fa67163b9..4738f69f83c4 100644 --- a/substrate/frame/nfts/src/features/approvals.rs +++ b/substrate/frame/nfts/src/features/approvals.rs @@ -46,7 +46,7 @@ impl, I: 'static> Pallet { collection: T::CollectionId, item: T::ItemId, delegate: T::AccountId, - maybe_deadline: Option>, + maybe_deadline: Option>, ) -> DispatchResult { ensure!( Self::is_pallet_feature_enabled(PalletFeature::Approvals), @@ -65,7 +65,7 @@ impl, I: 'static> Pallet { ensure!(check_origin == details.owner, Error::::NoPermission); } - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); let deadline = maybe_deadline.map(|d| d.saturating_add(now)); details @@ -111,7 +111,7 @@ impl, I: 'static> Pallet { let maybe_deadline = details.approvals.get(&delegate).ok_or(Error::::NotDelegate)?; let is_past_deadline = if let Some(deadline) = maybe_deadline { - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); now > *deadline } else { false diff --git a/substrate/frame/nfts/src/features/atomic_swap.rs b/substrate/frame/nfts/src/features/atomic_swap.rs index 830283b73c2a..03ebd35b81b2 100644 --- a/substrate/frame/nfts/src/features/atomic_swap.rs +++ b/substrate/frame/nfts/src/features/atomic_swap.rs @@ -53,7 +53,7 @@ impl, I: 'static> Pallet { desired_collection_id: T::CollectionId, maybe_desired_item_id: Option, maybe_price: Option>>, - duration: frame_system::pallet_prelude::BlockNumberFor, + duration: BlockNumberFor, ) -> DispatchResult { ensure!( Self::is_pallet_feature_enabled(PalletFeature::Swaps), @@ -76,7 +76,7 @@ impl, I: 'static> Pallet { ), }; - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); let deadline = duration.saturating_add(now); PendingSwapOf::::insert( @@ -119,7 +119,7 @@ impl, I: 'static> Pallet { let swap = PendingSwapOf::::get(&offered_collection_id, &offered_item_id) .ok_or(Error::::UnknownSwap)?; - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); if swap.deadline > now { let item = Item::::get(&offered_collection_id, &offered_item_id) .ok_or(Error::::UnknownItem)?; @@ -187,7 +187,7 @@ impl, I: 'static> Pallet { ensure!(desired_item == send_item_id, Error::::UnknownSwap); } - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); ensure!(now <= swap.deadline, Error::::DeadlineExpired); if let Some(ref price) = swap.price { diff --git a/substrate/frame/nfts/src/features/attributes.rs b/substrate/frame/nfts/src/features/attributes.rs index 28f7bd2c58ce..2cd09f7d2193 100644 --- a/substrate/frame/nfts/src/features/attributes.rs +++ b/substrate/frame/nfts/src/features/attributes.rs @@ -225,7 +225,7 @@ impl, I: 'static> Pallet { Error::::MaxAttributesLimitReached ); - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); ensure!(deadline >= now, Error::::DeadlineExpired); let item_details = diff --git a/substrate/frame/nfts/src/features/create_delete_item.rs b/substrate/frame/nfts/src/features/create_delete_item.rs index 37f64ae1b1b9..57366127f142 100644 --- a/substrate/frame/nfts/src/features/create_delete_item.rs +++ b/substrate/frame/nfts/src/features/create_delete_item.rs @@ -145,7 +145,7 @@ impl, I: 'static> Pallet { ensure!(account == mint_to, Error::::WrongOrigin); } - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); ensure!(deadline >= now, Error::::DeadlineExpired); ensure!( diff --git a/substrate/frame/nfts/src/features/settings.rs b/substrate/frame/nfts/src/features/settings.rs index d4f7533ffa4e..48719ae2c20e 100644 --- a/substrate/frame/nfts/src/features/settings.rs +++ b/substrate/frame/nfts/src/features/settings.rs @@ -96,11 +96,7 @@ impl, I: 'static> Pallet { pub(crate) fn do_update_mint_settings( maybe_check_origin: Option, collection: T::CollectionId, - mint_settings: MintSettings< - BalanceOf, - frame_system::pallet_prelude::BlockNumberFor, - T::CollectionId, - >, + mint_settings: MintSettings, BlockNumberFor, T::CollectionId>, ) -> DispatchResult { if let Some(check_origin) = &maybe_check_origin { ensure!( diff --git a/substrate/frame/nfts/src/lib.rs b/substrate/frame/nfts/src/lib.rs index 4e5493a3c755..346ad162c503 100644 --- a/substrate/frame/nfts/src/lib.rs +++ b/substrate/frame/nfts/src/lib.rs @@ -58,7 +58,7 @@ use frame_support::traits::{ }; use frame_system::Config as SystemConfig; use sp_runtime::{ - traits::{IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, + traits::{BlockNumberProvider, IdentifyAccount, Saturating, StaticLookup, Verify, Zero}, RuntimeDebug, }; @@ -76,7 +76,7 @@ type AccountIdLookupOf = <::Lookup as StaticLookup>::Sourc pub mod pallet { use super::*; use frame_support::{pallet_prelude::*, traits::ExistenceRequirement}; - use frame_system::pallet_prelude::*; + use frame_system::{ensure_signed, pallet_prelude::OriginFor}; /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -210,7 +210,7 @@ pub mod pallet { /// The max duration in blocks for deadlines. #[pallet::constant] - type MaxDeadlineDuration: Get>; + type MaxDeadlineDuration: Get>; /// The max number of attributes a user could set per call. #[pallet::constant] @@ -242,6 +242,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// Provider for the block number. Normally this is the `frame_system` pallet. + type BlockNumberProvider: BlockNumberProvider; } /// Details of a collection. @@ -388,7 +391,7 @@ pub mod pallet { T::CollectionId, T::ItemId, PriceWithDirection>, - BlockNumberFor, + BlockNumberFor, >, OptionQuery, >; @@ -459,7 +462,7 @@ pub mod pallet { item: T::ItemId, owner: T::AccountId, delegate: T::AccountId, - deadline: Option>, + deadline: Option>, }, /// An approval for a `delegate` account to transfer the `item` of an item /// `collection` was cancelled by its `owner`. @@ -554,7 +557,7 @@ pub mod pallet { desired_collection: T::CollectionId, desired_item: Option, price: Option>>, - deadline: BlockNumberFor, + deadline: BlockNumberFor, }, /// The swap was cancelled. SwapCancelled { @@ -563,7 +566,7 @@ pub mod pallet { desired_collection: T::CollectionId, desired_item: Option, price: Option>>, - deadline: BlockNumberFor, + deadline: BlockNumberFor, }, /// The swap has been claimed. SwapClaimed { @@ -574,7 +577,7 @@ pub mod pallet { received_item: T::ItemId, received_item_owner: T::AccountId, price: Option>>, - deadline: BlockNumberFor, + deadline: BlockNumberFor, }, /// New attributes have been set for an `item` of the `collection`. PreSignedAttributesSet { @@ -857,7 +860,7 @@ pub mod pallet { item_config, |collection_details, collection_config| { let mint_settings = collection_config.mint_settings; - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); if let Some(start_block) = mint_settings.start_block { ensure!(start_block <= now, Error::::MintNotStarted); @@ -1029,7 +1032,7 @@ pub mod pallet { let deadline = details.approvals.get(&origin).ok_or(Error::::NoPermission)?; if let Some(d) = deadline { - let block_number = frame_system::Pallet::::block_number(); + let block_number = T::BlockNumberProvider::current_block_number(); ensure!(block_number <= *d, Error::::ApprovalExpired); } } @@ -1290,7 +1293,7 @@ pub mod pallet { collection: T::CollectionId, item: T::ItemId, delegate: AccountIdLookupOf, - maybe_deadline: Option>, + maybe_deadline: Option>, ) -> DispatchResult { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) @@ -1713,7 +1716,7 @@ pub mod pallet { pub fn update_mint_settings( origin: OriginFor, collection: T::CollectionId, - mint_settings: MintSettings, BlockNumberFor, T::CollectionId>, + mint_settings: MintSettings, BlockNumberFor, T::CollectionId>, ) -> DispatchResult { let maybe_check_origin = T::ForceOrigin::try_origin(origin) .map(|_| None) @@ -1809,7 +1812,7 @@ pub mod pallet { desired_collection: T::CollectionId, maybe_desired_item: Option, maybe_price: Option>>, - duration: BlockNumberFor, + duration: BlockNumberFor, ) -> DispatchResult { let origin = ensure_signed(origin)?; Self::do_create_swap( diff --git a/substrate/frame/nfts/src/mock.rs b/substrate/frame/nfts/src/mock.rs index 5b589f591ca3..291c3c081334 100644 --- a/substrate/frame/nfts/src/mock.rs +++ b/substrate/frame/nfts/src/mock.rs @@ -92,6 +92,7 @@ impl Config for Test { type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type Helper = (); + type BlockNumberProvider = frame_system::Pallet; } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/substrate/frame/nfts/src/types.rs b/substrate/frame/nfts/src/types.rs index d67fb404ea79..3ab85993473a 100644 --- a/substrate/frame/nfts/src/types.rs +++ b/substrate/frame/nfts/src/types.rs @@ -27,9 +27,11 @@ use frame_support::{ traits::Get, BoundedBTreeMap, BoundedBTreeSet, }; -use frame_system::pallet_prelude::BlockNumberFor; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; +pub type BlockNumberFor = + <>::BlockNumberProvider as BlockNumberProvider>::BlockNumber; + /// A type alias for handling balance deposits. pub type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -39,7 +41,7 @@ pub type CollectionDetailsFor = /// A type alias for keeping track of approvals used by a single item. pub type ApprovalsOf = BoundedBTreeMap< ::AccountId, - Option>, + Option>, >::ApprovalsLimit, >; /// A type alias for keeping track of approvals for an item's attributes. @@ -70,13 +72,13 @@ pub type ItemTipOf = ItemTip< >; /// A type alias for the settings configuration of a collection. pub type CollectionConfigFor = - CollectionConfig, BlockNumberFor, >::CollectionId>; + CollectionConfig, BlockNumberFor, >::CollectionId>; /// A type alias for the pre-signed minting configuration for a specified collection. pub type PreSignedMintOf = PreSignedMint< >::CollectionId, >::ItemId, ::AccountId, - BlockNumberFor, + BlockNumberFor, BalanceOf, >; /// A type alias for the pre-signed minting configuration on the attribute level of an item. @@ -84,7 +86,7 @@ pub type PreSignedAttributesOf = PreSignedAttributes< >::CollectionId, >::ItemId, ::AccountId, - BlockNumberFor, + BlockNumberFor, >; /// Information about a collection. diff --git a/substrate/frame/nfts/src/weights.rs b/substrate/frame/nfts/src/weights.rs index c5fb60a2206f..1182518e89f8 100644 --- a/substrate/frame/nfts/src/weights.rs +++ b/substrate/frame/nfts/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -109,8 +109,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Minimum execution time: 39_795_000 picoseconds. + Weight::from_parts(40_954_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -128,8 +128,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Minimum execution time: 19_590_000 picoseconds. + Weight::from_parts(20_452_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -152,14 +152,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32204 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_282_083_000 picoseconds. - Weight::from_parts(1_249_191_963, 2523990) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(6_470_227, 0).saturating_mul(a.into())) + // Minimum execution time: 1_283_452_000 picoseconds. + Weight::from_parts(1_066_445_083, 2523990) + // Standard Error: 9_120 + .saturating_add(Weight::from_parts(195_960, 0).saturating_mul(m.into())) + // Standard Error: 9_120 + .saturating_add(Weight::from_parts(7_706_045, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) @@ -182,8 +184,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 49_055_000 picoseconds. - Weight::from_parts(50_592_000, 4326) + // Minimum execution time: 55_122_000 picoseconds. + Weight::from_parts(56_437_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -203,8 +205,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 47_102_000 picoseconds. - Weight::from_parts(48_772_000, 4326) + // Minimum execution time: 53_137_000 picoseconds. + Weight::from_parts(54_307_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -230,8 +232,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `564` // Estimated: `4326` - // Minimum execution time: 52_968_000 picoseconds. - Weight::from_parts(55_136_000, 4326) + // Minimum execution time: 59_107_000 picoseconds. + Weight::from_parts(60_638_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -255,8 +257,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `593` // Estimated: `4326` - // Minimum execution time: 41_140_000 picoseconds. - Weight::from_parts(43_288_000, 4326) + // Minimum execution time: 47_355_000 picoseconds. + Weight::from_parts(48_729_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -271,10 +273,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `763 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 14_433_000 picoseconds. - Weight::from_parts(14_664_000, 3549) - // Standard Error: 23_078 - .saturating_add(Weight::from_parts(15_911_377, 0).saturating_mul(i.into())) + // Minimum execution time: 19_597_000 picoseconds. + Weight::from_parts(19_920_000, 3549) + // Standard Error: 25_051 + .saturating_add(Weight::from_parts(18_457_577, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -288,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 18_307_000 picoseconds. - Weight::from_parts(18_966_000, 3534) + // Minimum execution time: 23_838_000 picoseconds. + Weight::from_parts(24_765_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -301,8 +303,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 18_078_000 picoseconds. - Weight::from_parts(18_593_000, 3534) + // Minimum execution time: 24_030_000 picoseconds. + Weight::from_parts(24_589_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -314,8 +316,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Minimum execution time: 20_505_000 picoseconds. + Weight::from_parts(20_809_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -331,8 +333,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `562` // Estimated: `3593` - // Minimum execution time: 26_164_000 picoseconds. - Weight::from_parts(27_117_000, 3593) + // Minimum execution time: 32_314_000 picoseconds. + Weight::from_parts(33_213_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -344,8 +346,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `369` // Estimated: `6078` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_486_000, 6078) + // Minimum execution time: 44_563_000 picoseconds. + Weight::from_parts(45_899_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -357,8 +359,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `311` // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Minimum execution time: 20_515_000 picoseconds. + Weight::from_parts(21_125_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -370,8 +372,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `276` // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Minimum execution time: 16_933_000 picoseconds. + Weight::from_parts(17_552_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -383,8 +385,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 17_165_000 picoseconds. - Weight::from_parts(17_769_000, 3534) + // Minimum execution time: 22_652_000 picoseconds. + Weight::from_parts(23_655_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -402,8 +404,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `539` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_000, 3944) + // Minimum execution time: 56_832_000 picoseconds. + Weight::from_parts(58_480_000, 3944) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -415,8 +417,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `344` // Estimated: `3944` - // Minimum execution time: 24_665_000 picoseconds. - Weight::from_parts(25_465_000, 3944) + // Minimum execution time: 30_136_000 picoseconds. + Weight::from_parts(30_919_000, 3944) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -432,8 +434,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `983` // Estimated: `3944` - // Minimum execution time: 44_617_000 picoseconds. - Weight::from_parts(46_458_000, 3944) + // Minimum execution time: 52_264_000 picoseconds. + Weight::from_parts(53_806_000, 3944) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -445,8 +447,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `4326` - // Minimum execution time: 15_710_000 picoseconds. - Weight::from_parts(16_191_000, 4326) + // Minimum execution time: 20_476_000 picoseconds. + Weight::from_parts(21_213_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -463,10 +465,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `831 + n * (398 ±0)` // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 24_447_000 picoseconds. - Weight::from_parts(25_144_000, 4326) - // Standard Error: 4_872 - .saturating_add(Weight::from_parts(6_523_101, 0).saturating_mul(n.into())) + // Minimum execution time: 30_667_000 picoseconds. + Weight::from_parts(31_079_000, 4326) + // Standard Error: 5_236 + .saturating_add(Weight::from_parts(7_517_246, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -487,8 +489,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `539` // Estimated: `3812` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_098_000, 3812) + // Minimum execution time: 46_520_000 picoseconds. + Weight::from_parts(47_471_000, 3812) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -504,8 +506,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `849` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_000, 3812) + // Minimum execution time: 44_199_000 picoseconds. + Weight::from_parts(45_621_000, 3812) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -521,8 +523,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `398` // Estimated: `3759` - // Minimum execution time: 36_778_000 picoseconds. - Weight::from_parts(38_088_000, 3759) + // Minimum execution time: 41_260_000 picoseconds. + Weight::from_parts(42_420_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -538,8 +540,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `716` // Estimated: `3759` - // Minimum execution time: 36_887_000 picoseconds. - Weight::from_parts(38_406_000, 3759) + // Minimum execution time: 40_975_000 picoseconds. + Weight::from_parts(42_367_000, 3759) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -551,8 +553,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `410` // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_000, 4326) + // Minimum execution time: 23_150_000 picoseconds. + Weight::from_parts(24_089_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -562,8 +564,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 4326) + // Minimum execution time: 20_362_000 picoseconds. + Weight::from_parts(21_102_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -573,8 +575,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 15_013_000 picoseconds. - Weight::from_parts(15_607_000, 4326) + // Minimum execution time: 19_564_000 picoseconds. + Weight::from_parts(20_094_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -584,8 +586,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3517` - // Minimum execution time: 13_077_000 picoseconds. - Weight::from_parts(13_635_000, 3517) + // Minimum execution time: 13_360_000 picoseconds. + Weight::from_parts(13_943_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -597,8 +599,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Minimum execution time: 21_304_000 picoseconds. + Weight::from_parts(22_021_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -610,8 +612,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `323` // Estimated: `3538` - // Minimum execution time: 16_102_000 picoseconds. - Weight::from_parts(16_629_000, 3538) + // Minimum execution time: 20_888_000 picoseconds. + Weight::from_parts(21_600_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -627,8 +629,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `518` // Estimated: `4326` - // Minimum execution time: 22_118_000 picoseconds. - Weight::from_parts(22_849_000, 4326) + // Minimum execution time: 27_414_000 picoseconds. + Weight::from_parts(28_382_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -652,8 +654,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `705` // Estimated: `4326` - // Minimum execution time: 50_369_000 picoseconds. - Weight::from_parts(51_816_000, 4326) + // Minimum execution time: 55_660_000 picoseconds. + Weight::from_parts(57_720_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -662,10 +664,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_203_000 picoseconds. - Weight::from_parts(3_710_869, 0) - // Standard Error: 8_094 - .saturating_add(Weight::from_parts(2_201_869, 0).saturating_mul(n.into())) + // Minimum execution time: 2_064_000 picoseconds. + Weight::from_parts(3_432_697, 0) + // Standard Error: 6_920 + .saturating_add(Weight::from_parts(1_771_459, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -675,8 +677,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `494` // Estimated: `7662` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_506_000, 7662) + // Minimum execution time: 24_590_000 picoseconds. + Weight::from_parts(25_395_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -688,8 +690,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `513` // Estimated: `4326` - // Minimum execution time: 19_086_000 picoseconds. - Weight::from_parts(19_609_000, 4326) + // Minimum execution time: 22_121_000 picoseconds. + Weight::from_parts(23_196_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -713,8 +715,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `834` // Estimated: `7662` - // Minimum execution time: 84_103_000 picoseconds. - Weight::from_parts(85_325_000, 7662) + // Minimum execution time: 85_761_000 picoseconds. + Weight::from_parts(88_382_000, 7662) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -741,10 +743,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `629` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 128_363_000 picoseconds. - Weight::from_parts(139_474_918, 6078) - // Standard Error: 79_252 - .saturating_add(Weight::from_parts(31_384_027, 0).saturating_mul(n.into())) + // Minimum execution time: 136_928_000 picoseconds. + Weight::from_parts(143_507_020, 6078) + // Standard Error: 45_424 + .saturating_add(Weight::from_parts(32_942_641, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -768,10 +770,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `659` // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_688_000 picoseconds. - Weight::from_parts(79_208_379, 4326) - // Standard Error: 74_020 - .saturating_add(Weight::from_parts(31_028_221, 0).saturating_mul(n.into())) + // Minimum execution time: 72_412_000 picoseconds. + Weight::from_parts(84_724_399, 4326) + // Standard Error: 68_965 + .saturating_add(Weight::from_parts(31_711_702, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -796,8 +798,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3549` - // Minimum execution time: 34_863_000 picoseconds. - Weight::from_parts(36_679_000, 3549) + // Minimum execution time: 39_795_000 picoseconds. + Weight::from_parts(40_954_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -815,8 +817,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3549` - // Minimum execution time: 19_631_000 picoseconds. - Weight::from_parts(20_384_000, 3549) + // Minimum execution time: 19_590_000 picoseconds. + Weight::from_parts(20_452_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -839,14 +841,16 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. - fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32204 + a * (366 ±0)` // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_282_083_000 picoseconds. - Weight::from_parts(1_249_191_963, 2523990) - // Standard Error: 4_719 - .saturating_add(Weight::from_parts(6_470_227, 0).saturating_mul(a.into())) + // Minimum execution time: 1_283_452_000 picoseconds. + Weight::from_parts(1_066_445_083, 2523990) + // Standard Error: 9_120 + .saturating_add(Weight::from_parts(195_960, 0).saturating_mul(m.into())) + // Standard Error: 9_120 + .saturating_add(Weight::from_parts(7_706_045, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) @@ -869,8 +873,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 49_055_000 picoseconds. - Weight::from_parts(50_592_000, 4326) + // Minimum execution time: 55_122_000 picoseconds. + Weight::from_parts(56_437_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -890,8 +894,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 47_102_000 picoseconds. - Weight::from_parts(48_772_000, 4326) + // Minimum execution time: 53_137_000 picoseconds. + Weight::from_parts(54_307_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -917,8 +921,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `564` // Estimated: `4326` - // Minimum execution time: 52_968_000 picoseconds. - Weight::from_parts(55_136_000, 4326) + // Minimum execution time: 59_107_000 picoseconds. + Weight::from_parts(60_638_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -942,8 +946,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `593` // Estimated: `4326` - // Minimum execution time: 41_140_000 picoseconds. - Weight::from_parts(43_288_000, 4326) + // Minimum execution time: 47_355_000 picoseconds. + Weight::from_parts(48_729_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -958,10 +962,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `763 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 14_433_000 picoseconds. - Weight::from_parts(14_664_000, 3549) - // Standard Error: 23_078 - .saturating_add(Weight::from_parts(15_911_377, 0).saturating_mul(i.into())) + // Minimum execution time: 19_597_000 picoseconds. + Weight::from_parts(19_920_000, 3549) + // Standard Error: 25_051 + .saturating_add(Weight::from_parts(18_457_577, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) @@ -975,8 +979,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 18_307_000 picoseconds. - Weight::from_parts(18_966_000, 3534) + // Minimum execution time: 23_838_000 picoseconds. + Weight::from_parts(24_765_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -988,8 +992,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 18_078_000 picoseconds. - Weight::from_parts(18_593_000, 3534) + // Minimum execution time: 24_030_000 picoseconds. + Weight::from_parts(24_589_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1001,8 +1005,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 15_175_000 picoseconds. - Weight::from_parts(15_762_000, 3549) + // Minimum execution time: 20_505_000 picoseconds. + Weight::from_parts(20_809_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1018,8 +1022,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `562` // Estimated: `3593` - // Minimum execution time: 26_164_000 picoseconds. - Weight::from_parts(27_117_000, 3593) + // Minimum execution time: 32_314_000 picoseconds. + Weight::from_parts(33_213_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1031,8 +1035,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `369` // Estimated: `6078` - // Minimum execution time: 38_523_000 picoseconds. - Weight::from_parts(39_486_000, 6078) + // Minimum execution time: 44_563_000 picoseconds. + Weight::from_parts(45_899_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1044,8 +1048,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `311` // Estimated: `3549` - // Minimum execution time: 15_733_000 picoseconds. - Weight::from_parts(16_227_000, 3549) + // Minimum execution time: 20_515_000 picoseconds. + Weight::from_parts(21_125_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1057,8 +1061,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `276` // Estimated: `3549` - // Minimum execution time: 12_042_000 picoseconds. - Weight::from_parts(12_690_000, 3549) + // Minimum execution time: 16_933_000 picoseconds. + Weight::from_parts(17_552_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1070,8 +1074,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 17_165_000 picoseconds. - Weight::from_parts(17_769_000, 3534) + // Minimum execution time: 22_652_000 picoseconds. + Weight::from_parts(23_655_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1089,8 +1093,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `539` // Estimated: `3944` - // Minimum execution time: 48_862_000 picoseconds. - Weight::from_parts(50_584_000, 3944) + // Minimum execution time: 56_832_000 picoseconds. + Weight::from_parts(58_480_000, 3944) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1102,8 +1106,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `344` // Estimated: `3944` - // Minimum execution time: 24_665_000 picoseconds. - Weight::from_parts(25_465_000, 3944) + // Minimum execution time: 30_136_000 picoseconds. + Weight::from_parts(30_919_000, 3944) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1119,8 +1123,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `983` // Estimated: `3944` - // Minimum execution time: 44_617_000 picoseconds. - Weight::from_parts(46_458_000, 3944) + // Minimum execution time: 52_264_000 picoseconds. + Weight::from_parts(53_806_000, 3944) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1132,8 +1136,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381` // Estimated: `4326` - // Minimum execution time: 15_710_000 picoseconds. - Weight::from_parts(16_191_000, 4326) + // Minimum execution time: 20_476_000 picoseconds. + Weight::from_parts(21_213_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1150,10 +1154,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `831 + n * (398 ±0)` // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 24_447_000 picoseconds. - Weight::from_parts(25_144_000, 4326) - // Standard Error: 4_872 - .saturating_add(Weight::from_parts(6_523_101, 0).saturating_mul(n.into())) + // Minimum execution time: 30_667_000 picoseconds. + Weight::from_parts(31_079_000, 4326) + // Standard Error: 5_236 + .saturating_add(Weight::from_parts(7_517_246, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1174,8 +1178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `539` // Estimated: `3812` - // Minimum execution time: 39_990_000 picoseconds. - Weight::from_parts(41_098_000, 3812) + // Minimum execution time: 46_520_000 picoseconds. + Weight::from_parts(47_471_000, 3812) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1191,8 +1195,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `849` // Estimated: `3812` - // Minimum execution time: 38_030_000 picoseconds. - Weight::from_parts(39_842_000, 3812) + // Minimum execution time: 44_199_000 picoseconds. + Weight::from_parts(45_621_000, 3812) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1208,8 +1212,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `398` // Estimated: `3759` - // Minimum execution time: 36_778_000 picoseconds. - Weight::from_parts(38_088_000, 3759) + // Minimum execution time: 41_260_000 picoseconds. + Weight::from_parts(42_420_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1225,8 +1229,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `716` // Estimated: `3759` - // Minimum execution time: 36_887_000 picoseconds. - Weight::from_parts(38_406_000, 3759) + // Minimum execution time: 40_975_000 picoseconds. + Weight::from_parts(42_367_000, 3759) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1238,8 +1242,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `410` // Estimated: `4326` - // Minimum execution time: 18_734_000 picoseconds. - Weight::from_parts(19_267_000, 4326) + // Minimum execution time: 23_150_000 picoseconds. + Weight::from_parts(24_089_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1249,8 +1253,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 16_080_000 picoseconds. - Weight::from_parts(16_603_000, 4326) + // Minimum execution time: 20_362_000 picoseconds. + Weight::from_parts(21_102_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1260,8 +1264,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 15_013_000 picoseconds. - Weight::from_parts(15_607_000, 4326) + // Minimum execution time: 19_564_000 picoseconds. + Weight::from_parts(20_094_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1271,8 +1275,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3517` - // Minimum execution time: 13_077_000 picoseconds. - Weight::from_parts(13_635_000, 3517) + // Minimum execution time: 13_360_000 picoseconds. + Weight::from_parts(13_943_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1284,8 +1288,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 17_146_000 picoseconds. - Weight::from_parts(17_453_000, 3549) + // Minimum execution time: 21_304_000 picoseconds. + Weight::from_parts(22_021_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1297,8 +1301,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `323` // Estimated: `3538` - // Minimum execution time: 16_102_000 picoseconds. - Weight::from_parts(16_629_000, 3538) + // Minimum execution time: 20_888_000 picoseconds. + Weight::from_parts(21_600_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1314,8 +1318,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `518` // Estimated: `4326` - // Minimum execution time: 22_118_000 picoseconds. - Weight::from_parts(22_849_000, 4326) + // Minimum execution time: 27_414_000 picoseconds. + Weight::from_parts(28_382_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1339,8 +1343,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `705` // Estimated: `4326` - // Minimum execution time: 50_369_000 picoseconds. - Weight::from_parts(51_816_000, 4326) + // Minimum execution time: 55_660_000 picoseconds. + Weight::from_parts(57_720_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1349,10 +1353,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_203_000 picoseconds. - Weight::from_parts(3_710_869, 0) - // Standard Error: 8_094 - .saturating_add(Weight::from_parts(2_201_869, 0).saturating_mul(n.into())) + // Minimum execution time: 2_064_000 picoseconds. + Weight::from_parts(3_432_697, 0) + // Standard Error: 6_920 + .saturating_add(Weight::from_parts(1_771_459, 0).saturating_mul(n.into())) } /// Storage: `Nfts::Item` (r:2 w:0) /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) @@ -1362,8 +1366,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `494` // Estimated: `7662` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(19_506_000, 7662) + // Minimum execution time: 24_590_000 picoseconds. + Weight::from_parts(25_395_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1375,8 +1379,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `513` // Estimated: `4326` - // Minimum execution time: 19_086_000 picoseconds. - Weight::from_parts(19_609_000, 4326) + // Minimum execution time: 22_121_000 picoseconds. + Weight::from_parts(23_196_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1400,8 +1404,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `834` // Estimated: `7662` - // Minimum execution time: 84_103_000 picoseconds. - Weight::from_parts(85_325_000, 7662) + // Minimum execution time: 85_761_000 picoseconds. + Weight::from_parts(88_382_000, 7662) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -1428,10 +1432,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `629` // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 128_363_000 picoseconds. - Weight::from_parts(139_474_918, 6078) - // Standard Error: 79_252 - .saturating_add(Weight::from_parts(31_384_027, 0).saturating_mul(n.into())) + // Minimum execution time: 136_928_000 picoseconds. + Weight::from_parts(143_507_020, 6078) + // Standard Error: 45_424 + .saturating_add(Weight::from_parts(32_942_641, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1455,10 +1459,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `659` // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_688_000 picoseconds. - Weight::from_parts(79_208_379, 4326) - // Standard Error: 74_020 - .saturating_add(Weight::from_parts(31_028_221, 0).saturating_mul(n.into())) + // Minimum execution time: 72_412_000 picoseconds. + Weight::from_parts(84_724_399, 4326) + // Standard Error: 68_965 + .saturating_add(Weight::from_parts(31_711_702, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index 78e086d0ed12..ec1a5d93bcba 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -17,10 +17,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/nis/src/weights.rs b/substrate/frame/nis/src/weights.rs index a2411c1e39a6..4f476fd22c21 100644 --- a/substrate/frame/nis/src/weights.rs +++ b/substrate/frame/nis/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_nis` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -70,7 +70,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Nis::Queues` (r:1 w:1) /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nis::QueueTotals` (r:1 w:1) /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 999]`. @@ -78,32 +78,32 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6210 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_065_000 picoseconds. - Weight::from_parts(52_894_557, 51487) - // Standard Error: 275 - .saturating_add(Weight::from_parts(48_441, 0).saturating_mul(l.into())) + // Minimum execution time: 47_511_000 picoseconds. + Weight::from_parts(49_908_184, 51487) + // Standard Error: 1_434 + .saturating_add(Weight::from_parts(104_320, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Nis::Queues` (r:1 w:1) /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nis::QueueTotals` (r:1 w:1) /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) fn place_bid_max() -> Weight { // Proof Size summary in bytes: // Measured: `54212` // Estimated: `51487` - // Minimum execution time: 111_930_000 picoseconds. - Weight::from_parts(114_966_000, 51487) + // Minimum execution time: 163_636_000 picoseconds. + Weight::from_parts(172_874_000, 51487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Nis::Queues` (r:1 w:1) /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nis::QueueTotals` (r:1 w:1) /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 1000]`. @@ -111,10 +111,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6210 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_726_000 picoseconds. - Weight::from_parts(48_162_043, 51487) - // Standard Error: 187 - .saturating_add(Weight::from_parts(38_372, 0).saturating_mul(l.into())) + // Minimum execution time: 52_140_000 picoseconds. + Weight::from_parts(46_062_457, 51487) + // Standard Error: 1_320 + .saturating_add(Weight::from_parts(91_098, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -126,15 +126,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `225` // Estimated: `3593` - // Minimum execution time: 31_194_000 picoseconds. - Weight::from_parts(32_922_000, 3593) + // Minimum execution time: 35_741_000 picoseconds. + Weight::from_parts(36_659_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Nis::Receipts` (r:1 w:1) /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nis::Summary` (r:1 w:1) @@ -146,9 +146,9 @@ impl WeightInfo for SubstrateWeight { fn communify() -> Weight { // Proof Size summary in bytes: // Measured: `702` - // Estimated: `3675` - // Minimum execution time: 73_288_000 picoseconds. - Weight::from_parts(76_192_000, 3675) + // Estimated: `3820` + // Minimum execution time: 78_797_000 picoseconds. + Weight::from_parts(81_863_000, 3820) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -163,13 +163,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Assets::Account` (r:1 w:1) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn privatize() -> Weight { // Proof Size summary in bytes: // Measured: `863` - // Estimated: `3675` - // Minimum execution time: 94_307_000 picoseconds. - Weight::from_parts(96_561_000, 3675) + // Estimated: `3820` + // Minimum execution time: 100_374_000 picoseconds. + Weight::from_parts(103_660_000, 3820) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -180,13 +180,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `388` - // Estimated: `3658` - // Minimum execution time: 49_873_000 picoseconds. - Weight::from_parts(51_361_000, 3658) + // Estimated: `3820` + // Minimum execution time: 58_624_000 picoseconds. + Weight::from_parts(60_177_000, 3820) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -204,8 +204,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `807` // Estimated: `3675` - // Minimum execution time: 96_884_000 picoseconds. - Weight::from_parts(98_867_000, 3675) + // Minimum execution time: 98_193_000 picoseconds. + Weight::from_parts(101_255_000, 3675) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -219,8 +219,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6658` // Estimated: `7487` - // Minimum execution time: 21_019_000 picoseconds. - Weight::from_parts(22_057_000, 7487) + // Minimum execution time: 29_640_000 picoseconds. + Weight::from_parts(31_768_000, 7487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -230,8 +230,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `51487` - // Minimum execution time: 4_746_000 picoseconds. - Weight::from_parts(4_953_000, 51487) + // Minimum execution time: 5_273_000 picoseconds. + Weight::from_parts(5_461_000, 51487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -241,8 +241,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_836_000 picoseconds. - Weight::from_parts(5_093_000, 0) + // Minimum execution time: 4_553_000 picoseconds. + Weight::from_parts(4_726_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -252,7 +252,7 @@ impl WeightInfo for () { /// Storage: `Nis::Queues` (r:1 w:1) /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nis::QueueTotals` (r:1 w:1) /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 999]`. @@ -260,32 +260,32 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6210 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_065_000 picoseconds. - Weight::from_parts(52_894_557, 51487) - // Standard Error: 275 - .saturating_add(Weight::from_parts(48_441, 0).saturating_mul(l.into())) + // Minimum execution time: 47_511_000 picoseconds. + Weight::from_parts(49_908_184, 51487) + // Standard Error: 1_434 + .saturating_add(Weight::from_parts(104_320, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Nis::Queues` (r:1 w:1) /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nis::QueueTotals` (r:1 w:1) /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) fn place_bid_max() -> Weight { // Proof Size summary in bytes: // Measured: `54212` // Estimated: `51487` - // Minimum execution time: 111_930_000 picoseconds. - Weight::from_parts(114_966_000, 51487) + // Minimum execution time: 163_636_000 picoseconds. + Weight::from_parts(172_874_000, 51487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Nis::Queues` (r:1 w:1) /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Nis::QueueTotals` (r:1 w:1) /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 1000]`. @@ -293,10 +293,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6210 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_726_000 picoseconds. - Weight::from_parts(48_162_043, 51487) - // Standard Error: 187 - .saturating_add(Weight::from_parts(38_372, 0).saturating_mul(l.into())) + // Minimum execution time: 52_140_000 picoseconds. + Weight::from_parts(46_062_457, 51487) + // Standard Error: 1_320 + .saturating_add(Weight::from_parts(91_098, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -308,15 +308,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `225` // Estimated: `3593` - // Minimum execution time: 31_194_000 picoseconds. - Weight::from_parts(32_922_000, 3593) + // Minimum execution time: 35_741_000 picoseconds. + Weight::from_parts(36_659_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Nis::Receipts` (r:1 w:1) /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Nis::Summary` (r:1 w:1) @@ -328,9 +328,9 @@ impl WeightInfo for () { fn communify() -> Weight { // Proof Size summary in bytes: // Measured: `702` - // Estimated: `3675` - // Minimum execution time: 73_288_000 picoseconds. - Weight::from_parts(76_192_000, 3675) + // Estimated: `3820` + // Minimum execution time: 78_797_000 picoseconds. + Weight::from_parts(81_863_000, 3820) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -345,13 +345,13 @@ impl WeightInfo for () { /// Storage: `Assets::Account` (r:1 w:1) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn privatize() -> Weight { // Proof Size summary in bytes: // Measured: `863` - // Estimated: `3675` - // Minimum execution time: 94_307_000 picoseconds. - Weight::from_parts(96_561_000, 3675) + // Estimated: `3820` + // Minimum execution time: 100_374_000 picoseconds. + Weight::from_parts(103_660_000, 3820) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -362,13 +362,13 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `388` - // Estimated: `3658` - // Minimum execution time: 49_873_000 picoseconds. - Weight::from_parts(51_361_000, 3658) + // Estimated: `3820` + // Minimum execution time: 58_624_000 picoseconds. + Weight::from_parts(60_177_000, 3820) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -386,8 +386,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `807` // Estimated: `3675` - // Minimum execution time: 96_884_000 picoseconds. - Weight::from_parts(98_867_000, 3675) + // Minimum execution time: 98_193_000 picoseconds. + Weight::from_parts(101_255_000, 3675) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -401,8 +401,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6658` // Estimated: `7487` - // Minimum execution time: 21_019_000 picoseconds. - Weight::from_parts(22_057_000, 7487) + // Minimum execution time: 29_640_000 picoseconds. + Weight::from_parts(31_768_000, 7487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -412,8 +412,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `51487` - // Minimum execution time: 4_746_000 picoseconds. - Weight::from_parts(4_953_000, 51487) + // Minimum execution time: 5_273_000 picoseconds. + Weight::from_parts(5_461_000, 51487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -423,8 +423,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_836_000 picoseconds. - Weight::from_parts(5_093_000, 0) + // Minimum execution time: 4_553_000 picoseconds. + Weight::from_parts(4_726_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index 82aecc21d0b5..174736493934 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index aa90e4d81339..a5e8da17eb23 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -26,11 +26,11 @@ scale-info = { features = [ # FRAME frame-support = { workspace = true } frame-system = { workspace = true } -sp-runtime = { workspace = true } -sp-staking = { workspace = true } +log = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } -log = { workspace = true } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } # Optional: use for testing and/or fuzzing pallet-balances = { optional = true, workspace = true } diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index 7dd826a91224..0b3ac228e86f 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -26,9 +26,9 @@ frame-election-provider-support = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-bags-list = { workspace = true } -pallet-staking = { workspace = true } pallet-delegated-staking = { workspace = true } pallet-nomination-pools = { workspace = true } +pallet-staking = { workspace = true } # Substrate Primitives sp-runtime = { workspace = true } @@ -37,8 +37,8 @@ sp-staking = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true } -pallet-timestamp = { workspace = true, default-features = true } pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index b0c8f3655a50..7ddb78cca3f9 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -18,7 +18,7 @@ //! Benchmarks for the nomination pools coupled with the staking and bags list pallets. use alloc::{vec, vec::Vec}; -use frame_benchmarking::v1::{account, whitelist_account}; +use frame_benchmarking::v2::*; use frame_election_provider_support::SortedListProvider; use frame_support::{ assert_ok, ensure, @@ -270,19 +270,21 @@ impl ListScenario { } } -frame_benchmarking::benchmarks! { - where_clause { - where - T: pallet_staking::Config, - pallet_staking::BalanceOf: From, - BalanceOf: Into, - } - - join { +#[benchmarks( + where + T: pallet_staking::Config, + pallet_staking::BalanceOf: From, + BalanceOf: Into, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn join() { let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); // setup the worst case list scenario. - let scenario = ListScenario::::new(origin_weight, true)?; + let scenario = ListScenario::::new(origin_weight, true).unwrap(); assert_eq!( T::StakeAdapter::active_stake(Pool::from(scenario.origin1.clone())), origin_weight @@ -291,12 +293,13 @@ frame_benchmarking::benchmarks! { let max_additional = scenario.dest_weight - origin_weight; let joiner_free = CurrencyOf::::minimum_balance() + max_additional; - let joiner: T::AccountId - = create_funded_user_with_balance::("joiner", 0, joiner_free); + let joiner: T::AccountId = create_funded_user_with_balance::("joiner", 0, joiner_free); whitelist_account!(joiner); - }: _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1); + assert_eq!(CurrencyOf::::balance(&joiner), joiner_free - max_additional); assert_eq!( T::StakeAdapter::active_stake(Pool::from(scenario.origin1)), @@ -304,51 +307,64 @@ frame_benchmarking::benchmarks! { ); } - bond_extra_transfer { + #[benchmark] + fn bond_extra_transfer() { let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - let scenario = ListScenario::::new(origin_weight, true)?; + let scenario = ListScenario::::new(origin_weight, true).unwrap(); let extra = scenario.dest_weight - origin_weight; // creator of the src pool will bond-extra, bumping itself to dest bag. - }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) - verify { + #[extrinsic_call] + bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)); + assert!( - T::StakeAdapter::active_stake(Pool::from(scenario.origin1)) >= - scenario.dest_weight + T::StakeAdapter::active_stake(Pool::from(scenario.origin1)) >= scenario.dest_weight ); } - bond_extra_other { + #[benchmark] + fn bond_extra_other() { let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - let scenario = ListScenario::::new(origin_weight, true)?; + let scenario = ListScenario::::new(origin_weight, true).unwrap(); let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); - // set claim preferences to `PermissionlessAll` to any account to bond extra on member's behalf. - let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(scenario.creator1.clone()).into(), ClaimPermission::PermissionlessAll); + // set claim preferences to `PermissionlessAll` to any account to bond extra on member's + // behalf. + let _ = Pools::::set_claim_permission( + RuntimeOrigin::Signed(scenario.creator1.clone()).into(), + ClaimPermission::PermissionlessAll, + ); // transfer exactly `extra` to the depositor of the src pool (1), let reward_account1 = Pools::::generate_reward_account(1); assert!(extra >= CurrencyOf::::minimum_balance()); let _ = CurrencyOf::::mint_into(&reward_account1, extra); - }: _(RuntimeOrigin::Signed(claimer), T::Lookup::unlookup(scenario.creator1.clone()), BondExtra::Rewards) - verify { - // commission of 50% deducted here. + #[extrinsic_call] + _( + RuntimeOrigin::Signed(claimer), + T::Lookup::unlookup(scenario.creator1.clone()), + BondExtra::Rewards, + ); + + // commission of 50% deducted here. assert!( T::StakeAdapter::active_stake(Pool::from(scenario.origin1)) >= - scenario.dest_weight / 2u32.into() + scenario.dest_weight / 2u32.into() ); } - claim_payout { + #[benchmark] + fn claim_payout() { let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); let commission = Perbill::from_percent(50); let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); - let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); + let (depositor, _pool_account) = + create_pool_account::(0, origin_weight, Some(commission)); let reward_account = Pools::::generate_reward_account(1); // Send funds to the reward account of the pool @@ -356,33 +372,32 @@ frame_benchmarking::benchmarks! { // set claim preferences to `PermissionlessAll` so any account can claim rewards on member's // behalf. - let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(depositor.clone()).into(), ClaimPermission::PermissionlessAll); + let _ = Pools::::set_claim_permission( + RuntimeOrigin::Signed(depositor.clone()).into(), + ClaimPermission::PermissionlessAll, + ); // Sanity check - assert_eq!( - CurrencyOf::::balance(&depositor), - origin_weight - ); + assert_eq!(CurrencyOf::::balance(&depositor), origin_weight); whitelist_account!(depositor); - }:claim_payout_other(RuntimeOrigin::Signed(claimer), depositor.clone()) - verify { + + #[extrinsic_call] + claim_payout_other(RuntimeOrigin::Signed(claimer), depositor.clone()); + assert_eq!( CurrencyOf::::balance(&depositor), origin_weight + commission * origin_weight ); - assert_eq!( - CurrencyOf::::balance(&reward_account), - ed + commission * origin_weight - ); + assert_eq!(CurrencyOf::::balance(&reward_account), ed + commission * origin_weight); } - - unbond { + #[benchmark] + fn unbond() { // The weight the nominator will start at. The value used here is expected to be // significantly higher than the first position in a list (e.g. the first bag threshold). let origin_weight = Pools::::depositor_min_bond() * 200u32.into(); - let scenario = ListScenario::::new(origin_weight, false)?; + let scenario = ListScenario::::new(origin_weight, false).unwrap(); let amount = origin_weight - scenario.dest_weight; let scenario = scenario.add_joiner(amount); @@ -390,36 +405,30 @@ frame_benchmarking::benchmarks! { let member_id_lookup = T::Lookup::unlookup(member_id.clone()); let all_points = PoolMembers::::get(&member_id).unwrap().points; whitelist_account!(member_id); - }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points); + let bonded_after = T::StakeAdapter::active_stake(Pool::from(scenario.origin1)); // We at least went down to the destination bag assert!(bonded_after <= scenario.dest_weight); - let member = PoolMembers::::get( - &member_id - ) - .unwrap(); + let member = PoolMembers::::get(&member_id).unwrap(); assert_eq!( member.unbonding_eras.keys().cloned().collect::>(), vec![0 + T::StakeAdapter::bonding_duration()] ); - assert_eq!( - member.unbonding_eras.values().cloned().collect::>(), - vec![all_points] - ); + assert_eq!(member.unbonding_eras.values().cloned().collect::>(), vec![all_points]); } - pool_withdraw_unbonded { - let s in 0 .. MAX_SPANS; - + #[benchmark] + fn pool_withdraw_unbonded(s: Linear<0, MAX_SPANS>) { let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + let (_depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) - .unwrap(); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1).unwrap(); // Sanity check join worked assert_eq!( @@ -429,7 +438,8 @@ frame_benchmarking::benchmarks! { assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); // Unbond the new member - Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()) + .unwrap(); // Sanity check that unbond worked assert_eq!( @@ -443,26 +453,26 @@ frame_benchmarking::benchmarks! { // Add `s` count of slashing spans to storage. pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(pool_account); - }: _(RuntimeOrigin::Signed(pool_account.clone()), 1, s) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(pool_account.clone()), 1, s); + // The joiners funds didn't change assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); // The unlocking chunk was removed assert_eq!(pallet_staking::Ledger::::get(pool_account).unwrap().unlocking.len(), 0); } - withdraw_unbonded_update { - let s in 0 .. MAX_SPANS; - + #[benchmark] + fn withdraw_unbonded_update(s: Linear<0, MAX_SPANS>) { let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + let (_depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) - .unwrap(); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1).unwrap(); // Sanity check join worked assert_eq!( @@ -473,7 +483,8 @@ frame_benchmarking::benchmarks! { // Unbond the new member pallet_staking::CurrentEra::::put(0); - Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()) + .unwrap(); // Sanity check that unbond worked assert_eq!( @@ -487,18 +498,17 @@ frame_benchmarking::benchmarks! { pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(joiner); - }: withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s) - verify { - assert_eq!( - CurrencyOf::::balance(&joiner), min_join_bond * 2u32.into() - ); + + #[extrinsic_call] + withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s); + + assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond * 2u32.into()); // The unlocking chunk was removed assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 0); } - withdraw_unbonded_kill { - let s in 0 .. MAX_SPANS; - + #[benchmark] + fn withdraw_unbonded_kill(s: Linear<0, MAX_SPANS>) { let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); @@ -519,13 +529,14 @@ frame_benchmarking::benchmarks! { // up when unbonding. let reward_account = Pools::::generate_reward_account(1); assert!(frame_system::Account::::contains_key(&reward_account)); - Pools::::fully_unbond(RuntimeOrigin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); + Pools::::fully_unbond( + RuntimeOrigin::Signed(depositor.clone()).into(), + depositor.clone(), + ) + .unwrap(); // Sanity check that unbond worked - assert_eq!( - T::StakeAdapter::active_stake(Pool::from(pool_account.clone())), - Zero::zero() - ); + assert_eq!(T::StakeAdapter::active_stake(Pool::from(pool_account.clone())), Zero::zero()); assert_eq!( T::StakeAdapter::total_balance(Pool::from(pool_account.clone())), Some(min_create_bond) @@ -544,8 +555,10 @@ frame_benchmarking::benchmarks! { assert!(frame_system::Account::::contains_key(&reward_account)); whitelist_account!(depositor); - }: withdraw_unbonded(RuntimeOrigin::Signed(depositor.clone()), depositor_lookup, s) - verify { + + #[extrinsic_call] + withdraw_unbonded(RuntimeOrigin::Signed(depositor.clone()), depositor_lookup, s); + // Pool removal worked assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); assert!(!BondedPools::::contains_key(&1)); @@ -563,27 +576,34 @@ frame_benchmarking::benchmarks! { ); } - create { + #[benchmark] + fn create() { let min_create_bond = Pools::::depositor_min_bond(); let depositor: T::AccountId = account("depositor", USER_SEED, 0); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // Give the depositor some balance to bond - // it needs to transfer min balance to reward account as well so give additional min balance. - CurrencyOf::::set_balance(&depositor, min_create_bond + CurrencyOf::::minimum_balance() * 2u32.into()); + // it needs to transfer min balance to reward account as well so give additional min + // balance. + CurrencyOf::::set_balance( + &depositor, + min_create_bond + CurrencyOf::::minimum_balance() * 2u32.into(), + ); // Make sure no Pools exist at a pre-condition for our verify checks assert_eq!(RewardPools::::count(), 0); assert_eq!(BondedPools::::count(), 0); whitelist_account!(depositor); - }: _( + + #[extrinsic_call] + _( RuntimeOrigin::Signed(depositor.clone()), min_create_bond, depositor_lookup.clone(), depositor_lookup.clone(), - depositor_lookup - ) - verify { + depositor_lookup, + ); + assert_eq!(RewardPools::::count(), 1); assert_eq!(BondedPools::::count(), 1); let (_, new_pool) = BondedPools::::iter().next().unwrap(); @@ -608,22 +628,21 @@ frame_benchmarking::benchmarks! { ); } - nominate { - let n in 1 .. MaxNominationsOf::::get(); - + #[benchmark] + fn nominate(n: Linear<1, { MaxNominationsOf::::get() }>) { // Create a pool let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + let (depositor, _pool_account) = create_pool_account::(0, min_create_bond, None); // Create some accounts to nominate. For the sake of benchmarking they don't need to be // actual validators - let validators: Vec<_> = (0..n) - .map(|i| account("stash", USER_SEED, i)) - .collect(); + let validators: Vec<_> = (0..n).map(|i| account("stash", USER_SEED, i)).collect(); whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1, validators) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(depositor.clone()), 1, validators); + assert_eq!(RewardPools::::count(), 1); assert_eq!(BondedPools::::count(), 1); let (_, new_pool) = BondedPools::::iter().next().unwrap(); @@ -648,10 +667,12 @@ frame_benchmarking::benchmarks! { ); } - set_state { + #[benchmark] + fn set_state() { // Create a pool let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + // Don't need the accounts, but the pool. + let _ = create_pool_account::(0, min_create_bond, None); BondedPools::::mutate(&1, |maybe_pool| { // Force the pool into an invalid state maybe_pool.as_mut().map(|pool| pool.points = min_create_bond * 10u32.into()); @@ -659,36 +680,44 @@ frame_benchmarking::benchmarks! { let caller = account("caller", 0, USER_SEED); whitelist_account!(caller); - }:_(RuntimeOrigin::Signed(caller), 1, PoolState::Destroying) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(caller), 1, PoolState::Destroying); + assert_eq!(BondedPools::::get(1).unwrap().state, PoolState::Destroying); } - set_metadata { - let n in 1 .. ::MaxMetadataLen::get(); - + #[benchmark] + fn set_metadata( + n: Linear<1, { ::MaxMetadataLen::get() }>, + ) { // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + let (depositor, _pool_account) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); // Create metadata of the max possible size let metadata: Vec = (0..n).map(|_| 42).collect(); whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor), 1, metadata.clone()) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(depositor), 1, metadata.clone()); assert_eq!(Metadata::::get(&1), metadata); } - set_configs { - }:_( - RuntimeOrigin::Root, - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(Perbill::max_value()) - ) verify { + #[benchmark] + fn set_configs() { + #[extrinsic_call] + _( + RuntimeOrigin::Root, + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(Perbill::max_value()), + ); + assert_eq!(MinJoinBond::::get(), BalanceOf::::max_value()); assert_eq!(MinCreateBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxPools::::get(), Some(u32::MAX)); @@ -697,17 +726,22 @@ frame_benchmarking::benchmarks! { assert_eq!(GlobalMaxCommission::::get(), Some(Perbill::max_value())); } - update_roles { + #[benchmark] + fn update_roles() { let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; - let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); - }:_( - RuntimeOrigin::Signed(root.clone()), - first_id, - ConfigOp::Set(random.clone()), - ConfigOp::Set(random.clone()), - ConfigOp::Set(random.clone()) - ) verify { + let (root, _) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + let random: T::AccountId = + account("but is anything really random in computers..?", 0, USER_SEED); + + #[extrinsic_call] + _( + RuntimeOrigin::Signed(root.clone()), + first_id, + ConfigOp::Set(random.clone()), + ConfigOp::Set(random.clone()), + ConfigOp::Set(random.clone()), + ); assert_eq!( pallet_nomination_pools::BondedPools::::get(first_id).unwrap().roles, pallet_nomination_pools::PoolRoles { @@ -719,12 +753,14 @@ frame_benchmarking::benchmarks! { ) } - chill { + #[benchmark] + fn chill() { // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + let (depositor, pool_account) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); // Nominate with the pool. - let validators: Vec<_> = (0..MaxNominationsOf::::get()) + let validators: Vec<_> = (0..MaxNominationsOf::::get()) .map(|i| account("stash", USER_SEED, i)) .collect(); @@ -732,121 +768,176 @@ frame_benchmarking::benchmarks! { assert!(T::StakeAdapter::nominations(Pool::from(pool_account.clone())).is_some()); whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(depositor.clone()), 1); + assert!(T::StakeAdapter::nominations(Pool::from(pool_account.clone())).is_none()); } - set_commission { + #[benchmark] + fn set_commission() { // Create a pool - do not set a commission yet. - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + let (depositor, _pool_account) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); // set a max commission - Pools::::set_commission_max(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), Perbill::from_percent(50)).unwrap(); + Pools::::set_commission_max( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + Perbill::from_percent(50), + ) + .unwrap(); // set a change rate - Pools::::set_commission_change_rate(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), CommissionChangeRate { - max_increase: Perbill::from_percent(20), - min_delay: 0u32.into(), - }).unwrap(); + Pools::::set_commission_change_rate( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + CommissionChangeRate { + max_increase: Perbill::from_percent(20), + min_delay: 0u32.into(), + }, + ) + .unwrap(); // set a claim permission to an account. Pools::::set_commission_claim_permission( RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), - Some(CommissionClaimPermission::Account(depositor.clone())) - ).unwrap(); - - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some((Perbill::from_percent(20), depositor.clone()))) - verify { - assert_eq!(BondedPools::::get(1).unwrap().commission, Commission { - current: Some((Perbill::from_percent(20), depositor.clone())), - max: Some(Perbill::from_percent(50)), - change_rate: Some(CommissionChangeRate { + Some(CommissionClaimPermission::Account(depositor.clone())), + ) + .unwrap(); + + #[extrinsic_call] + _( + RuntimeOrigin::Signed(depositor.clone()), + 1u32.into(), + Some((Perbill::from_percent(20), depositor.clone())), + ); + + assert_eq!( + BondedPools::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(20), depositor.clone())), + max: Some(Perbill::from_percent(50)), + change_rate: Some(CommissionChangeRate { max_increase: Perbill::from_percent(20), min_delay: 0u32.into() - }), - throttle_from: Some(1u32.into()), - claim_permission: Some(CommissionClaimPermission::Account(depositor)), - }); + }), + throttle_from: Some(1u32.into()), + claim_permission: Some(CommissionClaimPermission::Account(depositor)), + } + ); } - set_commission_max { + #[benchmark] + fn set_commission_max() { // Create a pool, setting a commission that will update when max commission is set. - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), Some(Perbill::from_percent(50))); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Perbill::from_percent(50)) - verify { + let (depositor, _pool_account) = create_pool_account::( + 0, + Pools::::depositor_min_bond() * 2u32.into(), + Some(Perbill::from_percent(50)), + ); + + #[extrinsic_call] + _(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Perbill::from_percent(50)); + assert_eq!( - BondedPools::::get(1).unwrap().commission, Commission { - current: Some((Perbill::from_percent(50), depositor)), - max: Some(Perbill::from_percent(50)), - change_rate: None, - throttle_from: Some(0u32.into()), - claim_permission: None, - }); + BondedPools::::get(1).unwrap().commission, + Commission { + current: Some((Perbill::from_percent(50), depositor)), + max: Some(Perbill::from_percent(50)), + change_rate: None, + throttle_from: Some(0u32.into()), + claim_permission: None, + } + ); } - set_commission_change_rate { + #[benchmark] + fn set_commission_change_rate() { // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), CommissionChangeRate { - max_increase: Perbill::from_percent(50), - min_delay: 1000u32.into(), - }) - verify { - assert_eq!( - BondedPools::::get(1).unwrap().commission, Commission { - current: None, - max: None, - change_rate: Some(CommissionChangeRate { + let (depositor, _pool_account) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + + #[extrinsic_call] + _( + RuntimeOrigin::Signed(depositor.clone()), + 1u32.into(), + CommissionChangeRate { max_increase: Perbill::from_percent(50), min_delay: 1000u32.into(), - }), - throttle_from: Some(1_u32.into()), - claim_permission: None, - }); - } + }, + ); + + assert_eq!( + BondedPools::::get(1).unwrap().commission, + Commission { + current: None, + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(50), + min_delay: 1000u32.into(), + }), + throttle_from: Some(1_u32.into()), + claim_permission: None, + } + ); + } - set_commission_claim_permission { + #[benchmark] + fn set_commission_claim_permission() { // Create a pool. - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some(CommissionClaimPermission::Account(depositor.clone()))) - verify { + let (depositor, _pool_account) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + + #[extrinsic_call] + _( + RuntimeOrigin::Signed(depositor.clone()), + 1u32.into(), + Some(CommissionClaimPermission::Account(depositor.clone())), + ); + assert_eq!( - BondedPools::::get(1).unwrap().commission, Commission { - current: None, - max: None, - change_rate: None, - throttle_from: None, - claim_permission: Some(CommissionClaimPermission::Account(depositor)), - }); + BondedPools::::get(1).unwrap().commission, + Commission { + current: None, + max: None, + change_rate: None, + throttle_from: None, + claim_permission: Some(CommissionClaimPermission::Account(depositor)), + } + ); } - set_claim_permission { + #[benchmark] + fn set_claim_permission() { // Create a pool let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + let (_depositor, pool_account) = create_pool_account::(0, min_create_bond, None); // Join pool let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 4u32.into()); - let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) - .unwrap(); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1).unwrap(); // Sanity check join worked assert_eq!( T::StakeAdapter::active_stake(Pool::from(pool_account.clone())), min_create_bond + min_join_bond ); - }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::Permissioned) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::Permissioned); + assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::Permissioned); } - claim_commission { + #[benchmark] + fn claim_commission() { let claimer: T::AccountId = account("claimer_member", USER_SEED + 4, 0); let commission = Perbill::from_percent(50); let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); - let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); + let (depositor, _pool_account) = + create_pool_account::(0, origin_weight, Some(commission)); let reward_account = Pools::::generate_reward_account(1); CurrencyOf::::set_balance(&reward_account, ed + origin_weight); @@ -856,52 +947,60 @@ frame_benchmarking::benchmarks! { let _ = Pools::::set_commission_claim_permission( RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), - Some(CommissionClaimPermission::Account(claimer)) + Some(CommissionClaimPermission::Account(claimer)), ); whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()); + assert_eq!( CurrencyOf::::balance(&depositor), origin_weight + commission * origin_weight ); - assert_eq!( - CurrencyOf::::balance(&reward_account), - ed + commission * origin_weight - ); + assert_eq!(CurrencyOf::::balance(&reward_account), ed + commission * origin_weight); } - adjust_pool_deposit { + #[benchmark] + fn adjust_pool_deposit() { // Create a pool - let (depositor, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + let (depositor, _) = + create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); // Remove ed freeze to create a scenario where the ed deposit needs to be adjusted. let _ = Pools::::unfreeze_pool_deposit(&Pools::::generate_reward_account(1)); assert!(&Pools::::check_ed_imbalance().is_err()); whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor), 1) - verify { + + #[extrinsic_call] + _(RuntimeOrigin::Signed(depositor), 1); + assert!(&Pools::::check_ed_imbalance().is_ok()); } - apply_slash { + #[benchmark] + fn apply_slash() { // Note: With older `TransferStake` strategy, slashing is greedy and apply_slash should // always fail. // We want to fill member's unbonding pools. So let's bond with big enough amount. - let deposit_amount = Pools::::depositor_min_bond() * T::MaxUnbonding::get().into() * 4u32.into(); + let deposit_amount = + Pools::::depositor_min_bond() * T::MaxUnbonding::get().into() * 4u32.into(); let (depositor, pool_account) = create_pool_account::(0, deposit_amount, None); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // verify user balance in the pool. assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount); // verify delegated balance. - assert_if_delegate::(T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount)); + assert_if_delegate::( + T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == + Some(deposit_amount), + ); // ugly type conversion between balances of pallet staking and pools (which really are same // type). Maybe there is a better way? - let slash_amount: u128 = deposit_amount.into()/2; + let slash_amount: u128 = deposit_amount.into() / 2; // slash pool by half pallet_staking::slashing::do_slash::( @@ -909,49 +1008,75 @@ frame_benchmarking::benchmarks! { slash_amount.into(), &mut pallet_staking::BalanceOf::::zero(), &mut pallet_staking::NegativeImbalanceOf::::zero(), - EraIndex::zero() + EraIndex::zero(), ); // verify user balance is slashed in the pool. - assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount/2u32.into()); + assert_eq!( + PoolMembers::::get(&depositor).unwrap().total_balance(), + deposit_amount / 2u32.into() + ); // verify delegated balance are not yet slashed. - assert_if_delegate::(T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount)); + assert_if_delegate::( + T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == + Some(deposit_amount), + ); // Fill member's sub pools for the worst case. for i in 1..(T::MaxUnbonding::get() + 1) { pallet_staking::CurrentEra::::put(i); - assert!(Pools::::unbond(RuntimeOrigin::Signed(depositor.clone()).into(), depositor_lookup.clone(), Pools::::depositor_min_bond()).is_ok()); + assert!(Pools::::unbond( + RuntimeOrigin::Signed(depositor.clone()).into(), + depositor_lookup.clone(), + Pools::::depositor_min_bond() + ) + .is_ok()); } pallet_staking::CurrentEra::::put(T::MaxUnbonding::get() + 2); - let slash_reporter = create_funded_user_with_balance::("slasher", 0, CurrencyOf::::minimum_balance()); + let slash_reporter = + create_funded_user_with_balance::("slasher", 0, CurrencyOf::::minimum_balance()); whitelist_account!(depositor); - }: - { - assert_if_delegate::(Pools::::apply_slash(RuntimeOrigin::Signed(slash_reporter.clone()).into(), depositor_lookup.clone()).is_ok()); - } - verify { + + #[block] + { + assert_if_delegate::( + Pools::::apply_slash( + RuntimeOrigin::Signed(slash_reporter.clone()).into(), + depositor_lookup.clone(), + ) + .is_ok(), + ); + } + // verify balances are correct and slash applied. - assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount/2u32.into()); - assert_if_delegate::(T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount/2u32.into())); + assert_eq!( + PoolMembers::::get(&depositor).unwrap().total_balance(), + deposit_amount / 2u32.into() + ); + assert_if_delegate::( + T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == + Some(deposit_amount / 2u32.into()), + ); } - apply_slash_fail { + #[benchmark] + fn apply_slash_fail() { // Bench the scenario where pool has some unapplied slash but the member does not have any // slash to be applied. let deposit_amount = Pools::::depositor_min_bond() * 10u32.into(); // Create pool. - let (depositor, pool_account) = create_pool_account::(0, deposit_amount, None); + let (_depositor, pool_account) = create_pool_account::(0, deposit_amount, None); // slash pool by half - let slash_amount: u128 = deposit_amount.into()/2; + let slash_amount: u128 = deposit_amount.into() / 2; pallet_staking::slashing::do_slash::( &pool_account, slash_amount.into(), &mut pallet_staking::BalanceOf::::zero(), &mut pallet_staking::NegativeImbalanceOf::::zero(), - EraIndex::zero() + EraIndex::zero(), ); pallet_staking::CurrentEra::::put(1); @@ -961,68 +1086,106 @@ frame_benchmarking::benchmarks! { let join_amount = min_join_bond * T::MaxUnbonding::get().into() * 2u32.into(); let joiner = create_funded_user_with_balance::("joiner", 0, join_amount * 2u32.into()); let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - assert!(Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), join_amount, 1).is_ok()); + assert!( + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), join_amount, 1).is_ok() + ); // Fill member's sub pools for the worst case. for i in 0..T::MaxUnbonding::get() { pallet_staking::CurrentEra::::put(i + 2); // +2 because we already set the current era to 1. - assert!(Pools::::unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner_lookup.clone(), min_join_bond).is_ok()); + assert!(Pools::::unbond( + RuntimeOrigin::Signed(joiner.clone()).into(), + joiner_lookup.clone(), + min_join_bond + ) + .is_ok()); } pallet_staking::CurrentEra::::put(T::MaxUnbonding::get() + 3); whitelist_account!(joiner); - }: { - // Since the StakeAdapter can be different based on the runtime config, the errors could be different as well. - assert!(Pools::::apply_slash(RuntimeOrigin::Signed(joiner.clone()).into(), joiner_lookup.clone()).is_err()); + // Since the StakeAdapter can be different based on the runtime config, the errors could be + // different as well. + #[block] + { + assert!(Pools::::apply_slash( + RuntimeOrigin::Signed(joiner.clone()).into(), + joiner_lookup.clone() + ) + .is_err()); + } } - - pool_migrate { + #[benchmark] + fn pool_migrate() { // create a pool. let deposit_amount = Pools::::depositor_min_bond() * 2u32.into(); let (depositor, pool_account) = create_pool_account::(0, deposit_amount, None); // migrate pool to transfer stake. let _ = migrate_to_transfer_stake::(1); - }: { - assert_if_delegate::(Pools::::migrate_pool_to_delegate_stake(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into()).is_ok()); - } - verify { + #[block] + { + assert_if_delegate::( + Pools::::migrate_pool_to_delegate_stake( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + ) + .is_ok(), + ); + } // this queries agent balance if `DelegateStake` strategy. - assert!(T::StakeAdapter::total_balance(Pool::from(pool_account.clone())) == Some(deposit_amount)); + assert_eq!( + T::StakeAdapter::total_balance(Pool::from(pool_account.clone())), + Some(deposit_amount) + ); } - migrate_delegation { + #[benchmark] + fn migrate_delegation() { // create a pool. let deposit_amount = Pools::::depositor_min_bond() * 2u32.into(); - let (depositor, pool_account) = create_pool_account::(0, deposit_amount, None); + let (depositor, _pool_account) = create_pool_account::(0, deposit_amount, None); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // migrate pool to transfer stake. let _ = migrate_to_transfer_stake::(1); // Now migrate pool to delegate stake keeping delegators unmigrated. - assert_if_delegate::(Pools::::migrate_pool_to_delegate_stake(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into()).is_ok()); + assert_if_delegate::( + Pools::::migrate_pool_to_delegate_stake( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + ) + .is_ok(), + ); // delegation does not exist. - assert!(T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())).is_none()); + assert!( + T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())).is_none() + ); // contribution exists in the pool. assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount); whitelist_account!(depositor); - }: { - assert_if_delegate::(Pools::::migrate_delegation(RuntimeOrigin::Signed(depositor.clone()).into(), depositor_lookup.clone()).is_ok()); - } - verify { + + #[block] + { + assert_if_delegate::( + Pools::::migrate_delegation( + RuntimeOrigin::Signed(depositor.clone()).into(), + depositor_lookup.clone(), + ) + .is_ok(), + ); + } // verify balances once more. - assert_if_delegate::(T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount)); + assert_if_delegate::( + T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == + Some(deposit_amount), + ); assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount); } - impl_benchmark_test_suite!( - Pallet, - crate::mock::new_test_ext(), - crate::mock::Runtime - ); + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); } diff --git a/substrate/frame/nomination-pools/fuzzer/Cargo.toml b/substrate/frame/nomination-pools/fuzzer/Cargo.toml index e1518ed099ae..2f84004ece94 100644 --- a/substrate/frame/nomination-pools/fuzzer/Cargo.toml +++ b/substrate/frame/nomination-pools/fuzzer/Cargo.toml @@ -21,15 +21,15 @@ honggfuzz = { workspace = true } pallet-nomination-pools = { features = ["fuzzing"], workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } -rand = { features = ["small_rng"], workspace = true, default-features = true } log = { workspace = true, default-features = true } +rand = { features = ["small_rng"], workspace = true, default-features = true } [[bin]] name = "call" diff --git a/substrate/frame/nomination-pools/runtime-api/Cargo.toml b/substrate/frame/nomination-pools/runtime-api/Cargo.toml index 6de9fc8c8844..337cc31c7cbb 100644 --- a/substrate/frame/nomination-pools/runtime-api/Cargo.toml +++ b/substrate/frame/nomination-pools/runtime-api/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -sp-api = { workspace = true } pallet-nomination-pools = { workspace = true } +sp-api = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/nomination-pools/runtime-api/src/lib.rs b/substrate/frame/nomination-pools/runtime-api/src/lib.rs index d81ad1dd4954..644ee07fd634 100644 --- a/substrate/frame/nomination-pools/runtime-api/src/lib.rs +++ b/substrate/frame/nomination-pools/runtime-api/src/lib.rs @@ -43,6 +43,9 @@ sp_api::decl_runtime_apis! { fn pool_pending_slash(pool_id: PoolId) -> Balance; /// Returns the pending slash for a given pool member. + /// + /// If pending slash of the member exceeds `ExistentialDeposit`, it can be reported on + /// chain. fn member_pending_slash(member: AccountId) -> Balance; /// Returns true if the pool with `pool_id` needs migration. @@ -69,5 +72,8 @@ sp_api::decl_runtime_apis! { /// Total balance contributed to the pool. fn pool_balance(pool_id: PoolId) -> Balance; + + /// Returns the bonded account and reward account associated with the pool_id. + fn pool_accounts(pool_id: PoolId) -> (AccountId, AccountId); } } diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 177c5da74d4f..dc82bf3a37c6 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1944,6 +1944,8 @@ pub mod pallet { NothingToAdjust, /// No slash pending that can be applied to the member. NothingToSlash, + /// The slash amount is too low to be applied. + SlashTooLow, /// The pool or member delegation has already migrated to delegate stake. AlreadyMigrated, /// The pool or member delegation has not migrated yet to delegate stake. @@ -2300,7 +2302,7 @@ pub mod pallet { let slash_weight = // apply slash if any before withdraw. - match Self::do_apply_slash(&member_account, None) { + match Self::do_apply_slash(&member_account, None, false) { Ok(_) => T::WeightInfo::apply_slash(), Err(e) => { let no_pending_slash: DispatchResult = Err(Error::::NothingToSlash.into()); @@ -2974,8 +2976,10 @@ pub mod pallet { /// Fails unless [`crate::pallet::Config::StakeAdapter`] is of strategy type: /// [`adapter::StakeStrategyType::Delegate`]. /// - /// This call can be dispatched permissionlessly (i.e. by any account). If the member has - /// slash to be applied, caller may be rewarded with the part of the slash. + /// The pending slash amount of the member must be equal or more than `ExistentialDeposit`. + /// This call can be dispatched permissionlessly (i.e. by any account). If the execution + /// is successful, fee is refunded and caller may be rewarded with a part of the slash + /// based on the [`crate::pallet::Config::StakeAdapter`] configuration. #[pallet::call_index(23)] #[pallet::weight(T::WeightInfo::apply_slash())] pub fn apply_slash( @@ -2989,7 +2993,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let member_account = T::Lookup::lookup(member_account)?; - Self::do_apply_slash(&member_account, Some(who))?; + Self::do_apply_slash(&member_account, Some(who), true)?; // If successful, refund the fees. Ok(Pays::No.into()) @@ -3574,15 +3578,21 @@ impl Pallet { fn do_apply_slash( member_account: &T::AccountId, reporter: Option, + enforce_min_slash: bool, ) -> DispatchResult { let member = PoolMembers::::get(member_account).ok_or(Error::::PoolMemberNotFound)?; let pending_slash = Self::member_pending_slash(Member::from(member_account.clone()), member.clone())?; - // if nothing to slash, return error. + // ensure there is something to slash. ensure!(!pending_slash.is_zero(), Error::::NothingToSlash); + if enforce_min_slash { + // ensure slashed amount is at least the minimum balance. + ensure!(pending_slash >= T::Currency::minimum_balance(), Error::::SlashTooLow); + } + T::StakeAdapter::member_slash( Member::from(member_account.clone()), Pool::from(Pallet::::generate_bonded_account(member.pool_id)), @@ -3946,6 +3956,9 @@ impl Pallet { /// Returns the unapplied slash of a member. /// /// Pending slash is only applicable with [`adapter::DelegateStake`] strategy. + /// + /// If pending slash of the member exceeds `ExistentialDeposit`, it can be reported on + /// chain via [`Call::apply_slash`]. pub fn api_member_pending_slash(who: T::AccountId) -> BalanceOf { PoolMembers::::get(who.clone()) .map(|pool_member| { @@ -4020,6 +4033,13 @@ impl Pallet { T::StakeAdapter::total_balance(Pool::from(Self::generate_bonded_account(pool_id))) .unwrap_or_default() } + + /// Returns the bonded account and reward account associated with the pool_id. + pub fn api_pool_accounts(pool_id: PoolId) -> (T::AccountId, T::AccountId) { + let bonded_account = Self::generate_bonded_account(pool_id); + let reward_account = Self::generate_reward_account(pool_id); + (bonded_account, reward_account) + } } impl sp_staking::OnStakingUpdate> for Pallet { diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index 21711a499b62..086def4759a8 100644 --- a/substrate/frame/nomination-pools/src/weights.rs +++ b/substrate/frame/nomination-pools/src/weights.rs @@ -1382,4 +1382,4 @@ impl WeightInfo for () { Weight::from_parts(37_038_000, 27847) .saturating_add(RocksDbWeight::get().reads(6_u64)) } -} +} \ No newline at end of file diff --git a/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml b/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml index 7940caaff775..fe3743d7e5da 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml +++ b/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml @@ -19,23 +19,23 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = ["derive"], workspace = true, default-features = true } scale-info = { features = ["derive"], workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-staking = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +frame-support = { features = ["experimental"], workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } +pallet-bags-list = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } pallet-delegated-staking = { workspace = true, default-features = true } -pallet-bags-list = { workspace = true, default-features = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } pallet-nomination-pools = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } log = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 7fee2a0bdb23..cc6335959ab7 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -20,7 +20,7 @@ mod mock; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, hypothetically, traits::{fungible::InspectHold, Currency}, }; use mock::*; @@ -41,7 +41,7 @@ use sp_staking::Agent; fn pool_lifecycle_e2e() { new_test_ext().execute_with(|| { assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); @@ -204,7 +204,7 @@ fn pool_lifecycle_e2e() { fn pool_chill_e2e() { new_test_ext().execute_with(|| { assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); @@ -330,7 +330,7 @@ fn pool_slash_e2e() { new_test_ext().execute_with(|| { ExistentialDeposit::set(1); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); @@ -537,9 +537,9 @@ fn pool_slash_proportional() { // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that // happened in era 100 should only affect the latter two. new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); + ExistentialDeposit::set(2); BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Balances::minimum_balance(), 2); assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. @@ -670,6 +670,34 @@ fn pool_slash_proportional() { // no pending slash yet. assert_eq!(Pools::api_pool_pending_slash(1), 0); + // and therefore applying slash fails + assert_noop!( + Pools::apply_slash(RuntimeOrigin::signed(10), 21), + PoolsError::::NothingToSlash + ); + + hypothetically!({ + // a very small amount is slashed + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 3, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + // ensure correct amount is pending to be slashed + assert_eq!(Pools::api_pool_pending_slash(1), 3); + + // 21 has pending slash lower than ED (2) + assert_eq!(Pools::api_member_pending_slash(21), 1); + + // slash fails as minimum pending slash amount not met. + assert_noop!( + Pools::apply_slash(RuntimeOrigin::signed(10), 21), + PoolsError::::SlashTooLow + ); + }); pallet_staking::slashing::do_slash::( &POOL1_BONDED, @@ -758,7 +786,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { ExistentialDeposit::set(1); BondingDuration::set(28); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); @@ -837,7 +865,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ExistentialDeposit::set(1); BondingDuration::set(28); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); @@ -909,12 +937,13 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ); }); } + #[test] fn pool_migration_e2e() { new_test_ext().execute_with(|| { LegacyAdapter::set(true); assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool with TransferStake strategy. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); @@ -1192,7 +1221,7 @@ fn disable_pool_operations_on_non_migrated() { new_test_ext().execute_with(|| { LegacyAdapter::set(true); assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool with TransferStake strategy. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); @@ -1369,7 +1398,7 @@ fn pool_no_dangling_delegation() { new_test_ext().execute_with(|| { ExistentialDeposit::set(1); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // pool creator let alice = 10; let bob = 20; diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml index 7398404c2351..2cdc4c41a083 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml +++ b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml @@ -19,22 +19,22 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = ["derive"], workspace = true, default-features = true } scale-info = { features = ["derive"], workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-staking = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } +pallet-bags-list = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +pallet-nomination-pools = { workspace = true, default-features = true } pallet-staking = { workspace = true, default-features = true } -pallet-bags-list = { workspace = true, default-features = true } pallet-staking-reward-curve = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } log = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs index 28e978bba0e5..cc39cfee91c8 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs @@ -34,7 +34,7 @@ use sp_runtime::{bounded_btree_map, traits::Zero}; fn pool_lifecycle_e2e() { new_test_ext().execute_with(|| { assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); @@ -286,7 +286,7 @@ fn destroy_pool_with_erroneous_consumer() { fn pool_chill_e2e() { new_test_ext().execute_with(|| { assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); @@ -412,7 +412,7 @@ fn pool_slash_e2e() { new_test_ext().execute_with(|| { ExistentialDeposit::set(1); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); @@ -622,7 +622,7 @@ fn pool_slash_proportional() { ExistentialDeposit::set(1); BondingDuration::set(28); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); @@ -759,7 +759,7 @@ fn pool_slash_non_proportional_only_bonded_pool() { ExistentialDeposit::set(1); BondingDuration::set(28); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); @@ -838,7 +838,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ExistentialDeposit::set(1); BondingDuration::set(28); assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(Staking::current_era(), None); + assert_eq!(CurrentEra::::get(), None); // create the pool, we know this has id 1. assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index 98c320e1f808..4dd9d7f10c9f 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -17,12 +17,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-balances = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } sp-runtime = { workspace = true } sp-staking = { workspace = true } diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 28c7895180c4..76b167ebdb33 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { workspace = true } frame-election-provider-support = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-babe = { workspace = true } pallet-balances = { workspace = true } pallet-grandpa = { workspace = true } @@ -29,9 +29,9 @@ pallet-im-online = { workspace = true } pallet-offences = { workspace = true } pallet-session = { workspace = true } pallet-staking = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } sp-staking = { workspace = true } -log = { workspace = true } [dev-dependencies] pallet-staking-reward-curve = { workspace = true, default-features = true } diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 573114de0742..75f3e9931e34 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -19,7 +19,7 @@ use alloc::{vec, vec::Vec}; -use frame_benchmarking::v1::{account, benchmarks}; +use frame_benchmarking::v2::*; use frame_support::traits::Get; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; @@ -144,7 +144,7 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' fn make_offenders( num_offenders: u32, num_nominators: u32, -) -> Result<(Vec>, Vec>), &'static str> { +) -> Result>, &'static str> { Staking::::new_session(0); let mut offenders = vec![]; @@ -167,21 +167,50 @@ fn make_offenders( .expect("failed to convert validator id to full identification") }) .collect::>>(); - Ok((id_tuples, offenders)) + Ok(id_tuples) } -benchmarks! { - where_clause { - where +#[cfg(test)] +fn assert_all_slashes_applied(offender_count: usize) +where + T: Config, + ::RuntimeEvent: TryInto>, + ::RuntimeEvent: TryInto>, + ::RuntimeEvent: TryInto, + ::RuntimeEvent: TryInto>, +{ + // make sure that all slashes have been applied + // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + + // reporter account endowed + some funds rescinded from issuance. + assert_eq!( + System::::read_events_for_pallet::>().len(), + 2 * (offender_count + 1) + 3 + ); + // (n nominators + one validator) * slashed + Slash Reported + assert_eq!( + System::::read_events_for_pallet::>().len(), + 1 * (offender_count + 1) + 1 + ); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // reporter new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); +} + +#[benchmarks( + where ::RuntimeEvent: TryInto>, ::RuntimeEvent: TryInto>, ::RuntimeEvent: TryInto, ::RuntimeEvent: TryInto>, - } - - report_offence_grandpa { - let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); - +)] +mod benchmarks { + use super::*; + + #[benchmark] + pub fn report_offence_grandpa( + n: Linear<0, { MAX_NOMINATORS.min(MaxNominationsOf::::get()) }>, + ) -> Result<(), BenchmarkError> { // for grandpa equivocation reports the number of reporters // and offenders is always 1 let reporters = vec![account("reporter", 1, SEED)]; @@ -189,7 +218,7 @@ benchmarks! { // make sure reporters actually get rewarded Staking::::set_slash_reward_fraction(Perbill::one()); - let (mut offenders, raw_offenders) = make_offenders::(1, n)?; + let mut offenders = make_offenders::(1, n)?; let validator_set_count = Session::::validators().len() as u32; let offence = GrandpaEquivocationOffence { @@ -199,28 +228,24 @@ benchmarks! { offender: T::convert(offenders.pop().unwrap()), }; assert_eq!(System::::event_count(), 0); - }: { - let _ = Offences::::report_offence(reporters, offence); - } - verify { + + #[block] + { + let _ = Offences::::report_offence(reporters, offence); + } + #[cfg(test)] { - // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter - // account endowed + some funds rescinded from issuance. - assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); - // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); - // offence - assert_eq!(System::::read_events_for_pallet::().len(), 1); - // reporter new account - assert_eq!(System::::read_events_for_pallet::>().len(), 1); + assert_all_slashes_applied::(n as usize); } - } - report_offence_babe { - let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); + Ok(()) + } + #[benchmark] + fn report_offence_babe( + n: Linear<0, { MAX_NOMINATORS.min(MaxNominationsOf::::get()) }>, + ) -> Result<(), BenchmarkError> { // for babe equivocation reports the number of reporters // and offenders is always 1 let reporters = vec![account("reporter", 1, SEED)]; @@ -228,7 +253,7 @@ benchmarks! { // make sure reporters actually get rewarded Staking::::set_slash_reward_fraction(Perbill::one()); - let (mut offenders, raw_offenders) = make_offenders::(1, n)?; + let mut offenders = make_offenders::(1, n)?; let validator_set_count = Session::::validators().len() as u32; let offence = BabeEquivocationOffence { @@ -238,23 +263,17 @@ benchmarks! { offender: T::convert(offenders.pop().unwrap()), }; assert_eq!(System::::event_count(), 0); - }: { - let _ = Offences::::report_offence(reporters, offence); - } - verify { + + #[block] + { + let _ = Offences::::report_offence(reporters, offence); + } #[cfg(test)] { - // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter - // account endowed + some funds rescinded from issuance. - assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); - // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); - // offence - assert_eq!(System::::read_events_for_pallet::().len(), 1); - // reporter new account - assert_eq!(System::::read_events_for_pallet::>().len(), 1); + assert_all_slashes_applied::(n as usize); } + + Ok(()) } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index efaec49a65b3..c5c178aa4443 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -29,7 +29,7 @@ use frame_system as system; use pallet_session::historical as pallet_session_historical; use sp_runtime::{ testing::{Header, UintAuthorityId}, - BuildStorage, Perbill, + BuildStorage, KeyTypeId, Perbill, }; type AccountId = u64; @@ -66,7 +66,8 @@ sp_runtime::impl_opaque_keys! { pub struct TestSessionHandler; impl pallet_session::SessionHandler for TestSessionHandler { - const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[]; + // corresponds to the opaque key id above + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[KeyTypeId([100u8, 117u8, 109u8, 121u8])]; fn on_genesis_session(_validators: &[(AccountId, Ks)]) {} diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index a680139c5fdc..da029bdd7423 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -23,10 +23,10 @@ frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-runtime = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-metadata-ir = { optional = true, workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/paged-list/fuzzer/Cargo.toml b/substrate/frame/paged-list/fuzzer/Cargo.toml index d0108254ed2d..7e6162df09ba 100644 --- a/substrate/frame/paged-list/fuzzer/Cargo.toml +++ b/substrate/frame/paged-list/fuzzer/Cargo.toml @@ -21,5 +21,5 @@ arbitrary = { workspace = true } honggfuzz = { workspace = true } frame-support = { features = ["std"], workspace = true } -sp-io = { features = ["std"], workspace = true } pallet-paged-list = { features = ["std"], workspace = true } +sp-io = { features = ["std"], workspace = true } diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index a97ba1172a50..dda218b618c4 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -9,22 +9,22 @@ edition.workspace = true [dependencies] codec = { features = ["max-encoded-len"], workspace = true } -scale-info = { features = ["derive"], workspace = true } +docify = { workspace = true } paste = { workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } -docify = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { features = ["experimental"], workspace = true } frame-system = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } [dev-dependencies] +pallet-balances = { features = ["std"], workspace = true, default-features = true } +pallet-example-basic = { features = ["std"], workspace = true, default-features = true } sp-core = { features = ["std"], workspace = true, default-features = true } sp-io = { features = ["std"], workspace = true, default-features = true } -pallet-example-basic = { features = ["std"], workspace = true, default-features = true } -pallet-balances = { features = ["std"], workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/parameters/src/weights.rs b/substrate/frame/parameters/src/weights.rs index 6510db9ebce5..5601247dad2b 100644 --- a/substrate/frame/parameters/src/weights.rs +++ b/substrate/frame/parameters/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_parameters` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -63,8 +63,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3501` - // Minimum execution time: 8_360_000 picoseconds. - Weight::from_parts(8_568_000, 3501) + // Minimum execution time: 8_202_000 picoseconds. + Weight::from_parts(8_485_000, 3501) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -78,8 +78,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3501` - // Minimum execution time: 8_360_000 picoseconds. - Weight::from_parts(8_568_000, 3501) + // Minimum execution time: 8_202_000 picoseconds. + Weight::from_parts(8_485_000, 3501) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index 1356ac403d38..fae6627b6315 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -13,14 +13,14 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { optional = true, workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -log = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } diff --git a/substrate/frame/preimage/src/benchmarking.rs b/substrate/frame/preimage/src/benchmarking.rs index 3d0c5b900579..ea635bf3ef77 100644 --- a/substrate/frame/preimage/src/benchmarking.rs +++ b/substrate/frame/preimage/src/benchmarking.rs @@ -17,14 +17,13 @@ //! Preimage pallet benchmarking. -use super::*; use alloc::vec; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; +use frame_benchmarking::v2::*; use frame_support::assert_ok; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; -use crate::Pallet as Preimage; +use crate::*; fn funded_account() -> T::AccountId { let caller: T::AccountId = whitelisted_caller(); @@ -43,206 +42,225 @@ fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { (preimage, hash) } -benchmarks! { +fn insert_old_unrequested(s: u32) -> ::Hash { + let acc = account("old", s, 0); + T::Currency::make_free_balance_be(&acc, BalanceOf::::max_value() / 2u32.into()); + + // The preimage size does not matter here as it is not touched. + let preimage = s.to_le_bytes(); + let hash = ::Hashing::hash(&preimage[..]); + + #[allow(deprecated)] + StatusFor::::insert( + &hash, + OldRequestStatus::Unrequested { deposit: (acc, 123u32.into()), len: preimage.len() as u32 }, + ); + hash +} + +#[benchmarks] +mod benchmarks { + use super::*; + // Expensive note - will reserve. - note_preimage { - let s in 0 .. MAX_SIZE; + #[benchmark] + fn note_preimage(s: Linear<0, MAX_SIZE>) { let caller = funded_account::(); let (preimage, hash) = sized_preimage_and_hash::(s); - }: _(RawOrigin::Signed(caller), preimage) - verify { - assert!(Preimage::::have_preimage(&hash)); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), preimage); + + assert!(Pallet::::have_preimage(&hash)); } + // Cheap note - will not reserve since it was requested. - note_requested_preimage { - let s in 0 .. MAX_SIZE; + #[benchmark] + fn note_requested_preimage(s: Linear<0, MAX_SIZE>) { let caller = funded_account::(); let (preimage, hash) = sized_preimage_and_hash::(s); - assert_ok!(Preimage::::request_preimage( + assert_ok!(Pallet::::request_preimage( T::ManagerOrigin::try_successful_origin() .expect("ManagerOrigin has no successful origin required for the benchmark"), hash, )); - }: note_preimage(RawOrigin::Signed(caller), preimage) - verify { - assert!(Preimage::::have_preimage(&hash)); + + #[extrinsic_call] + note_preimage(RawOrigin::Signed(caller), preimage); + + assert!(Pallet::::have_preimage(&hash)); } + // Cheap note - will not reserve since it's the manager. - note_no_deposit_preimage { - let s in 0 .. MAX_SIZE; + #[benchmark] + fn note_no_deposit_preimage(s: Linear<0, MAX_SIZE>) { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (preimage, hash) = sized_preimage_and_hash::(s); - assert_ok!(Preimage::::request_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - hash, - )); - }: note_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - preimage - ) verify { - assert!(Preimage::::have_preimage(&hash)); + assert_ok!(Pallet::::request_preimage(o.clone(), hash,)); + + #[extrinsic_call] + note_preimage(o as T::RuntimeOrigin, preimage); + + assert!(Pallet::::have_preimage(&hash)); } // Expensive unnote - will unreserve. - unnote_preimage { + #[benchmark] + fn unnote_preimage() { let caller = funded_account::(); let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(caller.clone()).into(), preimage)); - }: _(RawOrigin::Signed(caller), hash) - verify { - assert!(!Preimage::::have_preimage(&hash)); + assert_ok!(Pallet::::note_preimage(RawOrigin::Signed(caller.clone()).into(), preimage)); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), hash); + + assert!(!Pallet::::have_preimage(&hash)); } + // Cheap unnote - will not unreserve since there's no deposit held. - unnote_no_deposit_preimage { + #[benchmark] + fn unnote_no_deposit_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::note_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - preimage, - )); - }: unnote_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { - assert!(!Preimage::::have_preimage(&hash)); + assert_ok!(Pallet::::note_preimage(o.clone(), preimage,)); + + #[extrinsic_call] + unnote_preimage(o as T::RuntimeOrigin, hash); + + assert!(!Pallet::::have_preimage(&hash)); } // Expensive request - will unreserve the noter's deposit. - request_preimage { + #[benchmark] + fn request_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (preimage, hash) = preimage_and_hash::(); let noter = funded_account::(); - assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); - }: _( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { - let ticket = TicketOf::::new(¬er, Footprint { count: 1, size: MAX_SIZE as u64 }).unwrap(); - let s = RequestStatus::Requested { maybe_ticket: Some((noter, ticket)), count: 1, maybe_len: Some(MAX_SIZE) }; + assert_ok!(Pallet::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); + + #[extrinsic_call] + _(o as T::RuntimeOrigin, hash); + + let ticket = + TicketOf::::new(¬er, Footprint { count: 1, size: MAX_SIZE as u64 }).unwrap(); + let s = RequestStatus::Requested { + maybe_ticket: Some((noter, ticket)), + count: 1, + maybe_len: Some(MAX_SIZE), + }; assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } + // Cheap request - would unreserve the deposit but none was held. - request_no_deposit_preimage { + #[benchmark] + fn request_no_deposit_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::note_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - preimage, - )); - }: request_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { - let s = RequestStatus::Requested { maybe_ticket: None, count: 2, maybe_len: Some(MAX_SIZE) }; + assert_ok!(Pallet::::note_preimage(o.clone(), preimage,)); + + #[extrinsic_call] + request_preimage(o as T::RuntimeOrigin, hash); + + let s = + RequestStatus::Requested { maybe_ticket: None, count: 2, maybe_len: Some(MAX_SIZE) }; assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } + // Cheap request - the preimage is not yet noted, so deposit to unreserve. - request_unnoted_preimage { + #[benchmark] + fn request_unnoted_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (_, hash) = preimage_and_hash::(); - }: request_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { + + #[extrinsic_call] + request_preimage(o as T::RuntimeOrigin, hash); + let s = RequestStatus::Requested { maybe_ticket: None, count: 1, maybe_len: None }; assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } + // Cheap request - the preimage is already requested, so just a counter bump. - request_requested_preimage { + #[benchmark] + fn request_requested_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - hash, - )); - }: request_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { + assert_ok!(Pallet::::request_preimage(o.clone(), hash,)); + + #[extrinsic_call] + request_preimage(o as T::RuntimeOrigin, hash); + let s = RequestStatus::Requested { maybe_ticket: None, count: 2, maybe_len: None }; assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } // Expensive unrequest - last reference and it's noted, so will destroy the preimage. - unrequest_preimage { + #[benchmark] + fn unrequest_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - hash, - )); - assert_ok!(Preimage::::note_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - preimage, - )); - }: _( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { + assert_ok!(Pallet::::request_preimage(o.clone(), hash,)); + assert_ok!(Pallet::::note_preimage(o.clone(), preimage)); + + #[extrinsic_call] + _(o as T::RuntimeOrigin, hash); + assert_eq!(RequestStatusFor::::get(&hash), None); } + // Cheap unrequest - last reference, but it's not noted. - unrequest_unnoted_preimage { + #[benchmark] + fn unrequest_unnoted_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - hash, - )); - }: unrequest_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { + assert_ok!(Pallet::::request_preimage(o.clone(), hash,)); + + #[extrinsic_call] + unrequest_preimage(o as T::RuntimeOrigin, hash); + assert_eq!(RequestStatusFor::::get(&hash), None); } + // Cheap unrequest - not the last reference. - unrequest_multi_referenced_preimage { + #[benchmark] + fn unrequest_multi_referenced_preimage() { + let o = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - hash, - )); - assert_ok!(Preimage::::request_preimage( - T::ManagerOrigin::try_successful_origin() - .expect("ManagerOrigin has no successful origin required for the benchmark"), - hash, - )); - }: unrequest_preimage( - T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, - hash - ) verify { + assert_ok!(Pallet::::request_preimage(o.clone(), hash,)); + assert_ok!(Pallet::::request_preimage(o.clone(), hash,)); + + #[extrinsic_call] + unrequest_preimage(o as T::RuntimeOrigin, hash); + let s = RequestStatus::Requested { maybe_ticket: None, count: 1, maybe_len: None }; assert_eq!(RequestStatusFor::::get(&hash), Some(s)); } - ensure_updated { - let n in 1..MAX_HASH_UPGRADE_BULK_COUNT; - + #[benchmark] + fn ensure_updated(n: Linear<1, MAX_HASH_UPGRADE_BULK_COUNT>) { let caller = funded_account::(); let hashes = (0..n).map(|i| insert_old_unrequested::(i)).collect::>(); - }: _(RawOrigin::Signed(caller), hashes) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), hashes); + assert_eq!(RequestStatusFor::::iter_keys().count(), n as usize); #[allow(deprecated)] let c = StatusFor::::iter_keys().count(); assert_eq!(c, 0); } - impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); -} - -fn insert_old_unrequested(s: u32) -> ::Hash { - let acc = account("old", s, 0); - T::Currency::make_free_balance_be(&acc, BalanceOf::::max_value() / 2u32.into()); - - // The preimage size does not matter here as it is not touched. - let preimage = s.to_le_bytes(); - let hash = ::Hashing::hash(&preimage[..]); - - #[allow(deprecated)] - StatusFor::::insert( - &hash, - OldRequestStatus::Unrequested { deposit: (acc, 123u32.into()), len: preimage.len() as u32 }, - ); - hash + impl_benchmark_test_suite! { + Pallet, + mock::new_test_ext(), + mock::Test + } } diff --git a/substrate/frame/preimage/src/weights.rs b/substrate/frame/preimage/src/weights.rs index 4e389e3a7340..a3aec7e7546e 100644 --- a/substrate/frame/preimage/src/weights.rs +++ b/substrate/frame/preimage/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_preimage` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_preimage -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/preimage/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_preimage +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/preimage/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,18 +74,18 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Parameters::Parameters` (r:2 w:0) /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112` + // Measured: `7` // Estimated: `6012` - // Minimum execution time: 52_531_000 picoseconds. - Weight::from_parts(53_245_000, 6012) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_744, 0).saturating_mul(s.into())) + // Minimum execution time: 51_305_000 picoseconds. + Weight::from_parts(51_670_000, 6012) + // Standard Error: 5 + .saturating_add(Weight::from_parts(2_337, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -100,12 +98,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 15_601_000 picoseconds. - Weight::from_parts(15_871_000, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_836, 0).saturating_mul(s.into())) + // Minimum execution time: 16_204_000 picoseconds. + Weight::from_parts(16_613_000, 3556) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_503, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -118,12 +116,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 15_614_000 picoseconds. - Weight::from_parts(15_934_000, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_832, 0).saturating_mul(s.into())) + // Minimum execution time: 15_118_000 picoseconds. + Weight::from_parts(15_412_000, 3556) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_411, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -132,15 +130,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `311` - // Estimated: `3658` - // Minimum execution time: 53_001_000 picoseconds. - Weight::from_parts(55_866_000, 3658) + // Measured: `206` + // Estimated: `3820` + // Minimum execution time: 57_218_000 picoseconds. + Weight::from_parts(61_242_000, 3820) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -152,10 +150,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 26_901_000 picoseconds. - Weight::from_parts(28_079_000, 3556) + // Minimum execution time: 25_140_000 picoseconds. + Weight::from_parts(27_682_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -165,10 +163,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `255` + // Measured: `150` // Estimated: `3556` - // Minimum execution time: 21_716_000 picoseconds. - Weight::from_parts(25_318_000, 3556) + // Minimum execution time: 25_296_000 picoseconds. + Weight::from_parts(27_413_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -178,10 +176,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 13_890_000 picoseconds. - Weight::from_parts(14_744_000, 3556) + // Minimum execution time: 15_011_000 picoseconds. + Weight::from_parts(16_524_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -191,10 +189,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `4` // Estimated: `3556` - // Minimum execution time: 14_192_000 picoseconds. - Weight::from_parts(15_113_000, 3556) + // Minimum execution time: 14_649_000 picoseconds. + Weight::from_parts(15_439_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -204,10 +202,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 9_909_000 picoseconds. - Weight::from_parts(10_134_000, 3556) + // Minimum execution time: 10_914_000 picoseconds. + Weight::from_parts(11_137_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -219,10 +217,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 21_725_000 picoseconds. - Weight::from_parts(24_058_000, 3556) + // Minimum execution time: 22_512_000 picoseconds. + Weight::from_parts(24_376_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -232,10 +230,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 9_854_000 picoseconds. - Weight::from_parts(10_175_000, 3556) + // Minimum execution time: 10_571_000 picoseconds. + Weight::from_parts(10_855_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -245,10 +243,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 10_143_000 picoseconds. - Weight::from_parts(10_539_000, 3556) + // Minimum execution time: 10_312_000 picoseconds. + Weight::from_parts(10_653_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -259,22 +257,22 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Parameters::Parameters` (r:2 w:0) /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1023 w:1023) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 1024]`. fn ensure_updated(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (227 ±0)` - // Estimated: `6012 + n * (2668 ±0)` - // Minimum execution time: 59_384_000 picoseconds. - Weight::from_parts(60_000_000, 6012) - // Standard Error: 39_890 - .saturating_add(Weight::from_parts(56_317_686, 0).saturating_mul(n.into())) + // Estimated: `6012 + n * (2830 ±0)` + // Minimum execution time: 61_990_000 picoseconds. + Weight::from_parts(62_751_000, 6012) + // Standard Error: 44_079 + .saturating_add(Weight::from_parts(57_343_378, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2668).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2830).saturating_mul(n.into())) } } @@ -287,18 +285,18 @@ impl WeightInfo for () { /// Storage: `Parameters::Parameters` (r:2 w:0) /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112` + // Measured: `7` // Estimated: `6012` - // Minimum execution time: 52_531_000 picoseconds. - Weight::from_parts(53_245_000, 6012) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_744, 0).saturating_mul(s.into())) + // Minimum execution time: 51_305_000 picoseconds. + Weight::from_parts(51_670_000, 6012) + // Standard Error: 5 + .saturating_add(Weight::from_parts(2_337, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -311,12 +309,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 15_601_000 picoseconds. - Weight::from_parts(15_871_000, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_836, 0).saturating_mul(s.into())) + // Minimum execution time: 16_204_000 picoseconds. + Weight::from_parts(16_613_000, 3556) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_503, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -329,12 +327,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 15_614_000 picoseconds. - Weight::from_parts(15_934_000, 3556) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_832, 0).saturating_mul(s.into())) + // Minimum execution time: 15_118_000 picoseconds. + Weight::from_parts(15_412_000, 3556) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_411, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -343,15 +341,15 @@ impl WeightInfo for () { /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `311` - // Estimated: `3658` - // Minimum execution time: 53_001_000 picoseconds. - Weight::from_parts(55_866_000, 3658) + // Measured: `206` + // Estimated: `3820` + // Minimum execution time: 57_218_000 picoseconds. + Weight::from_parts(61_242_000, 3820) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -363,10 +361,10 @@ impl WeightInfo for () { /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 26_901_000 picoseconds. - Weight::from_parts(28_079_000, 3556) + // Minimum execution time: 25_140_000 picoseconds. + Weight::from_parts(27_682_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -376,10 +374,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `255` + // Measured: `150` // Estimated: `3556` - // Minimum execution time: 21_716_000 picoseconds. - Weight::from_parts(25_318_000, 3556) + // Minimum execution time: 25_296_000 picoseconds. + Weight::from_parts(27_413_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -389,10 +387,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 13_890_000 picoseconds. - Weight::from_parts(14_744_000, 3556) + // Minimum execution time: 15_011_000 picoseconds. + Weight::from_parts(16_524_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -402,10 +400,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `4` // Estimated: `3556` - // Minimum execution time: 14_192_000 picoseconds. - Weight::from_parts(15_113_000, 3556) + // Minimum execution time: 14_649_000 picoseconds. + Weight::from_parts(15_439_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -415,10 +413,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 9_909_000 picoseconds. - Weight::from_parts(10_134_000, 3556) + // Minimum execution time: 10_914_000 picoseconds. + Weight::from_parts(11_137_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -430,10 +428,10 @@ impl WeightInfo for () { /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 21_725_000 picoseconds. - Weight::from_parts(24_058_000, 3556) + // Minimum execution time: 22_512_000 picoseconds. + Weight::from_parts(24_376_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -443,10 +441,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 9_854_000 picoseconds. - Weight::from_parts(10_175_000, 3556) + // Minimum execution time: 10_571_000 picoseconds. + Weight::from_parts(10_855_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -456,10 +454,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `68` // Estimated: `3556` - // Minimum execution time: 10_143_000 picoseconds. - Weight::from_parts(10_539_000, 3556) + // Minimum execution time: 10_312_000 picoseconds. + Weight::from_parts(10_653_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -470,21 +468,21 @@ impl WeightInfo for () { /// Storage: `Parameters::Parameters` (r:2 w:0) /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1023 w:1023) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 1024]`. fn ensure_updated(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (227 ±0)` - // Estimated: `6012 + n * (2668 ±0)` - // Minimum execution time: 59_384_000 picoseconds. - Weight::from_parts(60_000_000, 6012) - // Standard Error: 39_890 - .saturating_add(Weight::from_parts(56_317_686, 0).saturating_mul(n.into())) + // Estimated: `6012 + n * (2830 ±0)` + // Minimum execution time: 61_990_000 picoseconds. + Weight::from_parts(62_751_000, 6012) + // Standard Error: 44_079 + .saturating_add(Weight::from_parts(57_343_378, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2668).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2830).saturating_mul(n.into())) } } diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 8897c66419c7..a36b2c1cb9c3 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["max-encoded-len"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame = { workspace = true, features = ["experimental", "runtime"] } +scale-info = { features = ["derive"], workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } diff --git a/substrate/frame/proxy/src/benchmarking.rs b/substrate/frame/proxy/src/benchmarking.rs index eebb506bf374..b72f53af8e72 100644 --- a/substrate/frame/proxy/src/benchmarking.rs +++ b/substrate/frame/proxy/src/benchmarking.rs @@ -22,7 +22,9 @@ use super::*; use crate::Pallet as Proxy; use alloc::{boxed::Box, vec}; -use frame::benchmarking::prelude::*; +use frame::benchmarking::prelude::{ + account, benchmarks, impl_test_function, whitelisted_caller, BenchmarkError, RawOrigin, +}; const SEED: u32 = 0; @@ -317,7 +319,7 @@ mod benchmarks { BlockNumberFor::::zero(), 0, )?; - let height = frame_system::Pallet::::block_number(); + let height = T::BlockNumberProvider::current_block_number(); let ext_index = frame_system::Pallet::::extrinsic_index().unwrap_or(0); let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); diff --git a/substrate/frame/proxy/src/lib.rs b/substrate/frame/proxy/src/lib.rs index cc8aeedcc5f9..cc21db7469b2 100644 --- a/substrate/frame/proxy/src/lib.rs +++ b/substrate/frame/proxy/src/lib.rs @@ -47,6 +47,9 @@ type CallHashOf = <::CallHasher as Hash>::Output; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +pub type BlockNumberFor = + <::BlockNumberProvider as BlockNumberProvider>::BlockNumber; + type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// The parameters under which a particular account has a proxy relationship with some other @@ -163,6 +166,9 @@ pub mod pallet { /// into a pre-existing storage value. #[pallet::constant] type AnnouncementDepositFactor: Get>; + + /// Provider for the block number. Normally this is the `frame_system` pallet. + type BlockNumberProvider: BlockNumberProvider; } #[pallet::call] @@ -379,7 +385,7 @@ pub mod pallet { let announcement = Announcement { real: real.clone(), call_hash, - height: frame_system::Pallet::::block_number(), + height: T::BlockNumberProvider::current_block_number(), }; Announcements::::try_mutate(&who, |(ref mut pending, ref mut deposit)| { @@ -490,7 +496,7 @@ pub mod pallet { let def = Self::find_proxy(&real, &delegate, force_proxy_type)?; let call_hash = T::CallHasher::hash_of(&call); - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); Self::edit_announcements(&delegate, |ann| { ann.real != real || ann.call_hash != call_hash || @@ -626,7 +632,7 @@ impl Pallet { ) -> T::AccountId { let (height, ext_index) = maybe_when.unwrap_or_else(|| { ( - frame_system::Pallet::::block_number(), + T::BlockNumberProvider::current_block_number(), frame_system::Pallet::::extrinsic_index().unwrap_or_default(), ) }); diff --git a/substrate/frame/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 5baf9bb9e838..afc668188e6c 100644 --- a/substrate/frame/proxy/src/tests.rs +++ b/substrate/frame/proxy/src/tests.rs @@ -119,6 +119,7 @@ impl Config for Test { type MaxPending = ConstU32<2>; type AnnouncementDepositBase = ConstU64<1>; type AnnouncementDepositFactor = ConstU64<1>; + type BlockNumberProvider = frame_system::Pallet; } use super::{Call as ProxyCall, Event as ProxyEvent}; diff --git a/substrate/frame/proxy/src/weights.rs b/substrate/frame/proxy/src/weights.rs index eab2cb4b2683..851c0ba98a82 100644 --- a/substrate/frame/proxy/src/weights.rs +++ b/substrate/frame/proxy/src/weights.rs @@ -411,4 +411,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } -} +} \ No newline at end of file diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index eca59cf7fc22..78a02bec8e97 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +impl-trait-for-tuples = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -impl-trait-for-tuples = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/ranked-collective/src/benchmarking.rs b/substrate/frame/ranked-collective/src/benchmarking.rs index dc7f4aaca773..978489fb8485 100644 --- a/substrate/frame/ranked-collective/src/benchmarking.rs +++ b/substrate/frame/ranked-collective/src/benchmarking.rs @@ -21,11 +21,12 @@ use super::*; #[allow(unused_imports)] use crate::Pallet as RankedCollective; use alloc::vec::Vec; - -use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, +use frame_benchmarking::{ + v1::{account, BenchmarkError}, + v2::*, }; -use frame_support::{assert_ok, traits::UnfilteredDispatchable}; + +use frame_support::{assert_err, assert_ok, traits::NoOpPoll}; use frame_system::RawOrigin as SystemOrigin; const SEED: u32 = 0; @@ -56,131 +57,273 @@ fn make_member, I: 'static>(rank: Rank) -> T::AccountId { who } -benchmarks_instance_pallet! { - add_member { +#[instance_benchmarks( +where <>::Polls as frame_support::traits::Polling>>>::Index: From +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn add_member() -> Result<(), BenchmarkError> { + // Generate a test account for the new member. let who = account::("member", 0, SEED); let who_lookup = T::Lookup::unlookup(who.clone()); + + // Attempt to get the successful origin for adding a member. let origin = T::AddOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let call = Call::::add_member { who: who_lookup }; - }: { call.dispatch_bypass_filter(origin)? } - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, who_lookup); + + // Ensure the member count has increased (or is 1 for rank 0). assert_eq!(MemberCount::::get(0), 1); + + // Check that the correct event was emitted. assert_last_event::(Event::MemberAdded { who }.into()); + + Ok(()) } - remove_member { - let r in 0 .. 10; + #[benchmark] + fn remove_member(r: Linear<0, 10>) -> Result<(), BenchmarkError> { + // Convert `r` to a rank and create members. let rank = r as u16; - let first = make_member::(rank); let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); - let last_index = (0..=rank).map(|r| IdToIndex::::get(r, &last).unwrap()).collect::>(); + + // Collect the index of the `last` member for each rank. + let last_index: Vec<_> = + (0..=rank).map(|r| IdToIndex::::get(r, &last).unwrap()).collect(); + + // Fetch the remove origin. let origin = T::RemoveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let call = Call::::remove_member { who: who_lookup, min_rank: rank }; - }: { call.dispatch_bypass_filter(origin)? } - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, who_lookup, rank); + for r in 0..=rank { - assert_eq!(MemberCount::::get(r), 2); + assert_eq!(MemberCount::::get(r), 1); assert_ne!(last_index[r as usize], IdToIndex::::get(r, &last).unwrap()); } + + // Ensure the correct event was emitted for the member removal. assert_last_event::(Event::MemberRemoved { who, rank }.into()); + + Ok(()) } - promote_member { - let r in 0 .. 10; + #[benchmark] + fn promote_member(r: Linear<0, 10>) -> Result<(), BenchmarkError> { + // Convert `r` to a rank and create the member. let rank = r as u16; let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); + + // Try to fetch the promotion origin. let origin = T::PromoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let call = Call::::promote_member { who: who_lookup }; - }: { call.dispatch_bypass_filter(origin)? } - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, who_lookup); + + // Ensure the member's rank has increased by 1. assert_eq!(Members::::get(&who).unwrap().rank, rank + 1); + + // Ensure the correct event was emitted for the rank change. assert_last_event::(Event::RankChanged { who, rank: rank + 1 }.into()); + + Ok(()) } - demote_member { - let r in 0 .. 10; + #[benchmark] + fn demote_member(r: Linear<0, 10>) -> Result<(), BenchmarkError> { + // Convert `r` to a rank and create necessary members for the benchmark. let rank = r as u16; - let first = make_member::(rank); let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); + + // Get the last index for the member. let last_index = IdToIndex::::get(rank, &last).unwrap(); + + // Try to fetch the demotion origin. let origin = T::DemoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let call = Call::::demote_member { who: who_lookup }; - }: { call.dispatch_bypass_filter(origin)? } - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, who_lookup); + + // Ensure the member's rank has decreased by 1. assert_eq!(Members::::get(&who).map(|x| x.rank), rank.checked_sub(1)); - assert_eq!(MemberCount::::get(rank), 2); + + // Ensure the member count remains as expected. + assert_eq!(MemberCount::::get(rank), 1); + + // Ensure the index of the last member has changed. assert_ne!(last_index, IdToIndex::::get(rank, &last).unwrap()); - assert_last_event::(match rank { - 0 => Event::MemberRemoved { who, rank: 0 }, - r => Event::RankChanged { who, rank: r - 1 }, - }.into()); + + // Ensure the correct event was emitted depending on the member's rank. + assert_last_event::( + match rank { + 0 => Event::MemberRemoved { who, rank: 0 }, + r => Event::RankChanged { who, rank: r - 1 }, + } + .into(), + ); + + Ok(()) } - vote { - let class = T::Polls::classes().into_iter().next().unwrap(); - let rank = T::MinRankOfClass::convert(class.clone()); + #[benchmark] + fn vote() -> Result<(), BenchmarkError> { + // Get the first available class or set it to None if no class exists. + let class = T::Polls::classes().into_iter().next(); + + // Convert the class to a rank if it exists, otherwise use the default rank. + let rank = class.as_ref().map_or( + as frame_support::traits::RankedMembers>::Rank::default(), + |class| T::MinRankOfClass::convert(class.clone()), + ); + // Create a caller based on the rank. let caller = make_member::(rank); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - let poll = T::Polls::create_ongoing(class).expect("Must always be able to create a poll for rank 0"); + // Determine the poll to use: create an ongoing poll if class exists, or use an invalid + // poll. + let poll = if let Some(ref class) = class { + T::Polls::create_ongoing(class.clone()) + .expect("Poll creation should succeed for rank 0") + } else { + >::Index::MAX.into() + }; + + // Benchmark the vote logic for a positive vote (true). + #[block] + { + let vote_result = + Pallet::::vote(SystemOrigin::Signed(caller.clone()).into(), poll, true); + + // If the class exists, expect success; otherwise expect a "NotPolling" error. + if class.is_some() { + assert_ok!(vote_result); + } else { + assert_err!(vote_result, crate::Error::::NotPolling); + }; + } + + // Vote logic for a negative vote (false). + let vote_result = + Pallet::::vote(SystemOrigin::Signed(caller.clone()).into(), poll, false); + + // Check the result of the negative vote. + if class.is_some() { + assert_ok!(vote_result); + } else { + assert_err!(vote_result, crate::Error::::NotPolling); + }; + + // If the class exists, verify the vote event and tally. + if let Some(_) = class { + let tally = Tally::from_parts(0, 0, 1); + let vote_event = Event::Voted { who: caller, poll, vote: VoteRecord::Nay(1), tally }; + assert_last_event::(vote_event.into()); + } - // Vote once. - assert_ok!(Pallet::::vote(SystemOrigin::Signed(caller.clone()).into(), poll, true)); - }: _(SystemOrigin::Signed(caller.clone()), poll, false) - verify { - let tally = Tally::from_parts(0, 0, 1); - let ev = Event::Voted { who: caller, poll, vote: VoteRecord::Nay(1), tally }; - assert_last_event::(ev.into()); + Ok(()) } - cleanup_poll { - let n in 0 .. 100; + #[benchmark] + fn cleanup_poll(n: Linear<0, 100>) -> Result<(), BenchmarkError> { + let alice: T::AccountId = whitelisted_caller(); + let origin = SystemOrigin::Signed(alice.clone()); + + // Try to retrieve the first class if it exists. + let class = T::Polls::classes().into_iter().next(); + + // Convert the class to a rank, or use a default rank if no class exists. + let rank = class.as_ref().map_or( + as frame_support::traits::RankedMembers>::Rank::default(), + |class| T::MinRankOfClass::convert(class.clone()), + ); - // Create a poll - let class = T::Polls::classes().into_iter().next().unwrap(); - let rank = T::MinRankOfClass::convert(class.clone()); - let poll = T::Polls::create_ongoing(class).expect("Must always be able to create a poll"); + // Determine the poll to use: create an ongoing poll if class exists, or use an invalid + // poll. + let poll = if let Some(ref class) = class { + T::Polls::create_ongoing(class.clone()) + .expect("Poll creation should succeed for rank 0") + } else { + >::Index::MAX.into() + }; - // Vote in the poll by each of `n` members - for i in 0..n { - let who = make_member::(rank); - assert_ok!(Pallet::::vote(SystemOrigin::Signed(who).into(), poll, true)); + // Simulate voting by `n` members. + for _ in 0..n { + let voter = make_member::(rank); + let result = Pallet::::vote(SystemOrigin::Signed(voter).into(), poll, true); + + // Check voting results based on class existence. + if class.is_some() { + assert_ok!(result); + } else { + assert_err!(result, crate::Error::::NotPolling); + } + } + + // End the poll if the class exists. + if class.is_some() { + T::Polls::end_ongoing(poll, false) + .map_err(|_| BenchmarkError::Stop("Failed to end poll"))?; } - // End the poll. - T::Polls::end_ongoing(poll, false).expect("Must always be able to end a poll"); + // Verify the number of votes cast. + let expected_votes = if class.is_some() { n as usize } else { 0 }; + assert_eq!(Voting::::iter_prefix(poll).count(), expected_votes); - assert_eq!(Voting::::iter_prefix(poll).count(), n as usize); - }: _(SystemOrigin::Signed(whitelisted_caller()), poll, n) - verify { + // Benchmark the cleanup function. + #[extrinsic_call] + _(origin, poll, n); + + // Ensure all votes are cleaned up after the extrinsic call. assert_eq!(Voting::::iter().count(), 0); + + Ok(()) } - exchange_member { + #[benchmark] + fn exchange_member() -> Result<(), BenchmarkError> { + // Create an existing member. let who = make_member::(1); T::BenchmarkSetup::ensure_member(&who); let who_lookup = T::Lookup::unlookup(who.clone()); + + // Create a new account for the new member. let new_who = account::("new-member", 0, SEED); let new_who_lookup = T::Lookup::unlookup(new_who.clone()); + + // Attempt to get the successful origin for exchanging a member. let origin = T::ExchangeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let call = Call::::exchange_member { who: who_lookup, new_who: new_who_lookup }; - }: { call.dispatch_bypass_filter(origin)? } - verify { + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, who_lookup, new_who_lookup); + + // Check that the new member was successfully exchanged and holds the correct rank. assert_eq!(Members::::get(&new_who).unwrap().rank, 1); + + // Ensure the old member no longer exists. assert_eq!(Members::::get(&who), None); + + // Ensure the correct event was emitted. assert_has_event::(Event::MemberExchanged { who, new_who }.into()); + + Ok(()) } - impl_benchmark_test_suite!(RankedCollective, crate::tests::ExtBuilder::default().build(), crate::tests::Test); + impl_benchmark_test_suite!( + RankedCollective, + crate::tests::ExtBuilder::default().build(), + crate::tests::Test + ); } diff --git a/substrate/frame/ranked-collective/src/weights.rs b/substrate/frame/ranked-collective/src/weights.rs index e728635f2e72..09215c1ec096 100644 --- a/substrate/frame/ranked-collective/src/weights.rs +++ b/substrate/frame/ranked-collective/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_ranked_collective` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -75,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 15_440_000 picoseconds. - Weight::from_parts(15_990_000, 3507) + // Minimum execution time: 16_363_000 picoseconds. + Weight::from_parts(16_792_000, 3507) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -93,10 +93,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `616 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 30_171_000 picoseconds. - Weight::from_parts(33_395_037, 3519) - // Standard Error: 21_741 - .saturating_add(Weight::from_parts(16_589_950, 0).saturating_mul(r.into())) + // Minimum execution time: 37_472_000 picoseconds. + Weight::from_parts(38_888_667, 3519) + // Standard Error: 36_527 + .saturating_add(Weight::from_parts(18_271_687, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -116,10 +116,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `314 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 18_597_000 picoseconds. - Weight::from_parts(19_774_947, 3507) - // Standard Error: 5_735 - .saturating_add(Weight::from_parts(339_013, 0).saturating_mul(r.into())) + // Minimum execution time: 20_069_000 picoseconds. + Weight::from_parts(21_231_820, 3507) + // Standard Error: 5_686 + .saturating_add(Weight::from_parts(415_623, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -136,10 +136,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `632 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 29_670_000 picoseconds. - Weight::from_parts(33_022_564, 3519) - // Standard Error: 28_521 - .saturating_add(Weight::from_parts(817_563, 0).saturating_mul(r.into())) + // Minimum execution time: 37_085_000 picoseconds. + Weight::from_parts(40_627_931, 3519) + // Standard Error: 23_398 + .saturating_add(Weight::from_parts(847_496, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -157,8 +157,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `628` // Estimated: `219984` - // Minimum execution time: 42_072_000 picoseconds. - Weight::from_parts(43_360_000, 219984) + // Minimum execution time: 49_474_000 picoseconds. + Weight::from_parts(50_506_000, 219984) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -173,10 +173,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `462 + n * (50 ±0)` // Estimated: `3795 + n * (2540 ±0)` - // Minimum execution time: 14_338_000 picoseconds. - Weight::from_parts(18_144_424, 3795) - // Standard Error: 2_482 - .saturating_add(Weight::from_parts(1_200_576, 0).saturating_mul(n.into())) + // Minimum execution time: 20_009_000 picoseconds. + Weight::from_parts(23_414_747, 3795) + // Standard Error: 2_751 + .saturating_add(Weight::from_parts(1_314_498, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -200,8 +200,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `625` // Estimated: `19894` - // Minimum execution time: 73_317_000 picoseconds. - Weight::from_parts(75_103_000, 19894) + // Minimum execution time: 79_257_000 picoseconds. + Weight::from_parts(81_293_000, 19894) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(14_u64)) } @@ -221,8 +221,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 15_440_000 picoseconds. - Weight::from_parts(15_990_000, 3507) + // Minimum execution time: 16_363_000 picoseconds. + Weight::from_parts(16_792_000, 3507) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -239,10 +239,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `616 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 30_171_000 picoseconds. - Weight::from_parts(33_395_037, 3519) - // Standard Error: 21_741 - .saturating_add(Weight::from_parts(16_589_950, 0).saturating_mul(r.into())) + // Minimum execution time: 37_472_000 picoseconds. + Weight::from_parts(38_888_667, 3519) + // Standard Error: 36_527 + .saturating_add(Weight::from_parts(18_271_687, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -262,10 +262,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `314 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 18_597_000 picoseconds. - Weight::from_parts(19_774_947, 3507) - // Standard Error: 5_735 - .saturating_add(Weight::from_parts(339_013, 0).saturating_mul(r.into())) + // Minimum execution time: 20_069_000 picoseconds. + Weight::from_parts(21_231_820, 3507) + // Standard Error: 5_686 + .saturating_add(Weight::from_parts(415_623, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -282,10 +282,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `632 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 29_670_000 picoseconds. - Weight::from_parts(33_022_564, 3519) - // Standard Error: 28_521 - .saturating_add(Weight::from_parts(817_563, 0).saturating_mul(r.into())) + // Minimum execution time: 37_085_000 picoseconds. + Weight::from_parts(40_627_931, 3519) + // Standard Error: 23_398 + .saturating_add(Weight::from_parts(847_496, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -303,8 +303,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `628` // Estimated: `219984` - // Minimum execution time: 42_072_000 picoseconds. - Weight::from_parts(43_360_000, 219984) + // Minimum execution time: 49_474_000 picoseconds. + Weight::from_parts(50_506_000, 219984) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -319,10 +319,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `462 + n * (50 ±0)` // Estimated: `3795 + n * (2540 ±0)` - // Minimum execution time: 14_338_000 picoseconds. - Weight::from_parts(18_144_424, 3795) - // Standard Error: 2_482 - .saturating_add(Weight::from_parts(1_200_576, 0).saturating_mul(n.into())) + // Minimum execution time: 20_009_000 picoseconds. + Weight::from_parts(23_414_747, 3795) + // Standard Error: 2_751 + .saturating_add(Weight::from_parts(1_314_498, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -346,8 +346,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `625` // Estimated: `19894` - // Minimum execution time: 73_317_000 picoseconds. - Weight::from_parts(75_103_000, 19894) + // Minimum execution time: 79_257_000 picoseconds. + Weight::from_parts(81_293_000, 19894) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(14_u64)) } diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index 44335e8f575c..4f3a734d9868 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -17,10 +17,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/recovery/src/benchmarking.rs b/substrate/frame/recovery/src/benchmarking.rs index b7639742a620..ee97cb77d301 100644 --- a/substrate/frame/recovery/src/benchmarking.rs +++ b/substrate/frame/recovery/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use crate::Pallet; use alloc::{boxed::Box, vec, vec::Vec}; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_support::traits::{Currency, Get}; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -103,56 +103,55 @@ fn insert_recovery_account(caller: &T::AccountId, account: &T::Accoun >::insert(&account, recovery_config); } -benchmarks! { - as_recovered { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn as_recovered() { let caller: T::AccountId = whitelisted_caller(); let recovered_account: T::AccountId = account("recovered_account", 0, SEED); let recovered_account_lookup = T::Lookup::unlookup(recovered_account.clone()); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::insert(&caller, &recovered_account); - }: _( - RawOrigin::Signed(caller), - recovered_account_lookup, - Box::new(call) - ) - set_recovered { + #[extrinsic_call] + _(RawOrigin::Signed(caller), recovered_account_lookup, Box::new(call)) + } + + #[benchmark] + fn set_recovered() { let lost: T::AccountId = whitelisted_caller(); let lost_lookup = T::Lookup::unlookup(lost.clone()); let rescuer: T::AccountId = whitelisted_caller(); let rescuer_lookup = T::Lookup::unlookup(rescuer.clone()); - }: _( - RawOrigin::Root, - lost_lookup, - rescuer_lookup - ) verify { + + #[extrinsic_call] + _(RawOrigin::Root, lost_lookup, rescuer_lookup); + assert_last_event::( - Event::AccountRecovered { - lost_account: lost, - rescuer_account: rescuer, - }.into() + Event::AccountRecovered { lost_account: lost, rescuer_account: rescuer }.into(), ); } - create_recovery { - let n in 1 .. T::MaxFriends::get(); - + #[benchmark] + fn create_recovery(n: Linear<1, { T::MaxFriends::get() }>) { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Create friends let friends = generate_friends::(n); - }: _( - RawOrigin::Signed(caller.clone()), - friends, - n as u16, - DEFAULT_DELAY.into() - ) verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), friends, n as u16, DEFAULT_DELAY.into()); + assert_last_event::(Event::RecoveryCreated { account: caller }.into()); } - initiate_recovery { + #[benchmark] + fn initiate_recovery() { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -160,28 +159,23 @@ benchmarks! { let lost_account_lookup = T::Lookup::unlookup(lost_account.clone()); insert_recovery_account::(&caller, &lost_account); - }: _( - RawOrigin::Signed(caller.clone()), - lost_account_lookup - ) verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), lost_account_lookup); + assert_last_event::( - Event::RecoveryInitiated { - lost_account: lost_account, - rescuer_account: caller, - }.into() + Event::RecoveryInitiated { lost_account, rescuer_account: caller }.into(), ); } - vouch_recovery { - let n in 1 .. T::MaxFriends::get(); - + #[benchmark] + fn vouch_recovery(n: Linear<1, { T::MaxFriends::get() }>) { let caller: T::AccountId = whitelisted_caller(); let lost_account: T::AccountId = account("lost_account", 0, SEED); let lost_account_lookup = T::Lookup::unlookup(lost_account.clone()); let rescuer_account: T::AccountId = account("rescuer_account", 0, SEED); let rescuer_account_lookup = T::Lookup::unlookup(rescuer_account.clone()); - // Create friends let friends = add_caller_and_generate_friends::(caller.clone(), n); let bounded_friends: FriendsOf = friends.try_into().unwrap(); @@ -212,23 +206,15 @@ benchmarks! { // Create the active recovery storage item >::insert(&lost_account, &rescuer_account, recovery_status); - }: _( - RawOrigin::Signed(caller.clone()), - lost_account_lookup, - rescuer_account_lookup - ) verify { + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), lost_account_lookup, rescuer_account_lookup); assert_last_event::( - Event::RecoveryVouched { - lost_account: lost_account, - rescuer_account: rescuer_account, - sender: caller, - }.into() + Event::RecoveryVouched { lost_account, rescuer_account, sender: caller }.into(), ); } - claim_recovery { - let n in 1 .. T::MaxFriends::get(); - + #[benchmark] + fn claim_recovery(n: Linear<1, { T::MaxFriends::get() }>) { let caller: T::AccountId = whitelisted_caller(); let lost_account: T::AccountId = account("lost_account", 0, SEED); let lost_account_lookup = T::Lookup::unlookup(lost_account.clone()); @@ -264,25 +250,20 @@ benchmarks! { // Create the active recovery storage item >::insert(&lost_account, &caller, recovery_status); - }: _( - RawOrigin::Signed(caller.clone()), - lost_account_lookup - ) verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), lost_account_lookup); assert_last_event::( - Event::AccountRecovered { - lost_account: lost_account, - rescuer_account: caller, - }.into() + Event::AccountRecovered { lost_account, rescuer_account: caller }.into(), ); } - close_recovery { + #[benchmark] + fn close_recovery(n: Linear<1, { T::MaxFriends::get() }>) { let caller: T::AccountId = whitelisted_caller(); let rescuer_account: T::AccountId = account("rescuer_account", 0, SEED); let rescuer_account_lookup = T::Lookup::unlookup(rescuer_account.clone()); - let n in 1 .. T::MaxFriends::get(); - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); T::Currency::make_free_balance_be(&rescuer_account, BalanceOf::::max_value()); @@ -315,21 +296,16 @@ benchmarks! { // Create the active recovery storage item >::insert(&caller, &rescuer_account, recovery_status); - }: _( - RawOrigin::Signed(caller.clone()), - rescuer_account_lookup - ) verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), rescuer_account_lookup); assert_last_event::( - Event::RecoveryClosed { - lost_account: caller, - rescuer_account: rescuer_account, - }.into() + Event::RecoveryClosed { lost_account: caller, rescuer_account }.into(), ); } - remove_recovery { - let n in 1 .. T::MaxFriends::get(); - + #[benchmark] + fn remove_recovery(n: Linear<1, { T::MaxFriends::get() }>) { let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -353,17 +329,14 @@ benchmarks! { // Reserve deposit for recovery T::Currency::reserve(&caller, total_deposit).unwrap(); - }: _( - RawOrigin::Signed(caller.clone()) - ) verify { - assert_last_event::( - Event::RecoveryRemoved { - lost_account: caller - }.into() - ); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + assert_last_event::(Event::RecoveryRemoved { lost_account: caller }.into()); } - cancel_recovered { + #[benchmark] + fn cancel_recovered() -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let account: T::AccountId = account("account", 0, SEED); let account_lookup = T::Lookup::unlookup(account.clone()); @@ -373,10 +346,12 @@ benchmarks! { frame_system::Pallet::::inc_consumers(&caller)?; Proxy::::insert(&caller, &account); - }: _( - RawOrigin::Signed(caller), - account_lookup - ) + + #[extrinsic_call] + _(RawOrigin::Signed(caller), account_lookup); + + Ok(()) + } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/substrate/frame/recovery/src/lib.rs b/substrate/frame/recovery/src/lib.rs index f8622880538e..d8f3c33fbea9 100644 --- a/substrate/frame/recovery/src/lib.rs +++ b/substrate/frame/recovery/src/lib.rs @@ -156,7 +156,10 @@ use alloc::{boxed::Box, vec::Vec}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{CheckedAdd, CheckedMul, Dispatchable, SaturatedConversion, StaticLookup}, + traits::{ + BlockNumberProvider, CheckedAdd, CheckedMul, Dispatchable, SaturatedConversion, + StaticLookup, + }, RuntimeDebug, }; @@ -178,11 +181,12 @@ mod mock; mod tests; pub mod weights; +type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; - +type BlockNumberFromProviderOf = + <::BlockNumberProvider as BlockNumberProvider>::BlockNumber; type FriendsOf = BoundedVec<::AccountId, ::MaxFriends>; -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// An active recovery process. #[derive(Clone, Eq, PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -190,7 +194,7 @@ pub struct ActiveRecovery { /// The block number when the recovery process started. created: BlockNumber, /// The amount held in reserve of the `depositor`, - /// To be returned once this recovery process is closed. + /// to be returned once this recovery process is closed. deposit: Balance, /// The friends which have vouched so far. Always sorted. friends: Friends, @@ -236,6 +240,9 @@ pub mod pallet { + GetDispatchInfo + From>; + /// Provider for the block number. Normally this is the `frame_system` pallet. + type BlockNumberProvider: BlockNumberProvider; + /// The currency mechanism. type Currency: ReservableCurrency; @@ -339,7 +346,7 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - RecoveryConfig, BalanceOf, FriendsOf>, + RecoveryConfig, BalanceOf, FriendsOf>, >; /// Active recovery attempts. @@ -354,7 +361,7 @@ pub mod pallet { T::AccountId, Twox64Concat, T::AccountId, - ActiveRecovery, BalanceOf, FriendsOf>, + ActiveRecovery, BalanceOf, FriendsOf>, >; /// The list of allowed proxy accounts. @@ -445,7 +452,7 @@ pub mod pallet { origin: OriginFor, friends: Vec, threshold: u16, - delay_period: BlockNumberFor, + delay_period: BlockNumberFromProviderOf, ) -> DispatchResult { let who = ensure_signed(origin)?; // Check account is not already set up for recovery @@ -511,7 +518,7 @@ pub mod pallet { T::Currency::reserve(&who, recovery_deposit)?; // Create an active recovery status let recovery_status = ActiveRecovery { - created: >::block_number(), + created: T::BlockNumberProvider::current_block_number(), deposit: recovery_deposit, friends: Default::default(), }; @@ -596,7 +603,7 @@ pub mod pallet { Self::active_recovery(&account, &who).ok_or(Error::::NotStarted)?; ensure!(!Proxy::::contains_key(&who), Error::::AlreadyProxy); // Make sure the delay period has passed - let current_block_number = >::block_number(); + let current_block_number = T::BlockNumberProvider::current_block_number(); let recoverable_block_number = active_recovery .created .checked_add(&recovery_config.delay_period) diff --git a/substrate/frame/recovery/src/mock.rs b/substrate/frame/recovery/src/mock.rs index 8e30cbe997e1..3930db82d6c7 100644 --- a/substrate/frame/recovery/src/mock.rs +++ b/substrate/frame/recovery/src/mock.rs @@ -66,6 +66,7 @@ impl Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type RuntimeCall = RuntimeCall; + type BlockNumberProvider = System; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; diff --git a/substrate/frame/recovery/src/weights.rs b/substrate/frame/recovery/src/weights.rs index e38ad0461afd..38b085f0a293 100644 --- a/substrate/frame/recovery/src/weights.rs +++ b/substrate/frame/recovery/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_recovery` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -73,10 +73,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `497` + // Measured: `530` // Estimated: `3997` - // Minimum execution time: 15_318_000 picoseconds. - Weight::from_parts(15_767_000, 3997) + // Minimum execution time: 21_063_000 picoseconds. + Weight::from_parts(21_784_000, 3997) .saturating_add(T::DbWeight::get().reads(3_u64)) } /// Storage: `Recovery::Proxy` (r:0 w:1) @@ -85,8 +85,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_153_000 picoseconds. - Weight::from_parts(7_578_000, 0) + // Minimum execution time: 6_653_000 picoseconds. + Weight::from_parts(7_009_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Recovery::Recoverable` (r:1 w:1) @@ -94,12 +94,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `279` // Estimated: `3816` - // Minimum execution time: 23_303_000 picoseconds. - Weight::from_parts(24_725_158, 3816) - // Standard Error: 5_723 - .saturating_add(Weight::from_parts(13_638, 0).saturating_mul(n.into())) + // Minimum execution time: 27_992_000 picoseconds. + Weight::from_parts(29_149_096, 3816) + // Standard Error: 5_733 + .saturating_add(Weight::from_parts(87_755, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -109,10 +109,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) fn initiate_recovery() -> Weight { // Proof Size summary in bytes: - // Measured: `343` + // Measured: `376` // Estimated: `3854` - // Minimum execution time: 26_914_000 picoseconds. - Weight::from_parts(28_041_000, 3854) + // Minimum execution time: 32_675_000 picoseconds. + Weight::from_parts(34_217_000, 3854) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -123,12 +123,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + n * (64 ±0)` + // Measured: `464 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 17_695_000 picoseconds. - Weight::from_parts(18_591_642, 3854) - // Standard Error: 5_582 - .saturating_add(Weight::from_parts(188_668, 0).saturating_mul(n.into())) + // Minimum execution time: 23_557_000 picoseconds. + Weight::from_parts(24_517_150, 3854) + // Standard Error: 5_550 + .saturating_add(Weight::from_parts(156_378, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -141,12 +141,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `463 + n * (64 ±0)` + // Measured: `496 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 22_580_000 picoseconds. - Weight::from_parts(23_526_020, 3854) - // Standard Error: 6_604 - .saturating_add(Weight::from_parts(134_340, 0).saturating_mul(n.into())) + // Minimum execution time: 28_261_000 picoseconds. + Weight::from_parts(29_298_729, 3854) + // Standard Error: 5_392 + .saturating_add(Weight::from_parts(162_096, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -157,12 +157,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `584 + n * (32 ±0)` + // Measured: `617 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 32_017_000 picoseconds. - Weight::from_parts(33_401_086, 3854) - // Standard Error: 6_498 - .saturating_add(Weight::from_parts(95_507, 0).saturating_mul(n.into())) + // Minimum execution time: 38_953_000 picoseconds. + Weight::from_parts(40_675_824, 3854) + // Standard Error: 6_163 + .saturating_add(Weight::from_parts(144_246, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -173,12 +173,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `341 + n * (32 ±0)` + // Measured: `374 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 28_641_000 picoseconds. - Weight::from_parts(30_230_511, 3854) - // Standard Error: 7_058 - .saturating_add(Weight::from_parts(61_004, 0).saturating_mul(n.into())) + // Minimum execution time: 32_735_000 picoseconds. + Weight::from_parts(33_830_787, 3854) + // Standard Error: 7_758 + .saturating_add(Weight::from_parts(194_601, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,10 +186,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) fn cancel_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `385` // Estimated: `3545` - // Minimum execution time: 11_767_000 picoseconds. - Weight::from_parts(12_275_000, 3545) + // Minimum execution time: 17_356_000 picoseconds. + Weight::from_parts(18_101_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -205,10 +205,10 @@ impl WeightInfo for () { /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `497` + // Measured: `530` // Estimated: `3997` - // Minimum execution time: 15_318_000 picoseconds. - Weight::from_parts(15_767_000, 3997) + // Minimum execution time: 21_063_000 picoseconds. + Weight::from_parts(21_784_000, 3997) .saturating_add(RocksDbWeight::get().reads(3_u64)) } /// Storage: `Recovery::Proxy` (r:0 w:1) @@ -217,8 +217,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_153_000 picoseconds. - Weight::from_parts(7_578_000, 0) + // Minimum execution time: 6_653_000 picoseconds. + Weight::from_parts(7_009_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Recovery::Recoverable` (r:1 w:1) @@ -226,12 +226,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `279` // Estimated: `3816` - // Minimum execution time: 23_303_000 picoseconds. - Weight::from_parts(24_725_158, 3816) - // Standard Error: 5_723 - .saturating_add(Weight::from_parts(13_638, 0).saturating_mul(n.into())) + // Minimum execution time: 27_992_000 picoseconds. + Weight::from_parts(29_149_096, 3816) + // Standard Error: 5_733 + .saturating_add(Weight::from_parts(87_755, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -241,10 +241,10 @@ impl WeightInfo for () { /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) fn initiate_recovery() -> Weight { // Proof Size summary in bytes: - // Measured: `343` + // Measured: `376` // Estimated: `3854` - // Minimum execution time: 26_914_000 picoseconds. - Weight::from_parts(28_041_000, 3854) + // Minimum execution time: 32_675_000 picoseconds. + Weight::from_parts(34_217_000, 3854) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -255,12 +255,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + n * (64 ±0)` + // Measured: `464 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 17_695_000 picoseconds. - Weight::from_parts(18_591_642, 3854) - // Standard Error: 5_582 - .saturating_add(Weight::from_parts(188_668, 0).saturating_mul(n.into())) + // Minimum execution time: 23_557_000 picoseconds. + Weight::from_parts(24_517_150, 3854) + // Standard Error: 5_550 + .saturating_add(Weight::from_parts(156_378, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -273,12 +273,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `463 + n * (64 ±0)` + // Measured: `496 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 22_580_000 picoseconds. - Weight::from_parts(23_526_020, 3854) - // Standard Error: 6_604 - .saturating_add(Weight::from_parts(134_340, 0).saturating_mul(n.into())) + // Minimum execution time: 28_261_000 picoseconds. + Weight::from_parts(29_298_729, 3854) + // Standard Error: 5_392 + .saturating_add(Weight::from_parts(162_096, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -289,12 +289,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `584 + n * (32 ±0)` + // Measured: `617 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 32_017_000 picoseconds. - Weight::from_parts(33_401_086, 3854) - // Standard Error: 6_498 - .saturating_add(Weight::from_parts(95_507, 0).saturating_mul(n.into())) + // Minimum execution time: 38_953_000 picoseconds. + Weight::from_parts(40_675_824, 3854) + // Standard Error: 6_163 + .saturating_add(Weight::from_parts(144_246, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -305,12 +305,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `341 + n * (32 ±0)` + // Measured: `374 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 28_641_000 picoseconds. - Weight::from_parts(30_230_511, 3854) - // Standard Error: 7_058 - .saturating_add(Weight::from_parts(61_004, 0).saturating_mul(n.into())) + // Minimum execution time: 32_735_000 picoseconds. + Weight::from_parts(33_830_787, 3854) + // Standard Error: 7_758 + .saturating_add(Weight::from_parts(194_601, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -318,10 +318,10 @@ impl WeightInfo for () { /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) fn cancel_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `385` // Estimated: `3545` - // Minimum execution time: 11_767_000 picoseconds. - Weight::from_parts(12_275_000, 3545) + // Minimum execution time: 17_356_000 picoseconds. + Weight::from_parts(18_101_000, 3545) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 32dba3436595..0f35dc74382e 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -20,15 +20,15 @@ assert_matches = { optional = true, workspace = true } codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], optional = true, workspace = true, default-features = true } -sp-arithmetic = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } +sp-arithmetic = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -log = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } @@ -57,7 +57,6 @@ std = [ ] runtime-benchmarks = [ "assert_matches", - "frame-benchmarking", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/substrate/frame/referenda/src/weights.rs b/substrate/frame/referenda/src/weights.rs index b34758ee4667..7c94b2b1799f 100644 --- a/substrate/frame/referenda/src/weights.rs +++ b/substrate/frame/referenda/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_referenda` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -96,8 +96,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `286` // Estimated: `110487` - // Minimum execution time: 33_162_000 picoseconds. - Weight::from_parts(34_217_000, 110487) + // Minimum execution time: 38_152_000 picoseconds. + Weight::from_parts(39_632_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -111,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `539` // Estimated: `219984` - // Minimum execution time: 45_276_000 picoseconds. - Weight::from_parts(46_903_000, 219984) + // Minimum execution time: 52_369_000 picoseconds. + Weight::from_parts(55_689_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -130,8 +130,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3326` // Estimated: `110487` - // Minimum execution time: 63_832_000 picoseconds. - Weight::from_parts(65_616_000, 110487) + // Minimum execution time: 68_807_000 picoseconds. + Weight::from_parts(71_917_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -149,8 +149,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3346` // Estimated: `110487` - // Minimum execution time: 63_726_000 picoseconds. - Weight::from_parts(64_909_000, 110487) + // Minimum execution time: 68_971_000 picoseconds. + Weight::from_parts(71_317_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -166,8 +166,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `539` // Estimated: `219984` - // Minimum execution time: 53_001_000 picoseconds. - Weight::from_parts(54_489_000, 219984) + // Minimum execution time: 59_447_000 picoseconds. + Weight::from_parts(61_121_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -183,8 +183,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `539` // Estimated: `219984` - // Minimum execution time: 51_021_000 picoseconds. - Weight::from_parts(53_006_000, 219984) + // Minimum execution time: 58_243_000 picoseconds. + Weight::from_parts(59_671_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -194,8 +194,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3831` - // Minimum execution time: 26_572_000 picoseconds. - Weight::from_parts(27_534_000, 3831) + // Minimum execution time: 31_621_000 picoseconds. + Weight::from_parts(32_628_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -205,8 +205,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `407` // Estimated: `3831` - // Minimum execution time: 26_897_000 picoseconds. - Weight::from_parts(27_883_000, 3831) + // Minimum execution time: 32_483_000 picoseconds. + Weight::from_parts(33_427_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -220,8 +220,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `447` // Estimated: `219984` - // Minimum execution time: 31_767_000 picoseconds. - Weight::from_parts(33_045_000, 219984) + // Minimum execution time: 36_283_000 picoseconds. + Weight::from_parts(37_748_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -237,8 +237,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `688` // Estimated: `219984` - // Minimum execution time: 67_798_000 picoseconds. - Weight::from_parts(70_044_000, 219984) + // Minimum execution time: 75_460_000 picoseconds. + Weight::from_parts(77_956_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -250,8 +250,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `240` // Estimated: `5477` - // Minimum execution time: 10_056_000 picoseconds. - Weight::from_parts(10_460_000, 5477) + // Minimum execution time: 15_139_000 picoseconds. + Weight::from_parts(15_651_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -265,8 +265,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 44_293_000 picoseconds. - Weight::from_parts(45_784_000, 110487) + // Minimum execution time: 48_590_000 picoseconds. + Weight::from_parts(50_207_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -280,8 +280,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 45_642_000 picoseconds. - Weight::from_parts(47_252_000, 110487) + // Minimum execution time: 48_555_000 picoseconds. + Weight::from_parts(49_956_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -293,8 +293,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 22_096_000 picoseconds. - Weight::from_parts(22_496_000, 5477) + // Minimum execution time: 28_326_000 picoseconds. + Weight::from_parts(29_735_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -306,8 +306,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 21_931_000 picoseconds. - Weight::from_parts(22_312_000, 5477) + // Minimum execution time: 28_209_000 picoseconds. + Weight::from_parts(29_375_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -321,8 +321,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3081` // Estimated: `5477` - // Minimum execution time: 28_890_000 picoseconds. - Weight::from_parts(29_679_000, 5477) + // Minimum execution time: 33_973_000 picoseconds. + Weight::from_parts(35_732_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -336,8 +336,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3101` // Estimated: `5477` - // Minimum execution time: 28_875_000 picoseconds. - Weight::from_parts(29_492_000, 5477) + // Minimum execution time: 34_112_000 picoseconds. + Weight::from_parts(35_748_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -349,8 +349,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `399` // Estimated: `110487` - // Minimum execution time: 19_787_000 picoseconds. - Weight::from_parts(20_493_000, 110487) + // Minimum execution time: 26_135_000 picoseconds. + Weight::from_parts(27_080_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -362,8 +362,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `447` // Estimated: `110487` - // Minimum execution time: 19_987_000 picoseconds. - Weight::from_parts(20_860_000, 110487) + // Minimum execution time: 26_494_000 picoseconds. + Weight::from_parts(27_290_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -373,8 +373,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `344` // Estimated: `3831` - // Minimum execution time: 13_416_000 picoseconds. - Weight::from_parts(13_857_000, 3831) + // Minimum execution time: 15_294_000 picoseconds. + Weight::from_parts(15_761_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -388,8 +388,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `447` // Estimated: `110487` - // Minimum execution time: 27_199_000 picoseconds. - Weight::from_parts(28_562_000, 110487) + // Minimum execution time: 32_360_000 picoseconds. + Weight::from_parts(33_747_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -403,8 +403,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `447` // Estimated: `110487` - // Minimum execution time: 29_205_000 picoseconds. - Weight::from_parts(30_407_000, 110487) + // Minimum execution time: 34_133_000 picoseconds. + Weight::from_parts(35_784_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -416,8 +416,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `500` // Estimated: `110487` - // Minimum execution time: 24_136_000 picoseconds. - Weight::from_parts(24_868_000, 110487) + // Minimum execution time: 30_009_000 picoseconds. + Weight::from_parts(30_985_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -429,8 +429,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `483` // Estimated: `110487` - // Minimum execution time: 23_860_000 picoseconds. - Weight::from_parts(24_556_000, 110487) + // Minimum execution time: 29_439_000 picoseconds. + Weight::from_parts(30_386_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -442,8 +442,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `500` // Estimated: `110487` - // Minimum execution time: 23_409_000 picoseconds. - Weight::from_parts(24_354_000, 110487) + // Minimum execution time: 29_293_000 picoseconds. + Weight::from_parts(30_577_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -455,8 +455,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `504` // Estimated: `110487` - // Minimum execution time: 21_947_000 picoseconds. - Weight::from_parts(22_485_000, 110487) + // Minimum execution time: 27_418_000 picoseconds. + Weight::from_parts(28_718_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -470,8 +470,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `504` // Estimated: `219984` - // Minimum execution time: 34_643_000 picoseconds. - Weight::from_parts(36_193_000, 219984) + // Minimum execution time: 40_020_000 picoseconds. + Weight::from_parts(40_861_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -483,8 +483,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `500` // Estimated: `110487` - // Minimum execution time: 24_097_000 picoseconds. - Weight::from_parts(24_881_000, 110487) + // Minimum execution time: 29_843_000 picoseconds. + Weight::from_parts(30_764_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -498,10 +498,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `555` + // Measured: `450` // Estimated: `3831` - // Minimum execution time: 19_947_000 picoseconds. - Weight::from_parts(20_396_000, 3831) + // Minimum execution time: 24_642_000 picoseconds. + Weight::from_parts(25_498_000, 3831) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -513,8 +513,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `421` // Estimated: `3831` - // Minimum execution time: 15_516_000 picoseconds. - Weight::from_parts(16_094_000, 3831) + // Minimum execution time: 20_867_000 picoseconds. + Weight::from_parts(21_803_000, 3831) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -532,8 +532,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `286` // Estimated: `110487` - // Minimum execution time: 33_162_000 picoseconds. - Weight::from_parts(34_217_000, 110487) + // Minimum execution time: 38_152_000 picoseconds. + Weight::from_parts(39_632_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -547,8 +547,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `539` // Estimated: `219984` - // Minimum execution time: 45_276_000 picoseconds. - Weight::from_parts(46_903_000, 219984) + // Minimum execution time: 52_369_000 picoseconds. + Weight::from_parts(55_689_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -566,8 +566,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3326` // Estimated: `110487` - // Minimum execution time: 63_832_000 picoseconds. - Weight::from_parts(65_616_000, 110487) + // Minimum execution time: 68_807_000 picoseconds. + Weight::from_parts(71_917_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -585,8 +585,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3346` // Estimated: `110487` - // Minimum execution time: 63_726_000 picoseconds. - Weight::from_parts(64_909_000, 110487) + // Minimum execution time: 68_971_000 picoseconds. + Weight::from_parts(71_317_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -602,8 +602,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `539` // Estimated: `219984` - // Minimum execution time: 53_001_000 picoseconds. - Weight::from_parts(54_489_000, 219984) + // Minimum execution time: 59_447_000 picoseconds. + Weight::from_parts(61_121_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -619,8 +619,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `539` // Estimated: `219984` - // Minimum execution time: 51_021_000 picoseconds. - Weight::from_parts(53_006_000, 219984) + // Minimum execution time: 58_243_000 picoseconds. + Weight::from_parts(59_671_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -630,8 +630,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `417` // Estimated: `3831` - // Minimum execution time: 26_572_000 picoseconds. - Weight::from_parts(27_534_000, 3831) + // Minimum execution time: 31_621_000 picoseconds. + Weight::from_parts(32_628_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -641,8 +641,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `407` // Estimated: `3831` - // Minimum execution time: 26_897_000 picoseconds. - Weight::from_parts(27_883_000, 3831) + // Minimum execution time: 32_483_000 picoseconds. + Weight::from_parts(33_427_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -656,8 +656,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `447` // Estimated: `219984` - // Minimum execution time: 31_767_000 picoseconds. - Weight::from_parts(33_045_000, 219984) + // Minimum execution time: 36_283_000 picoseconds. + Weight::from_parts(37_748_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -673,8 +673,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `688` // Estimated: `219984` - // Minimum execution time: 67_798_000 picoseconds. - Weight::from_parts(70_044_000, 219984) + // Minimum execution time: 75_460_000 picoseconds. + Weight::from_parts(77_956_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -686,8 +686,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `240` // Estimated: `5477` - // Minimum execution time: 10_056_000 picoseconds. - Weight::from_parts(10_460_000, 5477) + // Minimum execution time: 15_139_000 picoseconds. + Weight::from_parts(15_651_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -701,8 +701,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 44_293_000 picoseconds. - Weight::from_parts(45_784_000, 110487) + // Minimum execution time: 48_590_000 picoseconds. + Weight::from_parts(50_207_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -716,8 +716,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3216` // Estimated: `110487` - // Minimum execution time: 45_642_000 picoseconds. - Weight::from_parts(47_252_000, 110487) + // Minimum execution time: 48_555_000 picoseconds. + Weight::from_parts(49_956_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -729,8 +729,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 22_096_000 picoseconds. - Weight::from_parts(22_496_000, 5477) + // Minimum execution time: 28_326_000 picoseconds. + Weight::from_parts(29_735_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -742,8 +742,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 21_931_000 picoseconds. - Weight::from_parts(22_312_000, 5477) + // Minimum execution time: 28_209_000 picoseconds. + Weight::from_parts(29_375_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -757,8 +757,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3081` // Estimated: `5477` - // Minimum execution time: 28_890_000 picoseconds. - Weight::from_parts(29_679_000, 5477) + // Minimum execution time: 33_973_000 picoseconds. + Weight::from_parts(35_732_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -772,8 +772,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3101` // Estimated: `5477` - // Minimum execution time: 28_875_000 picoseconds. - Weight::from_parts(29_492_000, 5477) + // Minimum execution time: 34_112_000 picoseconds. + Weight::from_parts(35_748_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -785,8 +785,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `399` // Estimated: `110487` - // Minimum execution time: 19_787_000 picoseconds. - Weight::from_parts(20_493_000, 110487) + // Minimum execution time: 26_135_000 picoseconds. + Weight::from_parts(27_080_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -798,8 +798,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `447` // Estimated: `110487` - // Minimum execution time: 19_987_000 picoseconds. - Weight::from_parts(20_860_000, 110487) + // Minimum execution time: 26_494_000 picoseconds. + Weight::from_parts(27_290_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -809,8 +809,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `344` // Estimated: `3831` - // Minimum execution time: 13_416_000 picoseconds. - Weight::from_parts(13_857_000, 3831) + // Minimum execution time: 15_294_000 picoseconds. + Weight::from_parts(15_761_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -824,8 +824,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `447` // Estimated: `110487` - // Minimum execution time: 27_199_000 picoseconds. - Weight::from_parts(28_562_000, 110487) + // Minimum execution time: 32_360_000 picoseconds. + Weight::from_parts(33_747_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -839,8 +839,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `447` // Estimated: `110487` - // Minimum execution time: 29_205_000 picoseconds. - Weight::from_parts(30_407_000, 110487) + // Minimum execution time: 34_133_000 picoseconds. + Weight::from_parts(35_784_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -852,8 +852,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `500` // Estimated: `110487` - // Minimum execution time: 24_136_000 picoseconds. - Weight::from_parts(24_868_000, 110487) + // Minimum execution time: 30_009_000 picoseconds. + Weight::from_parts(30_985_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -865,8 +865,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `483` // Estimated: `110487` - // Minimum execution time: 23_860_000 picoseconds. - Weight::from_parts(24_556_000, 110487) + // Minimum execution time: 29_439_000 picoseconds. + Weight::from_parts(30_386_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -878,8 +878,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `500` // Estimated: `110487` - // Minimum execution time: 23_409_000 picoseconds. - Weight::from_parts(24_354_000, 110487) + // Minimum execution time: 29_293_000 picoseconds. + Weight::from_parts(30_577_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -891,8 +891,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `504` // Estimated: `110487` - // Minimum execution time: 21_947_000 picoseconds. - Weight::from_parts(22_485_000, 110487) + // Minimum execution time: 27_418_000 picoseconds. + Weight::from_parts(28_718_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -906,8 +906,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `504` // Estimated: `219984` - // Minimum execution time: 34_643_000 picoseconds. - Weight::from_parts(36_193_000, 219984) + // Minimum execution time: 40_020_000 picoseconds. + Weight::from_parts(40_861_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -919,8 +919,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `500` // Estimated: `110487` - // Minimum execution time: 24_097_000 picoseconds. - Weight::from_parts(24_881_000, 110487) + // Minimum execution time: 29_843_000 picoseconds. + Weight::from_parts(30_764_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -934,10 +934,10 @@ impl WeightInfo for () { /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `555` + // Measured: `450` // Estimated: `3831` - // Minimum execution time: 19_947_000 picoseconds. - Weight::from_parts(20_396_000, 3831) + // Minimum execution time: 24_642_000 picoseconds. + Weight::from_parts(25_498_000, 3831) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -949,8 +949,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `421` // Estimated: `3831` - // Minimum execution time: 15_516_000 picoseconds. - Weight::from_parts(16_094_000, 3831) + // Minimum execution time: 20_867_000 picoseconds. + Weight::from_parts(21_803_000, 3831) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index 487bada593cd..a40b577b52ea 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/remark/src/benchmarking.rs b/substrate/frame/remark/src/benchmarking.rs index 15b72b4748dd..41d49c3b930b 100644 --- a/substrate/frame/remark/src/benchmarking.rs +++ b/substrate/frame/remark/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use alloc::vec; -use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_system::{EventRecord, Pallet as System, RawOrigin}; #[cfg(test)] @@ -34,13 +34,24 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { assert_eq!(event, &system_event); } -benchmarks! { - store { - let l in 1 .. 1024*1024; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn store(l: Linear<1, { 1024 * 1024 }>) { let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]) - verify { - assert_last_event::(Event::Stored { sender: caller, content_hash: sp_io::hashing::blake2_256(&vec![0u8; l as usize]).into() }.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]); + + assert_last_event::( + Event::Stored { + sender: caller, + content_hash: sp_io::hashing::blake2_256(&vec![0u8; l as usize]).into(), + } + .into(), + ); } impl_benchmark_test_suite!(Remark, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/remark/src/weights.rs b/substrate/frame/remark/src/weights.rs index 8a8bdef6dd0f..26838f74a319 100644 --- a/substrate/frame/remark/src/weights.rs +++ b/substrate/frame/remark/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_remark` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -62,10 +62,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_652_000 picoseconds. - Weight::from_parts(6_793_000, 0) + // Minimum execution time: 6_242_000 picoseconds. + Weight::from_parts(15_241_545, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_364, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_643, 0).saturating_mul(l.into())) } } @@ -76,9 +76,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_652_000 picoseconds. - Weight::from_parts(6_793_000, 0) + // Minimum execution time: 6_242_000 picoseconds. + Weight::from_parts(15_241_545, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_364, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_643, 0).saturating_mul(l.into())) } } diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 67bc1809cad7..fa008f8e836a 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -17,32 +17,29 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { features = ["derive", "max-encoded-len"], workspace = true } +derive_more = { workspace = true } environmental = { workspace = true } +ethereum-types = { workspace = true, features = ["codec", "rlp", "serialize"] } +hex = { workspace = true } +impl-trait-for-tuples = { workspace = true } +log = { workspace = true } paste = { workspace = true } -polkavm = { version = "0.13.0", default-features = false } -bitflags = { workspace = true } -codec = { features = ["derive", "max-encoded-len"], workspace = true } +polkavm = { version = "0.18.0", default-features = false } +rlp = { workspace = true } scale-info = { features = ["derive"], workspace = true } -log = { workspace = true } serde = { features = [ "alloc", "derive", ], workspace = true, default-features = false } -impl-trait-for-tuples = { workspace = true } -rlp = { workspace = true } -derive_more = { workspace = true } -hex = { workspace = true } -jsonrpsee = { workspace = true, features = ["full"], optional = true } -ethereum-types = { workspace = true, features = ["codec", "rlp", "serialize"] } # Polkadot SDK Dependencies frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -pallet-balances = { optional = true, workspace = true } -pallet-revive-fixtures = { workspace = true, default-features = false } -pallet-revive-uapi = { workspace = true, default-features = true } -pallet-revive-proc-macro = { workspace = true, default-features = true } +pallet-revive-fixtures = { workspace = true, optional = true } +pallet-revive-proc-macro = { workspace = true } +pallet-revive-uapi = { workspace = true, features = ["scale"] } pallet-transaction-payment = { workspace = true } sp-api = { workspace = true } sp-arithmetic = { workspace = true } @@ -50,29 +47,26 @@ sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -sp-weights = { workspace = true } -xcm = { workspace = true } -xcm-builder = { workspace = true } subxt-signer = { workspace = true, optional = true, features = [ "unstable-eth", ] } +xcm = { workspace = true } +xcm-builder = { workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } assert_matches = { workspace = true } +hex-literal = { workspace = true } pretty_assertions = { workspace = true } -pallet-revive-fixtures = { workspace = true, default-features = true } secp256k1 = { workspace = true, features = ["recovery"] } serde_json = { workspace = true } -hex-literal = { workspace = true } # Polkadot SDK Dependencies pallet-balances = { workspace = true, default-features = true } +pallet-proxy = { workspace = true, default-features = true } +pallet-revive-fixtures = { workspace = true, default-features = true } pallet-timestamp = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } pallet-utility = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-proxy = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } xcm-builder = { workspace = true, default-features = true } @@ -87,11 +81,9 @@ std = [ "frame-support/std", "frame-system/std", "hex/std", - "jsonrpsee", "log/std", - "pallet-balances?/std", "pallet-proxy/std", - "pallet-revive-fixtures/std", + "pallet-revive-fixtures?/std", "pallet-timestamp/std", "pallet-transaction-payment/std", "pallet-utility/std", @@ -108,7 +100,6 @@ std = [ "sp-keystore/std", "sp-runtime/std", "sp-std/std", - "sp-weights/std", "subxt-signer", "xcm-builder/std", "xcm/std", @@ -117,22 +108,20 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-revive-fixtures", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", - "pallet-assets/try-runtime", "pallet-balances/try-runtime", - "pallet-message-queue/try-runtime", "pallet-proxy/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", diff --git a/substrate/frame/revive/README.md b/substrate/frame/revive/README.md index 5352e636c252..575920dfaac7 100644 --- a/substrate/frame/revive/README.md +++ b/substrate/frame/revive/README.md @@ -92,7 +92,7 @@ Driven by the desire to have an iterative approach in developing new contract in concept of an unstable interface. Akin to the rust nightly compiler it allows us to add new interfaces but mark them as unstable so that contract languages can experiment with them and give feedback before we stabilize those. -In order to access interfaces which don't have a stable `#[api_version(x)]` in [`runtime.rs`](src/wasm/runtime.rs) +In order to access interfaces which don't have a stable `#[stable]` in [`runtime.rs`](src/wasm/runtime.rs) one need to set `pallet_revive::Config::UnsafeUnstableInterface` to `ConstU32`. **It should be obvious that any production runtime should never be compiled with this feature: In addition to be subject to change or removal those interfaces might not have proper weights associated with them and are therefore diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml index 7a5452853d65..e17bc88a3847 100644 --- a/substrate/frame/revive/fixtures/Cargo.toml +++ b/substrate/frame/revive/fixtures/Cargo.toml @@ -5,26 +5,26 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Fixtures for testing and benchmarking" +homepage.workspace = true +repository.workspace = true + +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true [lints] workspace = true [dependencies] -frame-system = { workspace = true, default-features = true, optional = true } +anyhow = { workspace = true, default-features = true, optional = true } sp-core = { workspace = true, default-features = true, optional = true } sp-io = { workspace = true, default-features = true, optional = true } -sp-runtime = { workspace = true, default-features = true, optional = true } -anyhow = { workspace = true, default-features = true, optional = true } -log = { workspace = true } [build-dependencies] -parity-wasm = { workspace = true } -tempfile = { workspace = true } -toml = { workspace = true } -polkavm-linker = { version = "0.14.0" } anyhow = { workspace = true, default-features = true } +polkavm-linker = { version = "0.18.0" } +toml = { workspace = true } [features] default = ["std"] # only when std is enabled all fixtures are available -std = ["anyhow", "frame-system", "log/std", "sp-core", "sp-io", "sp-runtime"] +std = ["anyhow", "sp-core", "sp-io"] diff --git a/substrate/frame/revive/fixtures/build.rs b/substrate/frame/revive/fixtures/build.rs index bbd986d9d44c..eca547bc6ddd 100644 --- a/substrate/frame/revive/fixtures/build.rs +++ b/substrate/frame/revive/fixtures/build.rs @@ -20,7 +20,8 @@ use anyhow::Result; use anyhow::{bail, Context}; use std::{ - cfg, env, fs, + env, fs, + io::Write, path::{Path, PathBuf}, process::Command, }; @@ -82,7 +83,7 @@ fn create_cargo_toml<'a>( entries: impl Iterator, output_dir: &Path, ) -> Result<()> { - let mut cargo_toml: toml::Value = toml::from_str(include_str!("./build/Cargo.toml"))?; + let mut cargo_toml: toml::Value = toml::from_str(include_str!("./build/_Cargo.toml"))?; let mut set_dep = |name, path| -> Result<()> { cargo_toml["dependencies"][name]["path"] = toml::Value::String( fixtures_dir.join(path).canonicalize()?.to_str().unwrap().to_string(), @@ -106,19 +107,25 @@ fn create_cargo_toml<'a>( ); let cargo_toml = toml::to_string_pretty(&cargo_toml)?; - fs::write(output_dir.join("Cargo.toml"), cargo_toml).map_err(Into::into) + fs::write(output_dir.join("Cargo.toml"), cargo_toml.clone()) + .with_context(|| format!("Failed to write {cargo_toml:?}"))?; + fs::copy( + fixtures_dir.join("build/_rust-toolchain.toml"), + output_dir.join("rust-toolchain.toml"), + ) + .context("Failed to write toolchain file")?; + Ok(()) } -fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> { +fn invoke_build(current_dir: &Path) -> Result<()> { let encoded_rustflags = ["-Dwarnings"].join("\x1f"); - let mut build_command = Command::new(env::var("CARGO")?); + let mut build_command = Command::new("cargo"); build_command .current_dir(current_dir) .env_clear() .env("PATH", env::var("PATH").unwrap_or_default()) .env("CARGO_ENCODED_RUSTFLAGS", encoded_rustflags) - .env("RUSTC_BOOTSTRAP", "1") .env("RUSTUP_HOME", env::var("RUSTUP_HOME").unwrap_or_default()) .args([ "build", @@ -127,7 +134,7 @@ fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> { "-Zbuild-std-features=panic_immediate_abort", ]) .arg("--target") - .arg(target); + .arg(polkavm_linker::target_json_64_path().unwrap()); if let Ok(toolchain) = env::var(OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR) { build_command.env("RUSTUP_TOOLCHAIN", &toolchain); @@ -147,16 +154,17 @@ fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> { /// Post-process the compiled code. fn post_process(input_path: &Path, output_path: &Path) -> Result<()> { - let strip = std::env::var(OVERRIDE_STRIP_ENV_VAR).map_or(false, |value| value == "1"); - let optimize = std::env::var(OVERRIDE_OPTIMIZE_ENV_VAR).map_or(true, |value| value == "1"); + let strip = env::var(OVERRIDE_STRIP_ENV_VAR).map_or(false, |value| value == "1"); + let optimize = env::var(OVERRIDE_OPTIMIZE_ENV_VAR).map_or(true, |value| value == "1"); let mut config = polkavm_linker::Config::default(); config.set_strip(strip); config.set_optimize(optimize); - let orig = fs::read(input_path).with_context(|| format!("Failed to read {:?}", input_path))?; + let orig = fs::read(input_path).with_context(|| format!("Failed to read {input_path:?}"))?; let linked = polkavm_linker::program_from_elf(config, orig.as_ref()) .map_err(|err| anyhow::format_err!("Failed to link polkavm program: {}", err))?; - fs::write(output_path, linked).map_err(Into::into) + fs::write(output_path, linked).with_context(|| format!("Failed to write {output_path:?}"))?; + Ok(()) } /// Write the compiled contracts to the given output directory. @@ -164,7 +172,7 @@ fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec) -> Result for entry in entries { post_process( &build_dir - .join("target/riscv32emac-unknown-none-polkavm/release") + .join("target/riscv64emac-unknown-none-polkavm/release") .join(entry.name()), &out_dir.join(entry.out_filename()), )?; @@ -173,11 +181,66 @@ fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec) -> Result Ok(()) } +/// Create a directory in the `target` as output directory +fn create_out_dir() -> Result { + let temp_dir: PathBuf = env::var("OUT_DIR")?.into(); + + // this is set in case the user has overriden the target directory + let out_dir = if let Ok(path) = env::var("CARGO_TARGET_DIR") { + path.into() + } else { + // otherwise just traverse up from the out dir + let mut out_dir: PathBuf = temp_dir.clone(); + loop { + if !out_dir.pop() { + bail!("Cannot find project root.") + } + if out_dir.join("Cargo.lock").exists() { + break; + } + } + out_dir.join("target") + } + .join("pallet-revive-fixtures"); + + // clean up some leftover symlink from previous versions of this script + let mut out_exists = out_dir.exists(); + if out_exists && !out_dir.is_dir() { + fs::remove_file(&out_dir)?; + out_exists = false; + } + + if !out_exists { + fs::create_dir(&out_dir).context("Failed to create output directory")?; + } + + // write the location of the out dir so it can be found later + let mut file = fs::File::create(temp_dir.join("fixture_location.rs")) + .context("Failed to create fixture_location.rs")?; + write!( + file, + r#" + #[allow(dead_code)] + const FIXTURE_DIR: &str = "{0}"; + macro_rules! fixture {{ + ($name: literal) => {{ + include_bytes!(concat!("{0}", "/", $name, ".polkavm")) + }}; + }} + "#, + out_dir.display() + ) + .context("Failed to write to fixture_location.rs")?; + + Ok(out_dir) +} + pub fn main() -> Result<()> { let fixtures_dir: PathBuf = env::var("CARGO_MANIFEST_DIR")?.into(); let contracts_dir = fixtures_dir.join("contracts"); - let out_dir: PathBuf = env::var("OUT_DIR")?.into(); - let target = fixtures_dir.join("riscv32emac-unknown-none-polkavm.json"); + let out_dir = create_out_dir().context("Cannot determine output directory")?; + let build_dir = out_dir.join("build"); + fs::create_dir_all(&build_dir).context("Failed to create build directory")?; println!("cargo::rerun-if-env-changed={OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR}"); println!("cargo::rerun-if-env-changed={OVERRIDE_STRIP_ENV_VAR}"); @@ -195,23 +258,9 @@ pub fn main() -> Result<()> { return Ok(()) } - let tmp_dir = tempfile::tempdir()?; - let tmp_dir_path = tmp_dir.path(); - - create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?; - invoke_build(&target, tmp_dir_path)?; - - write_output(tmp_dir_path, &out_dir, entries)?; - - #[cfg(unix)] - if let Ok(symlink_dir) = env::var("CARGO_WORKSPACE_ROOT_DIR") { - let symlink_dir: PathBuf = symlink_dir.into(); - let symlink_dir: PathBuf = symlink_dir.join("target").join("pallet-revive-fixtures"); - if symlink_dir.is_symlink() { - fs::remove_file(&symlink_dir)? - } - std::os::unix::fs::symlink(&out_dir, &symlink_dir)?; - } + create_cargo_toml(&fixtures_dir, entries.iter(), &build_dir)?; + invoke_build(&build_dir)?; + write_output(&build_dir, &out_dir, entries)?; Ok(()) } diff --git a/substrate/frame/revive/fixtures/build/Cargo.toml b/substrate/frame/revive/fixtures/build/_Cargo.toml similarity index 62% rename from substrate/frame/revive/fixtures/build/Cargo.toml rename to substrate/frame/revive/fixtures/build/_Cargo.toml index 5d0e256e2e73..bfb9aaedd6f5 100644 --- a/substrate/frame/revive/fixtures/build/Cargo.toml +++ b/substrate/frame/revive/fixtures/build/_Cargo.toml @@ -4,14 +4,17 @@ publish = false version = "1.0.0" edition = "2021" +# Make sure this is not included into the workspace +[workspace] + # Binary targets are injected dynamically by the build script. [[bin]] # All paths are injected dynamically by the build script. [dependencies] -uapi = { package = 'pallet-revive-uapi', path = "", default-features = false } +uapi = { package = 'pallet-revive-uapi', path = "", features = ["unstable-hostfn"], default-features = false } common = { package = 'pallet-revive-fixtures-common', path = "" } -polkavm-derive = { version = "0.14.0" } +polkavm-derive = { version = "0.18.0" } [profile.release] opt-level = 3 diff --git a/substrate/frame/revive/fixtures/build/_rust-toolchain.toml b/substrate/frame/revive/fixtures/build/_rust-toolchain.toml new file mode 100644 index 000000000000..4c757c708d58 --- /dev/null +++ b/substrate/frame/revive/fixtures/build/_rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2024-11-19" +components = ["rust-src"] +profile = "minimal" diff --git a/substrate/frame/revive/fixtures/contracts/base_fee.rs b/substrate/frame/revive/fixtures/contracts/base_fee.rs new file mode 100644 index 000000000000..157909463ee4 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/base_fee.rs @@ -0,0 +1,36 @@ +// 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. + +//! Returns the base fee back to the caller. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut buf = [0; 32]; + api::base_fee(&mut buf); + api::return_value(ReturnFlags::empty(), &buf); +} diff --git a/substrate/frame/revive/fixtures/contracts/call_data_copy.rs b/substrate/frame/revive/fixtures/contracts/call_data_copy.rs new file mode 100644 index 000000000000..ccf1664058e8 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/call_data_copy.rs @@ -0,0 +1,53 @@ +// 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. + +//! Expects a call data of [0xFF; 32] and executes the test vectors from +//! [https://www.evm.codes/?fork=cancun#37] and some additional tests. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api}; + +const TEST_DATA: [u8; 32] = [ + 255, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +]; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut buf = [0; 32]; + + api::call_data_copy(&mut &mut buf[..], 0); + assert_eq!(buf, [255; 32]); + + api::call_data_copy(&mut &mut buf[..8], 31); + assert_eq!(buf, TEST_DATA); + + api::call_data_copy(&mut &mut buf[..], 32); + assert_eq!(buf, [0; 32]); + + let mut buf = [255; 32]; + api::call_data_copy(&mut &mut buf[..], u32::MAX); + assert_eq!(buf, [0; 32]); +} diff --git a/substrate/frame/revive/fixtures/contracts/call_data_load.rs b/substrate/frame/revive/fixtures/contracts/call_data_load.rs new file mode 100644 index 000000000000..d3df9433f5d1 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/call_data_load.rs @@ -0,0 +1,44 @@ +// 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 uses the call data load API to first the first input byte. +//! This single input byte is used as the offset for a second call +//! to the call data load API. +//! The output of the second API call is returned. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut buf = [0; 32]; + api::call_data_load(&mut buf, 0); + + let offset = buf[31] as u32; + let mut buf = [0; 32]; + api::call_data_load(&mut buf, offset); + + api::return_value(ReturnFlags::empty(), &buf); +} diff --git a/substrate/frame/revive/fixtures/contracts/call_data_size.rs b/substrate/frame/revive/fixtures/contracts/call_data_size.rs new file mode 100644 index 000000000000..7caf18d440b8 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/call_data_size.rs @@ -0,0 +1,34 @@ +// 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. + +//! Returns the call data size back to the caller. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + api::return_value(ReturnFlags::empty(), &api::call_data_size().to_le_bytes()); +} diff --git a/substrate/frame/revive/fixtures/contracts/caller_contract.rs b/substrate/frame/revive/fixtures/contracts/caller_contract.rs index f9a30b87df47..edad43fae251 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_contract.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_contract.rs @@ -65,7 +65,7 @@ pub extern "C" fn call() { None, Some(&salt), ); - assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); + assert!(matches!(res, Err(ReturnErrorCode::OutOfResources))); // Fail to deploy the contract due to insufficient proof_size weight. let res = api::instantiate( @@ -79,7 +79,7 @@ pub extern "C" fn call() { None, Some(&salt), ); - assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); + assert!(matches!(res, Err(ReturnErrorCode::OutOfResources))); // Deploy the contract successfully. let mut callee = [0u8; 20]; @@ -121,7 +121,7 @@ pub extern "C" fn call() { &input, None, ); - assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); + assert!(matches!(res, Err(ReturnErrorCode::OutOfResources))); // Fail to call the contract due to insufficient proof_size weight. let res = api::call( @@ -134,7 +134,7 @@ pub extern "C" fn call() { &input, None, ); - assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); + assert!(matches!(res, Err(ReturnErrorCode::OutOfResources))); // Call the contract successfully. let mut output = [0u8; 4]; diff --git a/substrate/frame/revive/fixtures/contracts/common/src/lib.rs b/substrate/frame/revive/fixtures/contracts/common/src/lib.rs index abfba282bec1..302608ccf87c 100644 --- a/substrate/frame/revive/fixtures/contracts/common/src/lib.rs +++ b/substrate/frame/revive/fixtures/contracts/common/src/lib.rs @@ -121,8 +121,9 @@ macro_rules! input { // e.g input!(buffer, 512, var1: u32, var2: [u8], ); ($buffer:ident, $size:expr, $($rest:tt)*) => { let mut $buffer = [0u8; $size]; - let $buffer = &mut &mut $buffer[..]; - $crate::api::input($buffer); + let input_size = $crate::api::call_data_size(); + let $buffer = &mut &mut $buffer[..$size.min(input_size as usize)]; + $crate::api::call_data_copy($buffer, 0); input!(@inner $buffer, 0, $($rest)*); }; diff --git a/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs b/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs index 4fa2db0c8c1c..a12c36af856a 100644 --- a/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs +++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs @@ -40,7 +40,7 @@ pub extern "C" fn call() { api::set_storage(StorageFlags::empty(), buffer, &[1u8; 4]); // Call the callee - api::call( + let ret = api::call( uapi::CallFlags::empty(), callee, 0u64, // How much ref_time weight to devote for the execution. 0 = all. @@ -49,8 +49,10 @@ pub extern "C" fn call() { &[0u8; 32], // Value transferred to the contract. input, None, - ) - .unwrap(); + ); + if let Err(code) = ret { + api::return_value(uapi::ReturnFlags::REVERT, &(code as u32).to_le_bytes()); + }; // create 8 byte of storage after calling // item of 12 bytes because we override 4 bytes diff --git a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs index 463706457a15..ecc0fc79e6fd 100644 --- a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs +++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs @@ -39,7 +39,7 @@ pub extern "C" fn call() { let salt = [0u8; 32]; let mut address = [0u8; 20]; - api::instantiate( + let ret = api::instantiate( code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. 0u64, // How much proof_size weight to devote for the execution. 0 = all. @@ -49,8 +49,10 @@ pub extern "C" fn call() { Some(&mut address), None, Some(&salt), - ) - .unwrap(); + ); + if let Err(code) = ret { + api::return_value(uapi::ReturnFlags::REVERT, &(code as u32).to_le_bytes()); + }; // Return the deployed contract address. api::return_value(uapi::ReturnFlags::empty(), &address); diff --git a/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs b/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs index d2efb26e5ceb..cf12fed27563 100644 --- a/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs +++ b/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs @@ -22,7 +22,7 @@ use common::input; use uapi::{HostFn, HostFnImpl as api, StorageFlags}; -static BUFFER: [u8; 512] = [0u8; 512]; +static BUFFER: [u8; 448] = [0u8; 448]; #[no_mangle] #[polkavm_derive::polkavm_export] diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call.rs b/substrate/frame/revive/fixtures/contracts/delegate_call.rs index 9fd155408af3..3cf74acf1321 100644 --- a/substrate/frame/revive/fixtures/contracts/delegate_call.rs +++ b/substrate/frame/revive/fixtures/contracts/delegate_call.rs @@ -28,7 +28,11 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - input!(code_hash: &[u8; 32],); + input!( + address: &[u8; 20], + ref_time: u64, + proof_size: u64, + ); let mut key = [0u8; 32]; key[0] = 1u8; @@ -42,7 +46,7 @@ pub extern "C" fn call() { assert!(value[0] == 2u8); let input = [0u8; 0]; - api::delegate_call(uapi::CallFlags::empty(), code_hash, &input, None).unwrap(); + api::delegate_call(uapi::CallFlags::empty(), address, ref_time, proof_size, None, &input, None).unwrap(); api::get_storage(StorageFlags::empty(), &key, value).unwrap(); assert!(value[0] == 1u8); diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs new file mode 100644 index 000000000000..0f157f5a18ac --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs @@ -0,0 +1,50 @@ +// 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. + +#![no_std] +#![no_main] + +use common::{input, u256_bytes}; +use uapi::{HostFn, HostFnImpl as api, StorageFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + input!( + address: &[u8; 20], + deposit_limit: u64, + ); + + let input = [0u8; 0]; + let ret = api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, Some(&u256_bytes(deposit_limit)), &input, None); + + if let Err(code) = ret { + api::return_value(uapi::ReturnFlags::REVERT, &(code as u32).to_le_bytes()); + }; + + let mut key = [0u8; 32]; + key[0] = 1u8; + + let mut value = [0u8; 32]; + + api::get_storage(StorageFlags::empty(), &key, &mut &mut value[..]).unwrap(); + assert!(value[0] == 1u8); +} diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs b/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs index 20f8ec3364ee..a8501dad4692 100644 --- a/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs +++ b/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs @@ -28,9 +28,9 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - input!(code_hash: &[u8; 32],); + input!(address: &[u8; 20],); - // Delegate call into passed code hash. + // Delegate call into passed address. let input = [0u8; 0]; - api::delegate_call(uapi::CallFlags::empty(), code_hash, &input, None).unwrap(); + api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, None, &input, None).unwrap(); } diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 0d644a4238c4..6e3e708a6b3d 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -36,6 +36,15 @@ pub extern "C" fn call() { // Try to self-destruct by sending more balance to the 0 address. // The call will fail because a contract transfer has a keep alive requirement. - let res = api::transfer(&[0u8; 20], &u256_bytes(balance)); + let res = api::call( + uapi::CallFlags::empty(), + &[0u8; 20], + 0, + 0, + None, + &u256_bytes(balance), + &[], + None, + ); assert!(matches!(res, Err(uapi::ReturnErrorCode::TransferFailed))); } diff --git a/substrate/frame/revive/fixtures/contracts/extcodesize.rs b/substrate/frame/revive/fixtures/contracts/extcodesize.rs index 0a1171be30e9..3f51b69b46db 100644 --- a/substrate/frame/revive/fixtures/contracts/extcodesize.rs +++ b/substrate/frame/revive/fixtures/contracts/extcodesize.rs @@ -18,7 +18,7 @@ #![no_std] #![no_main] -use common::{input, u64_output}; +use common::input; use uapi::{HostFn, HostFnImpl as api}; #[no_mangle] @@ -30,7 +30,7 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { input!(address: &[u8; 20], expected: u64,); - let received = u64_output!(api::code_size, address); + let received = api::code_size(address); assert_eq!(expected, received); } diff --git a/substrate/frame/revive/fixtures/contracts/gas_limit.rs b/substrate/frame/revive/fixtures/contracts/gas_limit.rs new file mode 100644 index 000000000000..9ce82227b64d --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/gas_limit.rs @@ -0,0 +1,34 @@ +// 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. + +//! Returns the block ref_time limit back to the caller. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + api::return_value(ReturnFlags::empty(), &api::gas_limit().to_le_bytes()); +} diff --git a/substrate/frame/revive/fixtures/contracts/gas_price.rs b/substrate/frame/revive/fixtures/contracts/gas_price.rs new file mode 100644 index 000000000000..c1c8109fafbe --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/gas_price.rs @@ -0,0 +1,34 @@ +// 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. + +//! Returns the gas price back to the caller. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + api::return_value(ReturnFlags::empty(), &api::gas_price().to_le_bytes()); +} diff --git a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs index 54c7c7f3d5e2..3d7702c6537a 100644 --- a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs +++ b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs @@ -30,6 +30,7 @@ const ALICE_FALLBACK: [u8; 20] = [1u8; 20]; fn load_input(delegate_call: bool) { input!( action: u32, + address: &[u8; 20], code_hash: &[u8; 32], ); @@ -51,7 +52,7 @@ fn load_input(delegate_call: bool) { } if delegate_call { - api::delegate_call(uapi::CallFlags::empty(), code_hash, &[], None).unwrap(); + api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, None, &[], None).unwrap(); } } diff --git a/substrate/frame/revive/fixtures/contracts/ref_time_left.rs b/substrate/frame/revive/fixtures/contracts/ref_time_left.rs new file mode 100644 index 000000000000..aa892a8ba440 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/ref_time_left.rs @@ -0,0 +1,34 @@ +// 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. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() { + assert!(api::ref_time_left() > api::ref_time_left()); +} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + api::return_value(ReturnFlags::empty(), &api::ref_time_left().to_le_bytes()); +} diff --git a/substrate/frame/revive/fixtures/contracts/return_data_api.rs b/substrate/frame/revive/fixtures/contracts/return_data_api.rs index 846396b0944d..1d483373cffd 100644 --- a/substrate/frame/revive/fixtures/contracts/return_data_api.rs +++ b/substrate/frame/revive/fixtures/contracts/return_data_api.rs @@ -35,11 +35,11 @@ static INPUT_DATA: [u8; INPUT_BUF_SIZE] = [0xFF; INPUT_BUF_SIZE]; const OUTPUT_BUF_SIZE: usize = INPUT_BUF_SIZE - 4; static OUTPUT_DATA: [u8; OUTPUT_BUF_SIZE] = [0xEE; OUTPUT_BUF_SIZE]; +/// Assert correct return data after calls and finally reset the return data. 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_balance_transfer_does_reset(); } /// Assert that what we get from [api::return_data_copy] matches `whole_return_data`, @@ -73,34 +73,16 @@ fn recursion_guard() -> [u8; 20] { 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_eq!(api::return_data_size(), 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); +/// Assert the return data to be reset after a balance transfer. +fn assert_balance_transfer_does_reset() { + api::call(uapi::CallFlags::empty(), &[0u8; 20], 0, 0, None, &u256_bytes(128), &[], None) + .unwrap(); + assert_return_data_size_of(0); } #[no_mangle] diff --git a/substrate/frame/revive/fixtures/contracts/rpc_demo.rs b/substrate/frame/revive/fixtures/contracts/rpc_demo.rs index 0d75c6eb8df6..4c61f2ea82ec 100644 --- a/substrate/frame/revive/fixtures/contracts/rpc_demo.rs +++ b/substrate/frame/revive/fixtures/contracts/rpc_demo.rs @@ -18,7 +18,7 @@ #![no_std] #![no_main] -use common::input; +use common::{input, u64_output}; use uapi::{HostFn, HostFnImpl as api}; #[no_mangle] @@ -31,6 +31,12 @@ pub extern "C" fn deploy() { #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { + // Not payable + let value = u64_output!(api::value_transferred,); + if value > 0 { + panic!(); + } + input!(128, data: [u8],); api::deposit_event(&[], data); } diff --git a/substrate/frame/revive/fixtures/contracts/set_code_hash.rs b/substrate/frame/revive/fixtures/contracts/set_code_hash.rs index 75995d7bb8a2..7292c6fd10ae 100644 --- a/substrate/frame/revive/fixtures/contracts/set_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/set_code_hash.rs @@ -29,7 +29,7 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { input!(addr: &[u8; 32],); - api::set_code_hash(addr).unwrap(); + api::set_code_hash(addr); // we return 1 after setting new code_hash // next `call` will NOT return this value, because contract code has been changed diff --git a/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs b/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs index bfeca9b8b4a4..09d45d0a8411 100644 --- a/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs +++ b/substrate/frame/revive/fixtures/contracts/transfer_return_code.rs @@ -28,7 +28,16 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - let ret_code = match api::transfer(&[0u8; 20], &u256_bytes(100u64)) { + let ret_code = match api::call( + uapi::CallFlags::empty(), + &[0u8; 20], + 0, + 0, + None, + &u256_bytes(100u64), + &[], + None, + ) { Ok(_) => 0u32, Err(code) => code as u32, }; diff --git a/substrate/frame/revive/fixtures/contracts/unknown_syscall.rs b/substrate/frame/revive/fixtures/contracts/unknown_syscall.rs new file mode 100644 index 000000000000..93ea86754f55 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/unknown_syscall.rs @@ -0,0 +1,44 @@ +// 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. +#![no_std] +#![no_main] + +extern crate common; + +#[polkavm_derive::polkavm_import] +extern "C" { + pub fn __this_syscall_does_not_exist__(); +} + +// Export that is never called. We can put code here that should be in the binary +// but is never supposed to be run. +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call_never() { + // make sure it is not optimized away + unsafe { + __this_syscall_does_not_exist__(); + } +} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() {} diff --git a/substrate/frame/revive/fixtures/contracts/unstable_interface.rs b/substrate/frame/revive/fixtures/contracts/unstable_interface.rs new file mode 100644 index 000000000000..d73ae041dc06 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/unstable_interface.rs @@ -0,0 +1,44 @@ +// 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. +#![no_std] +#![no_main] + +extern crate common; + +#[polkavm_derive::polkavm_import] +extern "C" { + pub fn set_code_hash(); +} + +// Export that is never called. We can put code here that should be in the binary +// but is never supposed to be run. +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call_never() { + // make sure it is not optimized away + unsafe { + set_code_hash(); + } +} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() {} diff --git a/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json b/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json deleted file mode 100644 index bbd54cdefbac..000000000000 --- a/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "arch": "riscv32", - "cpu": "generic-rv32", - "crt-objects-fallback": "false", - "data-layout": "e-m:e-p:32:32-i64:64-n32-S32", - "eh-frame-header": false, - "emit-debug-gdb-scripts": false, - "features": "+e,+m,+a,+c,+lui-addi-fusion,+fast-unaligned-access,+xtheadcondmov", - "linker": "rust-lld", - "linker-flavor": "ld.lld", - "llvm-abiname": "ilp32e", - "llvm-target": "riscv32", - "max-atomic-width": 32, - "panic-strategy": "abort", - "relocation-model": "pie", - "target-pointer-width": "32", - "singlethread": true, - "pre-link-args": { - "ld": [ - "--emit-relocs", - "--unique", - "--relocatable" - ] - }, - "env": "polkavm" -} diff --git a/substrate/frame/revive/fixtures/src/lib.rs b/substrate/frame/revive/fixtures/src/lib.rs index cc84daec9b59..38171edf1152 100644 --- a/substrate/frame/revive/fixtures/src/lib.rs +++ b/substrate/frame/revive/fixtures/src/lib.rs @@ -19,12 +19,14 @@ extern crate alloc; +// generated file that tells us where to find the fixtures +include!(concat!(env!("OUT_DIR"), "/fixture_location.rs")); + /// Load a given wasm module and returns a wasm binary contents along with it's hash. #[cfg(feature = "std")] pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec, sp_core::H256)> { - let out_dir: std::path::PathBuf = env!("OUT_DIR").into(); + let out_dir: std::path::PathBuf = FIXTURE_DIR.into(); let fixture_path = out_dir.join(format!("{fixture_name}.polkavm")); - log::debug!("Loading fixture from {fixture_path:?}"); let binary = std::fs::read(fixture_path)?; let code_hash = sp_io::hashing::keccak_256(&binary); Ok((binary, sp_core::H256(code_hash))) @@ -36,12 +38,6 @@ pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec, sp_core::H /// available in no-std environments (runtime benchmarks). pub mod bench { use alloc::vec::Vec; - - macro_rules! fixture { - ($name: literal) => { - include_bytes!(concat!(env!("OUT_DIR"), "/", $name, ".polkavm")) - }; - } pub const DUMMY: &[u8] = fixture!("dummy"); pub const NOOP: &[u8] = fixture!("noop"); pub const INSTR: &[u8] = fixture!("instr_benchmark"); @@ -61,7 +57,7 @@ pub mod bench { mod test { #[test] fn out_dir_should_have_compiled_mocks() { - let out_dir: std::path::PathBuf = env!("OUT_DIR").into(); + let out_dir: std::path::PathBuf = crate::FIXTURE_DIR.into(); assert!(out_dir.join("dummy.polkavm").exists()); } } diff --git a/substrate/frame/revive/mock-network/Cargo.toml b/substrate/frame/revive/mock-network/Cargo.toml index c5b18b3fa290..1ebeb2c95db7 100644 --- a/substrate/frame/revive/mock-network/Cargo.toml +++ b/substrate/frame/revive/mock-network/Cargo.toml @@ -18,22 +18,17 @@ frame-support = { workspace = true } frame-system = { workspace = true } pallet-assets = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } pallet-revive = { workspace = true, default-features = true } pallet-revive-uapi = { workspace = true } -pallet-revive-proc-macro = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } -pallet-proxy = { workspace = true, default-features = true } pallet-timestamp = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } pallet-xcm = { workspace = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } scale-info = { features = ["derive"], workspace = true } -sp-api = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } -sp-keystore = { workspace = true, default-features = true } sp-runtime = { workspace = true } sp-tracing = { workspace = true, default-features = true } xcm = { workspace = true } @@ -43,8 +38,8 @@ xcm-simulator = { workspace = true, default-features = true } [dev-dependencies] assert_matches = { workspace = true } -pretty_assertions = { workspace = true } pallet-revive-fixtures = { workspace = true } +pretty_assertions = { workspace = true } [features] default = ["std"] @@ -53,17 +48,13 @@ std = [ "frame-support/std", "frame-system/std", "pallet-balances/std", - "pallet-proxy/std", "pallet-revive-fixtures/std", "pallet-revive/std", "pallet-timestamp/std", - "pallet-utility/std", "pallet-xcm/std", "scale-info/std", - "sp-api/std", "sp-core/std", "sp-io/std", - "sp-keystore/std", "sp-runtime/std", "xcm-executor/std", "xcm/std", @@ -74,10 +65,8 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", - "pallet-proxy/runtime-benchmarks", "pallet-revive/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", @@ -85,6 +74,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", @@ -92,10 +82,8 @@ try-runtime = [ "pallet-assets/try-runtime", "pallet-balances/try-runtime", "pallet-message-queue/try-runtime", - "pallet-proxy/try-runtime", "pallet-revive/try-runtime", "pallet-timestamp/try-runtime", - "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", diff --git a/substrate/frame/revive/mock-network/src/tests.rs b/substrate/frame/revive/mock-network/src/tests.rs index bd05726a1a45..34f797c2b530 100644 --- a/substrate/frame/revive/mock-network/src/tests.rs +++ b/substrate/frame/revive/mock-network/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::traits::{fungibles::Mutate, Currency}; use frame_system::RawOrigin; use pallet_revive::{ test_utils::{self, builder::*}, - Code, + Code, DepositLimit, }; use pallet_revive_fixtures::compile_module; use pallet_revive_uapi::ReturnErrorCode; @@ -52,7 +52,7 @@ fn instantiate_test_contract(name: &str) -> Contract { RawOrigin::Signed(ALICE).into(), Code::Upload(wasm), ) - .storage_deposit_limit(1_000_000_000_000) + .storage_deposit_limit(DepositLimit::Balance(1_000_000_000_000)) .build_and_unwrap_contract() }); diff --git a/substrate/frame/revive/proc-macro/src/lib.rs b/substrate/frame/revive/proc-macro/src/lib.rs index 012b4bfab9a9..b6ea1a06d94e 100644 --- a/substrate/frame/revive/proc-macro/src/lib.rs +++ b/substrate/frame/revive/proc-macro/src/lib.rs @@ -25,6 +25,17 @@ use proc_macro2::{Literal, Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens}; use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, FnArg, Ident}; +#[proc_macro_attribute] +pub fn unstable_hostfn(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(item as syn::Item); + let expanded = quote! { + #[cfg(feature = "unstable-hostfn")] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable-hostfn")))] + #input + }; + expanded.into() +} + /// Defines a host functions set that can be imported by contract wasm code. /// /// **NB**: Be advised that all functions defined by this macro @@ -79,6 +90,7 @@ use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, F /// - `Result<(), TrapReason>`, /// - `Result`, /// - `Result`. +/// - `Result`. /// /// The macro expands to `pub struct Env` declaration, with the following traits implementations: /// - `pallet_revive::wasm::Environment> where E: Ext` @@ -118,7 +130,7 @@ struct EnvDef { /// Parsed host function definition. struct HostFn { item: syn::ItemFn, - api_version: Option, + is_stable: bool, name: String, returns: HostFnReturn, cfg: Option, @@ -127,6 +139,7 @@ struct HostFn { enum HostFnReturn { Unit, U32, + U64, ReturnCode, } @@ -134,8 +147,7 @@ impl HostFnReturn { fn map_output(&self) -> TokenStream2 { match self { Self::Unit => quote! { |_| None }, - Self::U32 => quote! { |ret_val| Some(ret_val) }, - Self::ReturnCode => quote! { |ret_code| Some(ret_code.into()) }, + _ => quote! { |ret_val| Some(ret_val.into()) }, } } @@ -143,6 +155,7 @@ impl HostFnReturn { match self { Self::Unit => syn::ReturnType::Default, Self::U32 => parse_quote! { -> u32 }, + Self::U64 => parse_quote! { -> u64 }, Self::ReturnCode => parse_quote! { -> ReturnErrorCode }, } } @@ -181,22 +194,21 @@ impl HostFn { }; // process attributes - let msg = "Only #[api_version()], #[cfg] and #[mutating] attributes are allowed."; + let msg = "Only #[stable], #[cfg] and #[mutating] attributes are allowed."; let span = item.span(); let mut attrs = item.attrs.clone(); attrs.retain(|a| !a.path().is_ident("doc")); - let mut api_version = None; + let mut is_stable = false; let mut mutating = false; let mut cfg = None; while let Some(attr) = attrs.pop() { let ident = attr.path().get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { - "api_version" => { - if api_version.is_some() { - return Err(err(span, "#[api_version] can only be specified once")) + "stable" => { + if is_stable { + return Err(err(span, "#[stable] can only be specified once")) } - api_version = - Some(attr.parse_args::().and_then(|lit| lit.base10_parse())?); + is_stable = true; }, "mutating" => { if mutating { @@ -243,7 +255,8 @@ impl HostFn { let msg = r#"Should return one of the following: - Result<(), TrapReason>, - Result, - - Result"#; + - Result, + - Result"#; let ret_ty = match item.clone().sig.output { syn::ReturnType::Type(_, ty) => Ok(ty.clone()), _ => Err(err(span, &msg)), @@ -305,11 +318,12 @@ impl HostFn { let returns = match ok_ty_str.as_str() { "()" => Ok(HostFnReturn::Unit), "u32" => Ok(HostFnReturn::U32), + "u64" => Ok(HostFnReturn::U64), "ReturnErrorCode" => Ok(HostFnReturn::ReturnCode), _ => Err(err(arg1.span(), &msg)), }?; - Ok(Self { item, api_version, name, returns, cfg }) + Ok(Self { item, is_stable, name, returns, cfg }) }, _ => Err(err(span, &msg)), } @@ -339,48 +353,61 @@ where P: Iterator> + Clone, I: Iterator> + Clone, { - const ALLOWED_REGISTERS: u32 = 6; - let mut registers_used = 0; - let mut bindings = vec![]; - for (idx, (name, ty)) in param_names.clone().zip(param_types.clone()).enumerate() { + const ALLOWED_REGISTERS: usize = 6; + + // all of them take one register but we truncate them before passing into the function + // it is important to not allow any type which has illegal bit patterns like 'bool' + if !param_types.clone().all(|ty| { let syn::Type::Path(path) = &**ty else { panic!("Type needs to be path"); }; 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"); - }; - registers_used += size; - if registers_used > ALLOWED_REGISTERS { - return quote! { - let (#( #param_names, )*): (#( #param_types, )*) = memory.read_as(__a0__)?; - } - } - let this_reg = quote::format_ident!("__a{}__", idx); - let next_reg = quote::format_ident!("__a{}__", idx + 1); - let binding = if size == 1 { + matches!(ident.to_string().as_ref(), "u8" | "u16" | "u32" | "u64") + }) { + panic!("Only primitive unsigned integers are allowed as arguments to syscalls"); + } + + // too many arguments: pass as pointer to a struct in memory + if param_names.clone().count() > ALLOWED_REGISTERS { + let fields = param_names.clone().zip(param_types.clone()).map(|(name, ty)| { quote! { - let #name = #this_reg as #ty; + #name: #ty, } - } else { - quote! { - let #name = (#this_reg as #ty) | ((#next_reg as #ty) << 32); + }); + return quote! { + #[derive(Default)] + #[repr(C)] + struct Args { + #(#fields)* } - }; - bindings.push(binding); + let Args { #(#param_names,)* } = { + let len = ::core::mem::size_of::(); + let mut args = Args::default(); + let ptr = &mut args as *mut Args as *mut u8; + // Safety + // 1. The struct is initialized at all times. + // 2. We only allow primitive integers (no bools) as arguments so every bit pattern is safe. + // 3. The reference doesn't outlive the args field. + // 4. There is only the single reference to the args field. + // 5. The length of the generated slice is the same as the struct. + let reference = unsafe { + ::core::slice::from_raw_parts_mut(ptr, len) + }; + memory.read_into_buf(__a0__ as _, reference)?; + args + }; + } } + + // otherwise: one argument per register + let bindings = param_names.zip(param_types).enumerate().map(|(idx, (name, ty))| { + let reg = quote::format_ident!("__a{}__", idx); + quote! { + let #name = #reg as #ty; + } + }); quote! { #( #bindings )* } @@ -394,20 +421,24 @@ fn expand_env(def: &EnvDef) -> TokenStream2 { let impls = expand_functions(def); let bench_impls = expand_bench_functions(def); let docs = expand_func_doc(def); - let highest_api_version = - def.host_funcs.iter().filter_map(|f| f.api_version).max().unwrap_or_default(); + let stable_syscalls = expand_func_list(def, false); + let all_syscalls = expand_func_list(def, true); quote! { - #[cfg(test)] - pub const HIGHEST_API_VERSION: u16 = #highest_api_version; + pub fn list_syscalls(include_unstable: bool) -> &'static [&'static [u8]] { + if include_unstable { + #all_syscalls + } else { + #stable_syscalls + } + } impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { fn handle_ecall( &mut self, memory: &mut M, __syscall_symbol__: &[u8], - __available_api_version__: ApiVersion, - ) -> Result, TrapReason> + ) -> Result, TrapReason> { #impls } @@ -457,10 +488,6 @@ fn expand_functions(def: &EnvDef) -> TokenStream2 { let body = &f.item.block; let map_output = f.returns.map_output(); let output = &f.item.sig.output; - let api_version = match f.api_version { - Some(version) => quote! { Some(#version) }, - None => quote! { None }, - }; // wrapped host function body call with host function traces // see https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/contracts#host-function-tracing @@ -496,7 +523,7 @@ fn expand_functions(def: &EnvDef) -> TokenStream2 { quote! { #cfg - #syscall_symbol if __is_available__(#api_version) => { + #syscall_symbol => { // closure is needed so that "?" can infere the correct type (|| #output { #arg_decoder @@ -517,18 +544,6 @@ fn expand_functions(def: &EnvDef) -> TokenStream2 { // This is the overhead to call an empty syscall that always needs to be charged. self.charge_gas(crate::wasm::RuntimeCosts::HostFn).map_err(TrapReason::from)?; - // Not all APIs are available depending on configuration or when the code was deployed. - // This closure will be used by syscall specific code to perform this check. - let __is_available__ = |syscall_version: Option| { - match __available_api_version__ { - ApiVersion::UnsafeNewest => true, - ApiVersion::Versioned(max_available_version) => - syscall_version - .map(|required_version| max_available_version >= required_version) - .unwrap_or(false), - } - }; - // They will be mapped to variable names by the syscall specific code. let (__a0__, __a1__, __a2__, __a3__, __a4__, __a5__) = memory.read_input_regs(); @@ -590,10 +605,8 @@ fn expand_func_doc(def: &EnvDef) -> TokenStream2 { }); quote! { #( #docs )* } }; - let availability = if let Some(version) = func.api_version { - let info = format!( - "\n# Required API version\nThis API was added in version **{version}**.", - ); + let availability = if func.is_stable { + let info = "\n# Stable API\nThis API is stable and will never change."; quote! { #[doc = #info] } } else { let info = @@ -615,3 +628,20 @@ fn expand_func_doc(def: &EnvDef) -> TokenStream2 { #( #docs )* } } + +fn expand_func_list(def: &EnvDef, include_unstable: bool) -> TokenStream2 { + let docs = def.host_funcs.iter().filter(|f| include_unstable || f.is_stable).map(|f| { + let name = Literal::byte_string(f.name.as_bytes()); + quote! { + #name.as_slice() + } + }); + let len = docs.clone().count(); + + quote! { + { + static FUNCS: [&[u8]; #len] = [#(#docs),*]; + FUNCS.as_slice() + } + } +} diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index 56db91f920fa..cfaaa102fc3d 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -38,43 +38,37 @@ path = "examples/rust/remark-extrinsic.rs" required-features = ["example"] [dependencies] -clap = { workspace = true, features = ["derive"] } anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codec = { workspace = true, features = ["derive"] } +ethabi = { version = "18.0.0" } futures = { workspace = true, features = ["thread-pool"] } +hex = { workspace = true } jsonrpsee = { workspace = true, features = ["full"] } -serde_json = { workspace = true } -thiserror = { workspace = true } -sp-crypto-hashing = { workspace = true } -subxt = { workspace = true, default-features = true, features = [ - "unstable-reconnecting-rpc-client", -] } -tokio = { workspace = true, features = ["full"] } -codec = { workspace = true, features = ["derive"] } -log.workspace = true +log = { workspace = true } pallet-revive = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-weights = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sc-rpc = { workspace = true, default-features = true } -sc-cli = { workspace = true, default-features = true } -sc-service = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } - rlp = { workspace = true, optional = true } +sc-cli = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true } +sp-weights = { workspace = true, default-features = true } +subxt = { workspace = true, default-features = true, features = ["reconnecting-rpc-client"] } subxt-signer = { workspace = true, optional = true, features = [ "unstable-eth", ] } -hex = { workspace = true, optional = true } -hex-literal = { workspace = true, optional = true } -scale-info = { workspace = true } -secp256k1 = { workspace = true, optional = true, features = ["recovery"] } -env_logger = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["full"] } [features] -example = ["hex", "hex-literal", "rlp", "secp256k1", "subxt-signer"] +example = ["rlp", "subxt-signer"] [dev-dependencies] -hex-literal = { workspace = true } -pallet-revive-fixtures = { workspace = true } +env_logger = { workspace = true } +pallet-revive-fixtures = { workspace = true, default-features = true } +static_init = { workspace = true } substrate-cli-test-utils = { workspace = true } subxt-signer = { workspace = true, features = ["unstable-eth"] } diff --git a/substrate/frame/revive/rpc/examples/README.md b/substrate/frame/revive/rpc/examples/README.md index bf30426648ba..b9a2756b381d 100644 --- a/substrate/frame/revive/rpc/examples/README.md +++ b/substrate/frame/revive/rpc/examples/README.md @@ -34,7 +34,7 @@ zombienet spawn --provider native westend_local_network.toml This command starts the Ethereum JSON-RPC server, which runs on `localhost:8545` by default: ```bash -RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc --features dev +RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc -- --dev ``` ## Rust examples @@ -65,34 +65,6 @@ bun src/script.ts ### Configure MetaMask -You can use the following instructions to setup [MetaMask] with the local chain. +See the doc [here](https://contracts.polkadot.io/work-with-a-local-node#metemask-configuration) for more +information on how to configure MetaMask. -> **Note**: When you interact with MetaMask and restart the chain, you need to clear the activity tab (Settings > -Advanced > Clear activity tab data), and in some cases lock/unlock MetaMask to reset the nonce. -See [this guide][reset-account] for more info on how to reset the account activity. - -#### Add a new network - -To interact with the local chain, add a new network in [MetaMask]. -See [this guide][add-network] for more info on how to add a custom network. - -Make sure the node and the RPC server are started, and use the following settings to configure the network -(MetaMask > Networks > Add a network manually): - -- Network name: KitchenSink -- RPC URL: -- Chain ID: 420420420 -- Currency Symbol: `DEV` - -#### Import Dev account - -You will need to import the following account, endowed with some balance at genesis, to interact with the chain. -See [this guide][import-account] for more info on how to import an account. - -- Account: `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac` -- Private Key: `5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133` - -[MetaMask]: https://metamask.io -[add-network]: https://support.metamask.io/networks-and-sidechains/managing-networks/how-to-add-a-custom-network-rpc/#adding-a-network-manually -[import-account]: https://support.metamask.io/managing-my-wallet/accounts-and-addresses/how-to-import-an-account/ -[reset-account]: https://support.metamask.io/managing-my-wallet/resetting-deleting-and-restoring/how-to-clear-your-account-activity-reset-account diff --git a/substrate/frame/revive/rpc/examples/bun.lockb b/substrate/frame/revive/rpc/examples/bun.lockb new file mode 100755 index 000000000000..3a7a0df5cea4 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/bun.lockb differ diff --git a/substrate/frame/revive/rpc/examples/js/.prettierrc.json b/substrate/frame/revive/rpc/examples/js/.prettierrc.json new file mode 100644 index 000000000000..e74ed9ff3578 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "semi": false, + "singleQuote": true +} diff --git a/substrate/frame/revive/rpc/examples/js/abi/ErrorTester.json b/substrate/frame/revive/rpc/examples/js/abi/ErrorTester.json new file mode 100644 index 000000000000..2d8dccc771e8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/ErrorTester.json @@ -0,0 +1,106 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "message", + "type": "string" + } + ], + "name": "CustomError", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "newState", + "type": "bool" + } + ], + "name": "setState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "state", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "triggerAssertError", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "triggerCustomError", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "triggerDivisionByZero", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "triggerOutOfBoundsError", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "triggerRequireError", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "triggerRevertError", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "valueMatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/abi/ErrorTester.ts b/substrate/frame/revive/rpc/examples/js/abi/ErrorTester.ts new file mode 100644 index 000000000000..f3776e498fd5 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/ErrorTester.ts @@ -0,0 +1,106 @@ +export const ErrorTesterAbi = [ + { + inputs: [ + { + internalType: "string", + name: "message", + type: "string", + }, + ], + name: "CustomError", + type: "error", + }, + { + inputs: [ + { + internalType: "bool", + name: "newState", + type: "bool", + }, + ], + name: "setState", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "state", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "triggerAssertError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerCustomError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerDivisionByZero", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerOutOfBoundsError", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerRequireError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerRevertError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "valueMatch", + outputs: [], + stateMutability: "payable", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/abi/EventExample.json b/substrate/frame/revive/rpc/examples/js/abi/EventExample.json new file mode 100644 index 000000000000..a64c920c4068 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/EventExample.json @@ -0,0 +1,34 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "message", + "type": "string" + } + ], + "name": "ExampleEvent", + "type": "event" + }, + { + "inputs": [], + "name": "triggerEvent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/abi/EventExample.ts b/substrate/frame/revive/rpc/examples/js/abi/EventExample.ts new file mode 100644 index 000000000000..efb0d741b48f --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/EventExample.ts @@ -0,0 +1,34 @@ +export const EventExampleAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "sender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "message", + type: "string", + }, + ], + name: "ExampleEvent", + type: "event", + }, + { + inputs: [], + name: "triggerEvent", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/abi/Flipper.json b/substrate/frame/revive/rpc/examples/js/abi/Flipper.json new file mode 100644 index 000000000000..4c1b163d2943 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/Flipper.json @@ -0,0 +1,35 @@ +[ + { + "inputs": [], + "name": "flip", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getValue", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "value", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/abi/Flipper.ts b/substrate/frame/revive/rpc/examples/js/abi/Flipper.ts new file mode 100644 index 000000000000..d7428beb6aa9 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/Flipper.ts @@ -0,0 +1,35 @@ +export const FlipperAbi = [ + { + inputs: [], + name: "flip", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getValue", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "value", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/abi/FlipperCaller.json b/substrate/frame/revive/rpc/examples/js/abi/FlipperCaller.json new file mode 100644 index 000000000000..c4ed4228f47d --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/FlipperCaller.json @@ -0,0 +1,46 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_flipperAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "callFlip", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "callGetValue", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "flipperAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/abi/FlipperCaller.ts b/substrate/frame/revive/rpc/examples/js/abi/FlipperCaller.ts new file mode 100644 index 000000000000..2d695886d960 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/FlipperCaller.ts @@ -0,0 +1,46 @@ +export const FlipperCallerAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_flipperAddress", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "callFlip", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "callGetValue", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "flipperAddress", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/abi/PiggyBank.json b/substrate/frame/revive/rpc/examples/js/abi/PiggyBank.json new file mode 100644 index 000000000000..e6655889e21a --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/PiggyBank.json @@ -0,0 +1,65 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "withdrawAmount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "remainingBal", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/js/abi/RevertExample.ts b/substrate/frame/revive/rpc/examples/js/abi/RevertExample.ts new file mode 100644 index 000000000000..ab483b1811c4 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/RevertExample.ts @@ -0,0 +1,14 @@ +export const RevertExampleAbi = [ + { + inputs: [], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "doRevert", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/abi/errorTester.ts b/substrate/frame/revive/rpc/examples/js/abi/errorTester.ts new file mode 100644 index 000000000000..f3776e498fd5 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/errorTester.ts @@ -0,0 +1,106 @@ +export const ErrorTesterAbi = [ + { + inputs: [ + { + internalType: "string", + name: "message", + type: "string", + }, + ], + name: "CustomError", + type: "error", + }, + { + inputs: [ + { + internalType: "bool", + name: "newState", + type: "bool", + }, + ], + name: "setState", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "state", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "triggerAssertError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerCustomError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerDivisionByZero", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerOutOfBoundsError", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerRequireError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "triggerRevertError", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "valueMatch", + outputs: [], + stateMutability: "payable", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/abi/piggyBank.ts b/substrate/frame/revive/rpc/examples/js/abi/piggyBank.ts new file mode 100644 index 000000000000..a6b8c1b0be56 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/piggyBank.ts @@ -0,0 +1,65 @@ +export const PiggyBankAbi = [ + { + inputs: [], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "deposit", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "getDeposit", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "withdrawAmount", + type: "uint256", + }, + ], + name: "withdraw", + outputs: [ + { + internalType: "uint256", + name: "remainingBal", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/substrate/frame/revive/rpc/examples/js/bun.lockb b/substrate/frame/revive/rpc/examples/js/bun.lockb index 8bf47d7eb8b8..46994bb14754 100755 Binary files a/substrate/frame/revive/rpc/examples/js/bun.lockb and b/substrate/frame/revive/rpc/examples/js/bun.lockb differ diff --git a/substrate/frame/revive/rpc/examples/js/contracts/.solhint.json b/substrate/frame/revive/rpc/examples/js/contracts/.solhint.json new file mode 100644 index 000000000000..ce2220e0b756 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/.solhint.json @@ -0,0 +1,3 @@ +{ + "extends": "solhint:recommended" +} diff --git a/substrate/frame/revive/rpc/examples/js/contracts/ErrorTester.sol b/substrate/frame/revive/rpc/examples/js/contracts/ErrorTester.sol new file mode 100644 index 000000000000..f1fdd219624a --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/ErrorTester.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract ErrorTester { + bool public state; + + // Payable function that can be used to test insufficient funds errors + function valueMatch(uint256 value) public payable { + require(msg.value == value , "msg.value does not match value"); + } + + function setState(bool newState) public { + state = newState; + } + + // Trigger a require statement failure with a custom error message + function triggerRequireError() public pure { + require(false, "This is a require error"); + } + + // Trigger an assert statement failure + function triggerAssertError() public pure { + assert(false); + } + + // Trigger a revert statement with a custom error message + function triggerRevertError() public pure { + revert("This is a revert error"); + } + + // Trigger a division by zero error + function triggerDivisionByZero() public pure returns (uint256) { + uint256 a = 1; + uint256 b = 0; + return a / b; + } + + // Trigger an out-of-bounds array access + function triggerOutOfBoundsError() public pure returns (uint256) { + uint256[] memory arr = new uint256[](1); + return arr[2]; + } + + // Trigger a custom error + error CustomError(string message); + + function triggerCustomError() public pure { + revert CustomError("This is a custom error"); + } +} + diff --git a/substrate/frame/revive/rpc/examples/js/contracts/Event.sol b/substrate/frame/revive/rpc/examples/js/contracts/Event.sol new file mode 100644 index 000000000000..1e4ce7cf8765 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/Event.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract EventExample { + event ExampleEvent(address indexed sender, uint256 value, string message); + + function triggerEvent() public { + uint256 value = 12345; + string memory message = "Hello world"; + emit ExampleEvent(msg.sender, value, message); + } +} + diff --git a/substrate/frame/revive/rpc/examples/js/contracts/Flipper.sol b/substrate/frame/revive/rpc/examples/js/contracts/Flipper.sol new file mode 100644 index 000000000000..51aaafcae428 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/Flipper.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Flipper - Stores and toggles a boolean value +contract Flipper { + bool public value; + + function flip() external { + value = !value; + } + + function getValue() external view returns (bool) { + return value; + } +} + +// FlipperCaller - Interacts with the Flipper contract +contract FlipperCaller { + // Address of the Flipper contract + address public flipperAddress; + + // Constructor to initialize Flipper's address + constructor(address _flipperAddress) { + flipperAddress = _flipperAddress; + } + + function callFlip() external { + Flipper(flipperAddress).flip(); + } + + function callGetValue() external view returns (bool) { + return Flipper(flipperAddress).getValue(); + } +} + diff --git a/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol b/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol new file mode 100644 index 000000000000..0c8a4d26f4dc --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract PiggyBank { + + uint256 private balance; + address public owner; + + constructor() { + owner = msg.sender; + balance = 0; + } + + function deposit() public payable returns (uint256) { + balance += msg.value; + return balance; + } + + function getDeposit() public view returns (uint256) { + return balance; + } + + function withdraw(uint256 withdrawAmount) public returns (uint256 remainingBal) { + require(msg.sender == owner); + balance -= withdrawAmount; + (bool success, ) = payable(msg.sender).call{value: withdrawAmount}(""); + require(success, "Transfer failed"); + + return balance; + } +} + diff --git a/substrate/frame/revive/rpc/examples/js/evm/.gitkeep b/substrate/frame/revive/rpc/examples/js/evm/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/substrate/frame/revive/rpc/examples/js/index.html b/substrate/frame/revive/rpc/examples/js/index.html index 72f7026ce5f3..97efebe180ea 100644 --- a/substrate/frame/revive/rpc/examples/js/index.html +++ b/substrate/frame/revive/rpc/examples/js/index.html @@ -1,29 +1,38 @@ - - - - - MetaMask Playground - - - - - + button { + display: block; + margin-bottom: 10px; + } + + + + + - + - - + + - - - + + + diff --git a/substrate/frame/revive/rpc/examples/js/package-lock.json b/substrate/frame/revive/rpc/examples/js/package-lock.json new file mode 100644 index 000000000000..5c7db0abc936 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/package-lock.json @@ -0,0 +1,443 @@ +{ + "name": "demo", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "demo", + "version": "0.0.0", + "dependencies": { + "ethers": "^6.13.1", + "solc": "^0.8.28" + }, + "devDependencies": { + "typescript": "^5.5.3", + "vite": "^5.4.8" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "license": "MIT" + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.24.0", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.0", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.15.13", + "license": "MIT" + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "license": "MIT" + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/ethers": { + "version": "6.13.3", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.47", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solc": { + "version": "0.8.28", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.28.tgz", + "integrity": "sha512-AFCiJ+b4RosyyNhnfdVH4ZR1+TxiL91iluPjw0EJslIu4LXGM9NYqi2z5y8TqochC4tcH9QsHfwWhOIC9jPDKA==", + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.6.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.4.8", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.17.1", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/substrate/frame/revive/rpc/examples/js/package.json b/substrate/frame/revive/rpc/examples/js/package.json index 4d7136606b65..6d8d00fd4214 100644 --- a/substrate/frame/revive/rpc/examples/js/package.json +++ b/substrate/frame/revive/rpc/examples/js/package.json @@ -1,18 +1,23 @@ { - "name": "demo", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "ethers": "^6.13.1" - }, - "devDependencies": { - "typescript": "^5.5.3", - "vite": "^5.4.8" - } + "name": "demo", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "ethers": "^6.13.4", + "solc": "^0.8.28", + "viem": "^2.21.47", + "@parity/revive": "^0.0.5" + }, + "devDependencies": { + "prettier": "^3.3.3", + "@types/bun": "^1.1.13", + "typescript": "^5.5.3", + "vite": "^5.4.8" + } } diff --git a/substrate/frame/revive/rpc/examples/js/pvm/ErrorTester.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/ErrorTester.polkavm new file mode 100644 index 000000000000..77de4ff3b1b3 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/ErrorTester.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/pvm/EventExample.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/EventExample.polkavm new file mode 100644 index 000000000000..6dbc5ca8b108 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/EventExample.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/pvm/Flipper.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/Flipper.polkavm new file mode 100644 index 000000000000..488ee684f0c4 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/Flipper.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm new file mode 100644 index 000000000000..585fbb392a31 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/FlipperCaller.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm new file mode 100644 index 000000000000..3f96fdfc21d8 Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/PiggyBank.polkavm differ diff --git a/substrate/frame/revive/rpc/examples/js/src/balance.ts b/substrate/frame/revive/rpc/examples/js/src/balance.ts new file mode 100644 index 000000000000..1261dcab7812 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/balance.ts @@ -0,0 +1,8 @@ +import { walletClient } from './lib.ts' + +const recipient = '0x8D97689C9818892B700e27F316cc3E41e17fBeb9' +try { + console.log(`Recipient balance: ${await walletClient.getBalance({ address: recipient })}`) +} catch (err) { + console.error(err) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts new file mode 100644 index 000000000000..a37b850214b8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts @@ -0,0 +1,96 @@ +import { compile } from '@parity/revive' +import { format } from 'prettier' +import { parseArgs } from 'node:util' +import solc from 'solc' +import { readdirSync, readFileSync, writeFileSync } from 'fs' +import { basename, join } from 'path' + +type CompileInput = Parameters[0] + +const { + values: { filter }, +} = parseArgs({ + args: process.argv.slice(2), + options: { + filter: { + type: 'string', + short: 'f', + }, + }, +}) + +function evmCompile(sources: CompileInput) { + const input = { + language: 'Solidity', + sources, + settings: { + outputSelection: { + '*': { + '*': ['*'], + }, + }, + }, + } + + return solc.compile(JSON.stringify(input)) +} + +console.log('Compiling contracts...') + +const rootDir = join(__dirname, '..') +const contractsDir = join(rootDir, 'contracts') +const abiDir = join(rootDir, 'abi') +const pvmDir = join(rootDir, 'pvm') +const evmDir = join(rootDir, 'evm') + +const input = readdirSync(contractsDir) + .filter((f) => f.endsWith('.sol')) + .filter((f) => !filter || f.includes(filter)) + +for (const file of input) { + console.log(`🔨 Compiling ${file}...`) + const name = basename(file, '.sol') + const input = { + [name]: { content: readFileSync(join(contractsDir, file), 'utf8') }, + } + + console.log('Compiling with revive...') + const reviveOut = await compile(input) + + for (const contracts of Object.values(reviveOut.contracts)) { + for (const [name, contract] of Object.entries(contracts)) { + console.log(`📜 Add PVM contract ${name}`) + const abi = contract.abi + const abiName = `${name}Abi` + writeFileSync( + join(abiDir, `${name}.json`), + JSON.stringify(abi, null, 2) + ) + + writeFileSync( + join(abiDir, `${name}.ts`), + await format(`export const ${abiName} = ${JSON.stringify(abi, null, 2)} as const`, { + parser: 'typescript', + }) + ) + + writeFileSync( + join(pvmDir, `${name}.polkavm`), + Buffer.from(contract.evm.bytecode.object, 'hex') + ) + } + } + + console.log(`Compile with solc ${file}`) + const evmOut = JSON.parse(evmCompile(input)) as typeof reviveOut + + for (const contracts of Object.values(evmOut.contracts)) { + for (const [name, contract] of Object.entries(contracts)) { + console.log(`📜 Add EVM contract ${name}`) + writeFileSync( + join(evmDir, `${name}.bin`), + Buffer.from(contract.evm.bytecode.object, 'hex') + ) + } + } +} diff --git a/substrate/frame/revive/rpc/examples/js/src/event.ts b/substrate/frame/revive/rpc/examples/js/src/event.ts new file mode 100644 index 000000000000..2e672a9772ff --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/event.ts @@ -0,0 +1,29 @@ +//! Run with bun run script-event.ts + +import { abi } from '../abi/event.ts' +import { assert, getByteCode, walletClient } from './lib.ts' + +const deployHash = await walletClient.deployContract({ + abi, + bytecode: getByteCode('event'), +}) +const deployReceipt = await walletClient.waitForTransactionReceipt({ hash: deployHash }) +const contractAddress = deployReceipt.contractAddress +console.log('Contract deployed:', contractAddress) +assert(contractAddress, 'Contract address should be set') + +const { request } = await walletClient.simulateContract({ + account: walletClient.account, + address: contractAddress, + abi, + functionName: 'triggerEvent', +}) + +const hash = await walletClient.writeContract(request) +const receipt = await walletClient.waitForTransactionReceipt({ hash }) +console.log(`Receipt: ${receipt.status}`) +console.log(`Logs receipt: ${receipt.status}`) + +for (const log of receipt.logs) { + console.log('Event log:', log) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/geth-diff-setup.ts b/substrate/frame/revive/rpc/examples/js/src/geth-diff-setup.ts new file mode 100644 index 000000000000..3db2453f2475 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/geth-diff-setup.ts @@ -0,0 +1,177 @@ +import { spawn, spawnSync, Subprocess } from 'bun' +import { resolve } from 'path' +import { readFileSync } from 'fs' +import { createWalletClient, defineChain, Hex, http, publicActions } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' + +export function getByteCode(name: string, evm: boolean): Hex { + const bytecode = evm ? readFileSync(`evm/${name}.bin`) : readFileSync(`pvm/${name}.polkavm`) + return `0x${Buffer.from(bytecode).toString('hex')}` +} + +export type JsonRpcError = { + code: number + message: string + data: Hex +} + +export function killProcessOnPort(port: number) { + // Check which process is using the specified port + const result = spawnSync(['lsof', '-ti', `:${port}`]) + const output = result.stdout.toString().trim() + + if (output) { + console.log(`Port ${port} is in use. Killing process...`) + const pids = output.split('\n') + + // Kill each process using the port + for (const pid of pids) { + spawnSync(['kill', '-9', pid]) + console.log(`Killed process with PID: ${pid}`) + } + } +} + +export let jsonRpcErrors: JsonRpcError[] = [] +export async function createEnv(name: 'geth' | 'kitchensink') { + const gethPort = process.env.GETH_PORT || '8546' + const kitchensinkPort = process.env.KITCHENSINK_PORT || '8545' + const url = `http://localhost:${name == 'geth' ? gethPort : kitchensinkPort}` + const chain = defineChain({ + id: name == 'geth' ? 1337 : 420420420, + name, + nativeCurrency: { + name: 'Westie', + symbol: 'WST', + decimals: 18, + }, + rpcUrls: { + default: { + http: [url], + }, + }, + testnet: true, + }) + + const transport = http(url, { + onFetchResponse: async (response) => { + const raw = await response.clone().json() + if (raw.error) { + jsonRpcErrors.push(raw.error as JsonRpcError) + } + }, + }) + + const wallet = createWalletClient({ + transport, + chain, + }) + + const [account] = await wallet.getAddresses() + const serverWallet = createWalletClient({ + account, + transport, + chain, + }).extend(publicActions) + + const accountWallet = createWalletClient({ + account: privateKeyToAccount( + '0xa872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f' + ), + transport, + chain, + }).extend(publicActions) + + return { serverWallet, accountWallet, evm: name == 'geth' } +} + +// wait for http request to return 200 +export function waitForHealth(url: string) { + return new Promise((resolve, reject) => { + const start = Date.now() + const interval = setInterval(async () => { + try { + const res = await fetch(url, { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_syncing', + params: [], + id: 1, + }), + }) + + if (res.status !== 200) { + return + } + + clearInterval(interval) + resolve() + } catch (_err) { + const elapsed = Date.now() - start + if (elapsed > 30_000) { + clearInterval(interval) + reject(new Error('hit timeout')) + } + } + }, 1000) + }) +} + +export const procs: Subprocess[] = [] +const polkadotSdkPath = resolve(__dirname, '../../../../../../..') +if (!process.env.USE_LIVE_SERVERS) { + procs.push( + // Run geth on port 8546 + await (async () => { + killProcessOnPort(8546) + const proc = spawn( + 'geth --http --http.api web3,eth,debug,personal,net --http.port 8546 --dev --verbosity 0'.split( + ' ' + ), + { stdout: Bun.file('/tmp/geth.out.log'), stderr: Bun.file('/tmp/geth.err.log') } + ) + + await waitForHealth('http://localhost:8546').catch() + return proc + })(), + //Run the substate node + (() => { + killProcessOnPort(9944) + return spawn( + [ + './target/debug/substrate-node', + '--dev', + '-l=error,evm=debug,sc_rpc_server=info,runtime::revive=debug', + ], + { + stdout: Bun.file('/tmp/kitchensink.out.log'), + stderr: Bun.file('/tmp/kitchensink.err.log'), + cwd: polkadotSdkPath, + } + ) + })(), + // Run eth-rpc on 8545 + await (async () => { + killProcessOnPort(8545) + const proc = spawn( + [ + './target/debug/eth-rpc', + '--dev', + '--node-rpc-url=ws://localhost:9944', + '-l=rpc-metrics=debug,eth-rpc=debug', + ], + { + stdout: Bun.file('/tmp/eth-rpc.out.log'), + stderr: Bun.file('/tmp/eth-rpc.err.log'), + cwd: polkadotSdkPath, + } + ) + await waitForHealth('http://localhost:8545').catch() + return proc + })() + ) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts b/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts new file mode 100644 index 000000000000..37ebbc9ea3b3 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/geth-diff.test.ts @@ -0,0 +1,315 @@ +import { jsonRpcErrors, procs, createEnv, getByteCode } from './geth-diff-setup.ts' +import { afterAll, afterEach, beforeAll, describe, expect, test } from 'bun:test' +import { encodeFunctionData, Hex, parseEther } from 'viem' +import { ErrorTesterAbi } from '../abi/ErrorTester' +import { FlipperCallerAbi } from '../abi/FlipperCaller' +import { FlipperAbi } from '../abi/Flipper' + +afterEach(() => { + jsonRpcErrors.length = 0 +}) + +afterAll(async () => { + procs.forEach((proc) => proc.kill()) +}) + +const envs = await Promise.all([createEnv('geth'), createEnv('kitchensink')]) + +for (const env of envs) { + describe(env.serverWallet.chain.name, () => { + let errorTesterAddr: Hex = '0x' + let flipperAddr: Hex = '0x' + let flipperCallerAddr: Hex = '0x' + beforeAll(async () => { + { + const hash = await env.serverWallet.deployContract({ + abi: ErrorTesterAbi, + bytecode: getByteCode('errorTester', env.evm), + }) + const deployReceipt = await env.serverWallet.waitForTransactionReceipt({ hash }) + if (!deployReceipt.contractAddress) + throw new Error('Contract address should be set') + errorTesterAddr = deployReceipt.contractAddress + } + + { + const hash = await env.serverWallet.deployContract({ + abi: FlipperAbi, + bytecode: getByteCode('flipper', env.evm), + }) + const deployReceipt = await env.serverWallet.waitForTransactionReceipt({ hash }) + if (!deployReceipt.contractAddress) + throw new Error('Contract address should be set') + flipperAddr = deployReceipt.contractAddress + } + + { + const hash = await env.serverWallet.deployContract({ + abi: FlipperCallerAbi, + args: [flipperAddr], + bytecode: getByteCode('flipperCaller', env.evm), + }) + const deployReceipt = await env.serverWallet.waitForTransactionReceipt({ hash }) + if (!deployReceipt.contractAddress) + throw new Error('Contract address should be set') + flipperCallerAddr = deployReceipt.contractAddress + } + }) + + test('triggerAssertError', async () => { + expect.assertions(3) + try { + await env.accountWallet.readContract({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'triggerAssertError', + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(3) + expect(lastJsonRpcError?.data).toBe( + '0x4e487b710000000000000000000000000000000000000000000000000000000000000001' + ) + expect(lastJsonRpcError?.message).toBe('execution reverted: assert(false)') + } + }) + + test('triggerRevertError', async () => { + expect.assertions(3) + try { + await env.accountWallet.readContract({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'triggerRevertError', + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(3) + expect(lastJsonRpcError?.message).toBe('execution reverted: This is a revert error') + expect(lastJsonRpcError?.data).toBe( + '0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001654686973206973206120726576657274206572726f7200000000000000000000' + ) + } + }) + + test('triggerDivisionByZero', async () => { + expect.assertions(3) + try { + await env.accountWallet.readContract({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'triggerDivisionByZero', + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(3) + expect(lastJsonRpcError?.data).toBe( + '0x4e487b710000000000000000000000000000000000000000000000000000000000000012' + ) + expect(lastJsonRpcError?.message).toBe( + 'execution reverted: division or modulo by zero' + ) + } + }) + + test('triggerOutOfBoundsError', async () => { + expect.assertions(3) + try { + await env.accountWallet.readContract({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'triggerOutOfBoundsError', + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(3) + expect(lastJsonRpcError?.data).toBe( + '0x4e487b710000000000000000000000000000000000000000000000000000000000000032' + ) + expect(lastJsonRpcError?.message).toBe( + 'execution reverted: out-of-bounds access of an array or bytesN' + ) + } + }) + + test('triggerCustomError', async () => { + expect.assertions(3) + try { + await env.accountWallet.readContract({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'triggerCustomError', + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(3) + expect(lastJsonRpcError?.data).toBe( + '0x8d6ea8be0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001654686973206973206120637573746f6d206572726f7200000000000000000000' + ) + expect(lastJsonRpcError?.message).toBe('execution reverted') + } + }) + + test('eth_call (not enough funds)', async () => { + expect.assertions(3) + try { + await env.accountWallet.simulateContract({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'valueMatch', + value: parseEther('10'), + args: [parseEther('10')], + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(-32000) + expect(lastJsonRpcError?.message).toInclude('insufficient funds') + expect(lastJsonRpcError?.data).toBeUndefined() + } + }) + + test('eth_call transfer (not enough funds)', async () => { + expect.assertions(3) + try { + await env.accountWallet.sendTransaction({ + to: '0x75E480dB528101a381Ce68544611C169Ad7EB342', + value: parseEther('10'), + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(-32000) + expect(lastJsonRpcError?.message).toInclude('insufficient funds') + expect(lastJsonRpcError?.data).toBeUndefined() + } + }) + + test('eth_estimate (not enough funds)', async () => { + expect.assertions(3) + try { + await env.accountWallet.estimateContractGas({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'valueMatch', + value: parseEther('10'), + args: [parseEther('10')], + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(-32000) + expect(lastJsonRpcError?.message).toInclude('insufficient funds') + expect(lastJsonRpcError?.data).toBeUndefined() + } + }) + + test('eth_estimate call caller (not enough funds)', async () => { + expect.assertions(3) + try { + await env.accountWallet.estimateContractGas({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'valueMatch', + value: parseEther('10'), + args: [parseEther('10')], + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(-32000) + expect(lastJsonRpcError?.message).toInclude('insufficient funds') + expect(lastJsonRpcError?.data).toBeUndefined() + } + }) + + test('eth_estimate (revert)', async () => { + expect.assertions(3) + try { + await env.serverWallet.estimateContractGas({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'valueMatch', + value: parseEther('11'), + args: [parseEther('10')], + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(3) + expect(lastJsonRpcError?.message).toBe( + 'execution reverted: msg.value does not match value' + ) + expect(lastJsonRpcError?.data).toBe( + '0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e6d73672e76616c756520646f6573206e6f74206d617463682076616c75650000' + ) + } + }) + + test('eth_get_balance (no account)', async () => { + const balance = await env.serverWallet.getBalance({ + address: '0x0000000000000000000000000000000000000123', + }) + expect(balance).toBe(0n) + }) + + test('eth_estimate (not enough funds to cover gas specified)', async () => { + expect.assertions(4) + try { + let balance = await env.serverWallet.getBalance(env.accountWallet.account) + expect(balance).toBe(0n) + + await env.accountWallet.estimateContractGas({ + address: errorTesterAddr, + abi: ErrorTesterAbi, + functionName: 'setState', + args: [true], + }) + } catch (err) { + const lastJsonRpcError = jsonRpcErrors.pop() + expect(lastJsonRpcError?.code).toBe(-32000) + expect(lastJsonRpcError?.message).toInclude('insufficient funds') + expect(lastJsonRpcError?.data).toBeUndefined() + } + }) + + test('eth_estimate (no gas specified)', async () => { + let balance = await env.serverWallet.getBalance(env.accountWallet.account) + expect(balance).toBe(0n) + + const data = encodeFunctionData({ + abi: ErrorTesterAbi, + functionName: 'setState', + args: [true], + }) + + await env.accountWallet.request({ + method: 'eth_estimateGas', + params: [ + { + data, + from: env.accountWallet.account.address, + to: errorTesterAddr, + }, + ], + }) + }) + + test.only('eth_estimate (no gas specified) child_call', async () => { + let balance = await env.serverWallet.getBalance(env.accountWallet.account) + expect(balance).toBe(0n) + + const data = encodeFunctionData({ + abi: FlipperCallerAbi, + functionName: 'callFlip', + }) + + await env.accountWallet.request({ + method: 'eth_estimateGas', + params: [ + { + data, + from: env.accountWallet.account.address, + to: flipperCallerAddr, + gas: `0x${Number(1000000).toString(16)}`, + }, + ], + }) + }) + }) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/lib.ts b/substrate/frame/revive/rpc/examples/js/src/lib.ts new file mode 100644 index 000000000000..e1f0e780d95b --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/lib.ts @@ -0,0 +1,128 @@ +import { readFileSync } from 'node:fs' +import { spawn } from 'node:child_process' +import { parseArgs } from 'node:util' +import { createWalletClient, defineChain, Hex, http, parseEther, publicActions } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' + +const { + values: { geth, proxy, westend, endowment, ['private-key']: privateKey }, +} = parseArgs({ + args: process.argv.slice(2), + options: { + ['private-key']: { + type: 'string', + short: 'k', + }, + endowment: { + type: 'string', + short: 'e', + }, + proxy: { + type: 'boolean', + }, + geth: { + type: 'boolean', + }, + westend: { + type: 'boolean', + }, + }, +}) + +if (geth) { + console.log('Testing with Geth') + const child = spawn( + 'geth', + [ + '--http', + '--http.api', + 'web3,eth,debug,personal,net', + '--http.port', + process.env.GETH_PORT ?? '8546', + '--dev', + '--verbosity', + '0', + ], + { stdio: 'inherit' } + ) + + process.on('exit', () => child.kill()) + child.unref() + await new Promise((resolve) => setTimeout(resolve, 500)) +} + +const rpcUrl = proxy + ? 'http://localhost:8080' + : westend + ? 'https://westend-asset-hub-eth-rpc.polkadot.io' + : geth + ? 'http://localhost:8546' + : 'http://localhost:8545' + +export const chain = defineChain({ + id: geth ? 1337 : 420420420, + name: 'Asset Hub Westend', + network: 'asset-hub', + nativeCurrency: { + name: 'Westie', + symbol: 'WST', + decimals: 18, + }, + rpcUrls: { + default: { + http: [rpcUrl], + }, + }, + testnet: true, +}) + +const wallet = createWalletClient({ + transport: http(), + chain, +}) +const [account] = await wallet.getAddresses() +export const serverWalletClient = createWalletClient({ + account, + transport: http(), + chain, +}) + +export const walletClient = await (async () => { + if (privateKey) { + const account = privateKeyToAccount(`0x${privateKey}`) + console.log(`Wallet address ${account.address}`) + + const wallet = createWalletClient({ + account, + transport: http(), + chain, + }) + + if (endowment) { + await serverWalletClient.sendTransaction({ + to: account.address, + value: parseEther(endowment), + }) + console.log(`Endowed address ${account.address} with: ${endowment}`) + } + + return wallet.extend(publicActions) + } else { + return serverWalletClient.extend(publicActions) + } +})() + +/** + * Get one of the pre-built contracts + * @param name - the contract name + */ +export function getByteCode(name: string): Hex { + const bytecode = geth ? readFileSync(`evm/${name}.bin`) : readFileSync(`pvm/${name}.polkavm`) + return `0x${Buffer.from(bytecode).toString('hex')}` +} + +export function assert(condition: any, message: string): asserts condition { + if (!condition) { + throw new Error(message) + } +} diff --git a/substrate/frame/revive/rpc/examples/js/src/main.ts b/substrate/frame/revive/rpc/examples/js/src/main.ts deleted file mode 100644 index 88b72755aae9..000000000000 --- a/substrate/frame/revive/rpc/examples/js/src/main.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { - AddressLike, - BrowserProvider, - Contract, - ContractFactory, - Eip1193Provider, - JsonRpcSigner, - parseEther, -} from "ethers"; - -declare global { - interface Window { - ethereum?: Eip1193Provider; - } -} - -function str_to_bytes(str: string): Uint8Array { - return new TextEncoder().encode(str); -} - -document.addEventListener("DOMContentLoaded", async () => { - if (typeof window.ethereum == "undefined") { - return console.log("MetaMask is not installed"); - } - - console.log("MetaMask is installed!"); - const provider = new BrowserProvider(window.ethereum); - - console.log("Getting signer..."); - let signer: JsonRpcSigner; - try { - signer = await provider.getSigner(); - console.log(`Signer: ${signer.address}`); - } catch (e) { - console.error("Failed to get signer", e); - return; - } - - console.log("Getting block number..."); - try { - const blockNumber = await provider.getBlockNumber(); - console.log(`Block number: ${blockNumber}`); - } catch (e) { - console.error("Failed to get block number", e); - return; - } - - const nonce = await signer.getNonce(); - console.log(`Nonce: ${nonce}`); - - document.getElementById("transferButton")?.addEventListener( - "click", - async () => { - const address = - (document.getElementById("transferInput") as HTMLInputElement).value; - await transfer(address); - }, - ); - - document.getElementById("deployButton")?.addEventListener( - "click", - async () => { - await deploy(); - }, - ); - document.getElementById("deployAndCallButton")?.addEventListener( - "click", - async () => { - const nonce = await signer.getNonce(); - console.log(`deploy with nonce: ${nonce}`); - - const address = await deploy(); - if (address) { - const nonce = await signer.getNonce(); - console.log(`call with nonce: ${nonce}`); - await call(address); - } - }, - ); - document.getElementById("callButton")?.addEventListener("click", async () => { - const address = - (document.getElementById("callInput") as HTMLInputElement).value; - await call(address); - }); - - async function deploy() { - console.log("Deploying contract..."); - - const bytecode = await fetch("rpc_demo.polkavm").then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.arrayBuffer(); - }) - .then((arrayBuffer) => new Uint8Array(arrayBuffer)); - - const contractFactory = new ContractFactory( - [ - "constructor(bytes memory _data)", - ], - bytecode, - signer, - ); - - try { - const args = str_to_bytes("hello"); - const contract = await contractFactory.deploy(args); - await contract.waitForDeployment(); - const address = await contract.getAddress(); - console.log(`Contract deployed: ${address}`); - return address; - } catch (e) { - console.error("Failed to deploy contract", e); - return; - } - } - - async function call(address: string) { - const abi = ["function call(bytes data)"]; - const contract = new Contract(address, abi, signer); - const tx = await contract.call(str_to_bytes("world")); - - console.log("Transaction hash:", tx.hash); - } - - async function transfer(to: AddressLike) { - console.log(`transferring 1 DOT to ${to}...`); - try { - const tx = await signer.sendTransaction({ - to, - value: parseEther("1.0"), - }); - - const receipt = await tx.wait(); - console.log(`Transaction hash: ${receipt?.hash}`); - } catch (e) { - console.error("Failed to send transaction", e); - return; - } - } -}); diff --git a/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts b/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts new file mode 100644 index 000000000000..0040b0c78dc4 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts @@ -0,0 +1,69 @@ +import { assert, getByteCode, walletClient } from './lib.ts' +import { abi } from '../abi/piggyBank.ts' +import { parseEther } from 'viem' + +const hash = await walletClient.deployContract({ + abi, + bytecode: getByteCode('piggyBank'), +}) +const deployReceipt = await walletClient.waitForTransactionReceipt({ hash }) +const contractAddress = deployReceipt.contractAddress +console.log('Contract deployed:', contractAddress) +assert(contractAddress, 'Contract address should be set') + +// Deposit 10 WST +{ + const result = await walletClient.estimateContractGas({ + account: walletClient.account, + address: contractAddress, + abi, + functionName: 'deposit', + value: parseEther('10'), + }) + + console.log(`Gas estimate: ${result}`) + + const { request } = await walletClient.simulateContract({ + account: walletClient.account, + address: contractAddress, + abi, + functionName: 'deposit', + value: parseEther('10'), + }) + + request.nonce = 0 + const hash = await walletClient.writeContract(request) + + const receipt = await walletClient.waitForTransactionReceipt({ hash }) + console.log(`Deposit receipt: ${receipt.status}`) + if (process.env.STOP) { + process.exit(0) + } +} + +// Withdraw 5 WST +{ + const { request } = await walletClient.simulateContract({ + account: walletClient.account, + address: contractAddress, + abi, + functionName: 'withdraw', + args: [parseEther('5')], + }) + + const hash = await walletClient.writeContract(request) + const receipt = await walletClient.waitForTransactionReceipt({ hash }) + console.log(`Withdraw receipt: ${receipt.status}`) + + // Check remaining balance + const balance = await walletClient.readContract({ + address: contractAddress, + abi, + functionName: 'getDeposit', + }) + + console.log(`Get deposit: ${balance}`) + console.log( + `Get contract balance: ${await walletClient.getBalance({ address: contractAddress })}` + ) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/script.ts b/substrate/frame/revive/rpc/examples/js/src/script.ts deleted file mode 100644 index 999312f0fd5b..000000000000 --- a/substrate/frame/revive/rpc/examples/js/src/script.ts +++ /dev/null @@ -1,49 +0,0 @@ -//! Run with bun run script.ts - -import { readFileSync } from "fs"; -import { Contract, ContractFactory, JsonRpcProvider } from "ethers"; - -const provider = new JsonRpcProvider("http://localhost:8545"); -const signer = await provider.getSigner(); -console.log( - `Signer address: ${await signer.getAddress()}, Nonce: ${await signer - .getNonce()}`, -); - -function str_to_bytes(str: string): Uint8Array { - return new TextEncoder().encode(str); -} - -// deploy -async function deploy() { - console.log(`Deploying Contract...`); - - const bytecode = readFileSync("../rpc_demo.polkavm"); - const contractFactory = new ContractFactory( - [ - "constructor(bytes memory _data)", - ], - bytecode, - signer, - ); - - const args = str_to_bytes("hello"); - console.log("Deploying contract with args:", args); - const contract = await contractFactory.deploy(args); - await contract.waitForDeployment(); - const address = await contract.getAddress(); - console.log(`Contract deployed: ${address}`); - return address; -} - -async function call(address: string) { - console.log(`Calling Contract at ${address}...`); - - const abi = ["function call(bytes data)"]; - const contract = new Contract(address, abi, signer); - const tx = await contract.call(str_to_bytes("world")); - console.log("Call transaction hash:", tx.hash); -} - -const address = await deploy(); -await call(address); diff --git a/substrate/frame/revive/rpc/examples/js/src/solc.d.ts b/substrate/frame/revive/rpc/examples/js/src/solc.d.ts new file mode 100644 index 000000000000..813829f40b6d --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/solc.d.ts @@ -0,0 +1,83 @@ +declare module 'solc' { + // Basic types for input/output handling + export interface CompileInput { + language: string + sources: { + [fileName: string]: { + content: string + } + } + settings?: { + optimizer?: { + enabled: boolean + runs: number + } + outputSelection: { + [fileName: string]: { + [contractName: string]: string[] + } + } + } + } + + export interface CompileOutput { + errors?: Array<{ + component: string + errorCode: string + formattedMessage: string + message: string + severity: string + sourceLocation?: { + file: string + start: number + end: number + } + type: string + }> + sources?: { + [fileName: string]: { + id: number + ast: object + } + } + contracts?: { + [fileName: string]: { + [contractName: string]: { + abi: object[] + evm: { + bytecode: { + object: string + sourceMap: string + linkReferences: { + [fileName: string]: { + [libraryName: string]: Array<{ + start: number + length: number + }> + } + } + } + deployedBytecode: { + object: string + sourceMap: string + linkReferences: { + [fileName: string]: { + [libraryName: string]: Array<{ + start: number + length: number + }> + } + } + } + } + } + } + } + } + + // Main exported functions + export function compile( + input: string | CompileInput, + options?: { import: (path: string) => { contents: string } } + ): string +} diff --git a/substrate/frame/revive/rpc/examples/js/src/transfer.ts b/substrate/frame/revive/rpc/examples/js/src/transfer.ts new file mode 100644 index 000000000000..aef9a487b0c0 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/transfer.ts @@ -0,0 +1,18 @@ +import { parseEther } from 'viem' +import { walletClient } from './lib.ts' + +const recipient = '0x75E480dB528101a381Ce68544611C169Ad7EB342' +try { + console.log(`Signer balance: ${await walletClient.getBalance(walletClient.account)}`) + console.log(`Recipient balance: ${await walletClient.getBalance({ address: recipient })}`) + + await walletClient.sendTransaction({ + to: recipient, + value: parseEther('1.0'), + }) + console.log(`Sent: ${parseEther('1.0')}`) + console.log(`Signer balance: ${await walletClient.getBalance(walletClient.account)}`) + console.log(`Recipient balance: ${await walletClient.getBalance({ address: recipient })}`) +} catch (err) { + console.error(err) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/web.ts b/substrate/frame/revive/rpc/examples/js/src/web.ts new file mode 100644 index 000000000000..ee7c8ed034da --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/web.ts @@ -0,0 +1,129 @@ +import { + AddressLike, + BrowserProvider, + Contract, + ContractFactory, + Eip1193Provider, + JsonRpcSigner, + parseEther, +} from 'ethers' + +declare global { + interface Window { + ethereum?: Eip1193Provider + } +} + +function str_to_bytes(str: string): Uint8Array { + return new TextEncoder().encode(str) +} + +document.addEventListener('DOMContentLoaded', async () => { + if (typeof window.ethereum == 'undefined') { + return console.log('MetaMask is not installed') + } + + console.log('MetaMask is installed!') + const provider = new BrowserProvider(window.ethereum) + + console.log('Getting signer...') + let signer: JsonRpcSigner + try { + signer = await provider.getSigner() + console.log(`Signer: ${signer.address}`) + } catch (e) { + console.error('Failed to get signer', e) + return + } + + console.log('Getting block number...') + try { + const blockNumber = await provider.getBlockNumber() + console.log(`Block number: ${blockNumber}`) + } catch (e) { + console.error('Failed to get block number', e) + return + } + + const nonce = await signer.getNonce() + console.log(`Nonce: ${nonce}`) + + document.getElementById('transferButton')?.addEventListener('click', async () => { + const address = (document.getElementById('transferInput') as HTMLInputElement).value + await transfer(address) + }) + + document.getElementById('deployButton')?.addEventListener('click', async () => { + await deploy() + }) + document.getElementById('deployAndCallButton')?.addEventListener('click', async () => { + const nonce = await signer.getNonce() + console.log(`deploy with nonce: ${nonce}`) + + const address = await deploy() + if (address) { + const nonce = await signer.getNonce() + console.log(`call with nonce: ${nonce}`) + await call(address) + } + }) + document.getElementById('callButton')?.addEventListener('click', async () => { + const address = (document.getElementById('callInput') as HTMLInputElement).value + await call(address) + }) + + async function deploy() { + console.log('Deploying contract...') + + const bytecode = await fetch('rpc_demo.polkavm') + .then((response) => { + if (!response.ok) { + throw new Error('Network response was not ok') + } + return response.arrayBuffer() + }) + .then((arrayBuffer) => new Uint8Array(arrayBuffer)) + + const contractFactory = new ContractFactory( + ['constructor(bytes memory _data)'], + bytecode, + signer + ) + + try { + const args = str_to_bytes('hello') + const contract = await contractFactory.deploy(args) + await contract.waitForDeployment() + const address = await contract.getAddress() + console.log(`Contract deployed: ${address}`) + return address + } catch (e) { + console.error('Failed to deploy contract', e) + return + } + } + + async function call(address: string) { + const abi = ['function call(bytes data)'] + const contract = new Contract(address, abi, signer) + const tx = await contract.call(str_to_bytes('world')) + + console.log('Transaction hash:', tx.hash) + } + + async function transfer(to: AddressLike) { + console.log(`transferring 1 DOT to ${to}...`) + try { + const tx = await signer.sendTransaction({ + to, + value: parseEther('1.0'), + }) + + const receipt = await tx.wait() + console.log(`Transaction hash: ${receipt?.hash}`) + } catch (e) { + console.error('Failed to send transaction', e) + return + } + } +}) diff --git a/substrate/frame/revive/rpc/examples/js/tsconfig.json b/substrate/frame/revive/rpc/examples/js/tsconfig.json index 0511b9f0e041..55cb8379e886 100644 --- a/substrate/frame/revive/rpc/examples/js/tsconfig.json +++ b/substrate/frame/revive/rpc/examples/js/tsconfig.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] } diff --git a/substrate/frame/revive/rpc/examples/rust/deploy.rs b/substrate/frame/revive/rpc/examples/rust/deploy.rs index f2be5d233f6d..b74d7ea18d41 100644 --- a/substrate/frame/revive/rpc/examples/rust/deploy.rs +++ b/substrate/frame/revive/rpc/examples/rust/deploy.rs @@ -17,10 +17,10 @@ use jsonrpsee::http_client::HttpClientBuilder; use pallet_revive::{ create1, - evm::{Account, BlockTag, Bytes, ReceiptInfo, U256}, + evm::{Account, BlockTag, ReceiptInfo, U256}, }; use pallet_revive_eth_rpc::{ - example::{send_transaction, wait_for_receipt}, + example::{wait_for_receipt, TransactionBuilder}, EthRpcClient, }; @@ -41,9 +41,11 @@ async fn main() -> anyhow::Result<()> { println!("\n\n=== Deploying contract ===\n\n"); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; - let hash = - send_transaction(&account, &client, 5_000_000_000_000u128.into(), input.into(), None) - .await?; + let hash = TransactionBuilder::default() + .value(5_000_000_000_000u128.into()) + .input(input) + .send(&client) + .await?; println!("Deploy Tx hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, contract_address, .. } = @@ -60,9 +62,11 @@ async fn main() -> anyhow::Result<()> { println!("- Contract balance: {balance:?}"); println!("\n\n=== Calling contract ===\n\n"); - let hash = - send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) - .await?; + let hash = TransactionBuilder::default() + .value(U256::from(1_000_000u32)) + .to(contract_address) + .send(&client) + .await?; println!("Contract call tx hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, to, .. } = wait_for_receipt(&client, hash).await?; diff --git a/substrate/frame/revive/rpc/examples/rust/transfer.rs b/substrate/frame/revive/rpc/examples/rust/transfer.rs index b99d48a2f78e..1d67a2dba28f 100644 --- a/substrate/frame/revive/rpc/examples/rust/transfer.rs +++ b/substrate/frame/revive/rpc/examples/rust/transfer.rs @@ -15,23 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. use jsonrpsee::http_client::HttpClientBuilder; -use pallet_revive::evm::{Account, BlockTag, Bytes, ReceiptInfo}; +use pallet_revive::evm::{Account, BlockTag, ReceiptInfo}; use pallet_revive_eth_rpc::{ - example::{send_transaction, wait_for_receipt}, + example::{wait_for_receipt, TransactionBuilder}, EthRpcClient, }; #[tokio::main] async fn main() -> anyhow::Result<()> { - let alith = Account::default(); let client = HttpClientBuilder::default().build("http://localhost:8545")?; + let alith = Account::default(); + let alith_address = alith.address(); let ethan = Account::from(subxt_signer::eth::dev::ethan()); let value = 1_000_000_000_000_000_000_000u128.into(); let print_balance = || async { - let balance = client.get_balance(alith.address(), BlockTag::Latest.into()).await?; - println!("Alith {:?} balance: {balance:?}", alith.address()); + let balance = client.get_balance(alith_address, BlockTag::Latest.into()).await?; + println!("Alith {:?} balance: {balance:?}", alith_address); let balance = client.get_balance(ethan.address(), BlockTag::Latest.into()).await?; println!("ethan {:?} balance: {balance:?}", ethan.address()); anyhow::Result::<()>::Ok(()) @@ -40,8 +41,12 @@ async fn main() -> anyhow::Result<()> { print_balance().await?; println!("\n\n=== Transferring ===\n\n"); - let hash = - send_transaction(&alith, &client, value, Bytes::default(), Some(ethan.address())).await?; + let hash = TransactionBuilder::default() + .signer(alith) + .value(value) + .to(ethan.address()) + .send(&client) + .await?; println!("Transaction hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, status, .. } = diff --git a/substrate/frame/revive/rpc/revive_chain.metadata b/substrate/frame/revive/rpc/revive_chain.metadata index 305d079f9bd8..64b1f2014dd0 100644 Binary files a/substrate/frame/revive/rpc/revive_chain.metadata and b/substrate/frame/revive/rpc/revive_chain.metadata differ diff --git a/substrate/frame/revive/rpc/src/cli.rs b/substrate/frame/revive/rpc/src/cli.rs index fcb84e6b54b0..c0f81fcafd77 100644 --- a/substrate/frame/revive/rpc/src/cli.rs +++ b/substrate/frame/revive/rpc/src/cli.rs @@ -15,7 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. //! The Ethereum JSON-RPC server. -use crate::{client::Client, EthRpcServer, EthRpcServerImpl}; +use crate::{ + client::Client, EthRpcServer, EthRpcServerImpl, SystemHealthRpcServer, + SystemHealthRpcServerImpl, +}; use clap::Parser; use futures::{pin_mut, FutureExt}; use jsonrpsee::server::RpcModule; @@ -118,7 +121,10 @@ pub fn run(cmd: CliCommand) -> anyhow::Result<()> { match tokio_handle.block_on(signals.try_until_signal(fut)) { Ok(Ok(client)) => rpc_module(is_dev, client), - Ok(Err(err)) => Err(sc_service::Error::Application(err.into())), + Ok(Err(err)) => { + log::error!("Error connecting to the node at {node_rpc_url}: {err}"); + Err(sc_service::Error::Application(err.into())) + }, Err(_) => Err(sc_service::Error::Application("Client connection interrupted".into())), } }; @@ -142,11 +148,14 @@ pub fn run(cmd: CliCommand) -> anyhow::Result<()> { /// Create the JSON-RPC module. fn rpc_module(is_dev: bool, client: Client) -> Result, sc_service::Error> { - let eth_api = EthRpcServerImpl::new(client) + let eth_api = EthRpcServerImpl::new(client.clone()) .with_accounts(if is_dev { vec![crate::Account::default()] } else { vec![] }) .into_rpc(); + let health_api = SystemHealthRpcServerImpl::new(client).into_rpc(); + let mut module = RpcModule::new(()); module.merge(eth_api).map_err(|e| sc_service::Error::Application(e.into()))?; + module.merge(health_api).map_err(|e| sc_service::Error::Application(e.into()))?; Ok(module) } diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index ba93d0af62ac..901c15e9756b 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -17,25 +17,24 @@ //! The client connects to the source substrate chain //! and is used by the rpc server to query and send transactions to the substrate chain. use crate::{ - rlp, runtime::GAS_PRICE, subxt_client::{ - revive::calls::types::EthTransact, runtime_types::pallet_revive::storage::ContractInfo, + revive::{calls::types::EthTransact, events::ContractEmitted}, + runtime_types::pallet_revive::storage::ContractInfo, }, - TransactionLegacySigned, LOG_TARGET, + LOG_TARGET, }; -use codec::Encode; use futures::{stream, StreamExt}; -use jsonrpsee::types::{ErrorCode, ErrorObjectOwned}; +use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObjectOwned}; use pallet_revive::{ create1, evm::{ - Block, BlockNumberOrTag, BlockNumberOrTagOrHash, Bytes256, GenericTransaction, ReceiptInfo, - SyncingProgress, SyncingStatus, TransactionSigned, H160, H256, U256, + Block, BlockNumberOrTag, BlockNumberOrTagOrHash, Bytes256, GenericTransaction, Log, + ReceiptInfo, SyncingProgress, SyncingStatus, TransactionSigned, H160, H256, U256, }, - EthContractResult, + EthTransactError, EthTransactInfo, }; -use sp_runtime::traits::{BlakeTwo256, Hash}; +use sp_core::keccak_256; use sp_weights::Weight; use std::{ collections::{HashMap, VecDeque}, @@ -44,9 +43,9 @@ use std::{ }; use subxt::{ backend::{ - legacy::LegacyRpcMethods, + legacy::{rpc_methods::SystemHealth, LegacyRpcMethods}, rpc::{ - reconnecting_rpc_client::{Client as ReconnectingRpcClient, ExponentialBackoff}, + reconnecting_rpc_client::{ExponentialBackoff, RpcClient as ReconnectingRpcClient}, RpcClient, }, }, @@ -99,63 +98,119 @@ struct BlockCache { tx_hashes_by_block_and_index: HashMap>, } -fn unwrap_subxt_err(err: &subxt::Error) -> String { +/// Unwrap the original `jsonrpsee::core::client::Error::Call` error. +fn unwrap_call_err(err: &subxt::error::RpcError) -> Option { + use subxt::backend::rpc::reconnecting_rpc_client; match err { - subxt::Error::Rpc(err) => unwrap_rpc_err(err), - _ => err.to_string(), + subxt::error::RpcError::ClientError(err) => { + match err.downcast_ref::() { + Some(reconnecting_rpc_client::Error::RpcError( + jsonrpsee::core::client::Error::Call(err), + )) => Some(err.clone().into_owned()), + _ => None, + } + }, + _ => None, } } -fn unwrap_rpc_err(err: &subxt::error::RpcError) -> String { - match err { - subxt::error::RpcError::ClientError(err) => match err - // TODO use the re-export from subxt once available - .downcast_ref::() - { - Some(jsonrpsee::core::ClientError::Call(call_err)) => call_err.message().to_string(), - Some(other_err) => other_err.to_string(), - None => err.to_string(), +/// Extract the revert message from a revert("msg") solidity statement. +fn extract_revert_message(exec_data: &[u8]) -> Option { + let error_selector = exec_data.get(0..4)?; + + match error_selector { + // assert(false) + [0x4E, 0x48, 0x7B, 0x71] => { + let panic_code: u32 = U256::from_big_endian(exec_data.get(4..36)?).try_into().ok()?; + + // See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require + let msg = match panic_code { + 0x00 => "generic panic", + 0x01 => "assert(false)", + 0x11 => "arithmetic underflow or overflow", + 0x12 => "division or modulo by zero", + 0x21 => "enum overflow", + 0x22 => "invalid encoded storage byte array accessed", + 0x31 => "out-of-bounds array access; popping on an empty array", + 0x32 => "out-of-bounds access of an array or bytesN", + 0x41 => "out of memory", + 0x51 => "uninitialized function", + code => return Some(format!("execution reverted: unknown panic code: {code:#x}")), + }; + + Some(format!("execution reverted: {msg}")) + }, + // revert(string) + [0x08, 0xC3, 0x79, 0xA0] => { + let decoded = ethabi::decode(&[ethabi::ParamType::String], &exec_data[4..]).ok()?; + if let Some(ethabi::Token::String(msg)) = decoded.first() { + return Some(format!("execution reverted: {msg}")) + } + Some("execution reverted".to_string()) + }, + _ => { + log::debug!(target: LOG_TARGET, "Unknown revert function selector: {error_selector:?}"); + Some("execution reverted".to_string()) }, - _ => err.to_string(), } } /// The error type for the client. #[derive(Error, Debug)] pub enum ClientError { + /// A [`jsonrpsee::core::ClientError`] wrapper error. + #[error(transparent)] + Jsonrpsee(#[from] jsonrpsee::core::ClientError), /// A [`subxt::Error`] wrapper error. - #[error("{}",unwrap_subxt_err(.0))] + #[error(transparent)] SubxtError(#[from] subxt::Error), /// A [`RpcError`] wrapper error. - #[error("{}",unwrap_rpc_err(.0))] + #[error(transparent)] RpcError(#[from] RpcError), /// A [`codec::Error`] wrapper error. #[error(transparent)] CodecError(#[from] codec::Error), - /// The dry run failed. - #[error("Dry run failed")] - DryRunFailed, + /// Contract reverted + #[error("contract reverted")] + Reverted(EthTransactError), /// A decimal conversion failed. - #[error("Conversion failed")] + #[error("conversion failed")] ConversionFailed, /// The block hash was not found. - #[error("Hash not found")] + #[error("hash not found")] BlockNotFound, /// The transaction fee could not be found - #[error("TransactionFeePaid event not found")] + #[error("transactionFeePaid event not found")] TxFeeNotFound, /// The cache is empty. - #[error("Cache is empty")] + #[error("cache is empty")] CacheEmpty, } -const GENERIC_ERROR_CODE: ErrorCode = ErrorCode::ServerError(-32000); - -// Convert a `ClientError` to an RPC `ErrorObjectOwned`. +const REVERT_CODE: i32 = 3; impl From for ErrorObjectOwned { - fn from(value: ClientError) -> Self { - log::debug!(target: LOG_TARGET, "ClientError: {value:?}"); - ErrorObjectOwned::owned::<()>(GENERIC_ERROR_CODE.code(), value.to_string(), None) + fn from(err: ClientError) -> Self { + match err { + ClientError::SubxtError(subxt::Error::Rpc(err)) | ClientError::RpcError(err) => { + if let Some(err) = unwrap_call_err(&err) { + return err; + } + ErrorObjectOwned::owned::>( + CALL_EXECUTION_FAILED_CODE, + err.to_string(), + None, + ) + }, + ClientError::Reverted(EthTransactError::Data(data)) => { + let msg = extract_revert_message(&data).unwrap_or_default(); + let data = format!("0x{}", hex::encode(data)); + ErrorObjectOwned::owned::(REVERT_CODE, msg, Some(data)) + }, + ClientError::Reverted(EthTransactError::Message(msg)) => + ErrorObjectOwned::owned::(CALL_EXECUTION_FAILED_CODE, msg, None), + _ => + ErrorObjectOwned::owned::(CALL_EXECUTION_FAILED_CODE, err.to_string(), None), + } } } @@ -192,6 +247,7 @@ impl BlockCache { } /// A client connect to a node and maintains a cache of the last `CACHE_SIZE` blocks. +#[derive(Clone)] pub struct Client { /// The inner state of the client. inner: Arc, @@ -207,7 +263,6 @@ struct ClientInner { cache: Shared>, chain_id: u64, max_block_weight: Weight, - native_to_evm_ratio: U256, } impl ClientInner { @@ -223,20 +278,10 @@ impl ClientInner { let rpc = LegacyRpcMethods::::new(RpcClient::new(rpc_client.clone())); - let (native_to_evm_ratio, chain_id, max_block_weight) = - tokio::try_join!(native_to_evm_ratio(&api), chain_id(&api), max_block_weight(&api))?; + let (chain_id, max_block_weight) = + tokio::try_join!(chain_id(&api), max_block_weight(&api))?; - Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight, native_to_evm_ratio }) - } - - /// Convert a native balance to an EVM balance. - fn native_to_evm_decimals(&self, value: U256) -> U256 { - value.saturating_mul(self.native_to_evm_ratio) - } - - /// Convert an evm balance to a native balance. - fn evm_to_native_decimals(&self, value: U256) -> U256 { - value / self.native_to_evm_ratio + Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight }) } /// Get the receipt infos from the extrinsics in a block. @@ -249,53 +294,74 @@ impl ClientInner { // Filter extrinsics from pallet_revive let extrinsics = extrinsics.iter().flat_map(|ext| { - let ext = ext.ok()?; - let call = ext.as_extrinsic::().ok()??; - let tx = rlp::decode::(&call.payload).ok()?; - let from = tx.recover_eth_address().ok()?; - let contract_address = if tx.transaction_legacy_unsigned.to.is_none() { - Some(create1(&from, tx.transaction_legacy_unsigned.nonce.try_into().ok()?)) + let transaction_hash = H256(keccak_256(&call.payload)); + let signed_tx = TransactionSigned::decode(&call.payload).ok()?; + let from = signed_tx.recover_eth_address().ok()?; + let tx_info = GenericTransaction::from_signed(signed_tx.clone(), Some(from)); + let contract_address = if tx_info.to.is_none() { + Some(create1(&from, tx_info.nonce.unwrap_or_default().try_into().ok()?)) } else { None }; - Some((from, tx, contract_address, ext)) + Some((from, signed_tx, tx_info, transaction_hash, contract_address, ext)) }); // Map each extrinsic to a receipt stream::iter(extrinsics) - .map(|(from, tx, contract_address, ext)| async move { + .map(|(from, signed_tx, tx_info, transaction_hash, contract_address, ext)| async move { let events = ext.events().await?; let tx_fees = events.find_first::()?.ok_or(ClientError::TxFeeNotFound)?; - let gas_price = tx.transaction_legacy_unsigned.gas_price; + let gas_price = tx_info.gas_price.unwrap_or_default(); let gas_used = (tx_fees.tip.saturating_add(tx_fees.actual_fee)) .checked_div(gas_price.as_u128()) .unwrap_or_default(); let success = events.has::()?; let transaction_index = ext.index(); - let transaction_hash = BlakeTwo256::hash(&Vec::from(ext.bytes()).encode()); let block_hash = block.hash(); let block_number = block.number().into(); - let receipt = ReceiptInfo { + // get logs from ContractEmitted event + let logs = events.iter() + .filter_map(|event_details| { + let event_details = event_details.ok()?; + let event = event_details.as_event::().ok()??; + + Some(Log { + address: event.contract, + topics: event.topics, + data: Some(event.data.into()), + block_number: Some(block_number), + transaction_hash, + transaction_index: Some(transaction_index.into()), + block_hash: Some(block_hash), + log_index: Some(event_details.index().into()), + ..Default::default() + }) + }).collect(); + + + log::debug!(target: LOG_TARGET, "Adding receipt for tx hash: {transaction_hash:?} - block: {block_number:?}"); + let receipt = ReceiptInfo::new( block_hash, block_number, contract_address, from, - to: tx.transaction_legacy_unsigned.to, - effective_gas_price: gas_price, - gas_used: gas_used.into(), - status: Some(if success { U256::one() } else { U256::zero() }), + logs, + tx_info.to, + gas_price, + gas_used.into(), + success, transaction_hash, - transaction_index: transaction_index.into(), - ..Default::default() - }; + transaction_index.into(), + tx_info.r#type.unwrap_or_default() + ); - Ok::<_, ClientError>((receipt.transaction_hash, (tx.into(), receipt))) + Ok::<_, ClientError>((receipt.transaction_hash, (signed_tx, receipt))) }) .buffer_unordered(10) .collect::>>() @@ -319,13 +385,6 @@ async fn max_block_weight(api: &OnlineClient) -> Result) -> Result { - let query = subxt_client::constants().revive().native_to_eth_ratio(); - let ratio = api.constants().at(&query)?; - Ok(U256::from(ratio)) -} - /// Extract the block timestamp. async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { let extrinsics = block.extrinsics().await.ok()?; @@ -350,7 +409,6 @@ impl Client { let (tx, mut updates) = tokio::sync::watch::channel(()); spawn_handle.spawn("subscribe-blocks", None, Self::subscribe_blocks(inner.clone(), tx)); - spawn_handle.spawn("subscribe-reconnect", None, Self::subscribe_reconnect(inner.clone())); updates.changed().await.expect("tx is not dropped"); Ok(Self { inner, updates }) @@ -408,18 +466,6 @@ impl Client { } } - /// Subscribe and log reconnection events. - async fn subscribe_reconnect(inner: Arc) { - let rpc = inner.as_ref().rpc_client.clone(); - loop { - let reconnected = rpc.reconnect_initiated().await; - log::info!(target: LOG_TARGET, "RPC client connection lost"); - let now = std::time::Instant::now(); - reconnected.await; - log::info!(target: LOG_TARGET, "RPC client reconnection took `{}s`", now.elapsed().as_secs()); - } - } - /// Subscribe to new blocks and update the cache. async fn subscribe_blocks(inner: Arc, tx: Sender<()>) { log::info!(target: LOG_TARGET, "Subscribing to new blocks"); @@ -427,7 +473,7 @@ impl Client { Ok(s) => s, Err(err) => { log::error!(target: LOG_TARGET, "Failed to subscribe to blocks: {err:?}"); - return + return; }, }; @@ -444,7 +490,7 @@ impl Client { } log::error!(target: LOG_TARGET, "Failed to fetch block: {err:?}"); - return + return; }, }; @@ -460,7 +506,6 @@ impl Client { .unwrap_or_default(); if !receipts.is_empty() { - log::debug!(target: LOG_TARGET, "Adding {} receipts", receipts.len()); let values = receipts .iter() .map(|(hash, (_, receipt))| (receipt.transaction_index, *hash)) @@ -555,6 +600,12 @@ impl Client { cache.tx_hashes_by_block_and_index.get(block_hash).map(|v| v.len()) } + /// Get the system health. + pub async fn system_health(&self) -> Result { + let health = self.inner.rpc.system_health().await?; + Ok(health) + } + /// Get the balance of the given address. pub async fn balance( &self, @@ -566,8 +617,9 @@ impl Client { let runtime_api = self.runtime_api(at).await?; let payload = subxt_client::apis().revive_api().balance(address); - let balance = runtime_api.call(payload).await?.into(); - Ok(self.inner.native_to_evm_decimals(balance)) + let balance = runtime_api.call(payload).await?; + + Ok(*balance) } /// Get the contract storage for the given contract address and key. @@ -610,44 +662,23 @@ impl Client { Ok(result) } - /// Dry run a transaction and returns the [`EthContractResult`] for the transaction. + /// Dry run a transaction and returns the [`EthTransactInfo`] for the transaction. pub async fn dry_run( &self, - tx: &GenericTransaction, + tx: GenericTransaction, block: BlockNumberOrTagOrHash, - ) -> Result, ClientError> { + ) -> Result, ClientError> { let runtime_api = self.runtime_api(&block).await?; + let payload = subxt_client::apis().revive_api().eth_transact(tx.into()); - let value = self - .inner - .evm_to_native_decimals(tx.value.unwrap_or_default()) - .try_into() - .map_err(|_| ClientError::ConversionFailed)?; - - // TODO: remove once subxt is updated - let from = tx.from.map(|v| v.0.into()); - let to = tx.to.map(|v| v.0.into()); - - let payload = subxt_client::apis().revive_api().eth_transact( - from.unwrap_or_default(), - to, - value, - tx.input.clone().unwrap_or_default().0, - None, - None, - ); - let res = runtime_api.call(payload).await?.0; - Ok(res) - } - - /// Dry run a transaction and returns the gas estimate for the transaction. - pub async fn estimate_gas( - &self, - tx: &GenericTransaction, - block: BlockNumberOrTagOrHash, - ) -> Result { - let dry_run = self.dry_run(tx, block).await?; - Ok(U256::from(dry_run.fee / GAS_PRICE as u128) + GAS_PRICE) + let result = runtime_api.call(payload).await?; + match result { + Err(err) => { + log::debug!(target: LOG_TARGET, "Dry run failed {err:?}"); + Err(ClientError::Reverted(err.0)) + }, + Ok(result) => Ok(result.0), + } } /// Get the nonce of the given address. diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index cdf5ce9d1b98..3b9a33296ef4 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -20,8 +20,7 @@ use crate::{EthRpcClient, ReceiptInfo}; use anyhow::Context; use pallet_revive::evm::{ - rlp::*, Account, BlockTag, Bytes, GenericTransaction, TransactionLegacyUnsigned, H160, H256, - U256, + Account, BlockTag, Bytes, GenericTransaction, TransactionLegacyUnsigned, H160, H256, U256, }; /// Wait for a transaction receipt. @@ -40,57 +39,152 @@ pub async fn wait_for_receipt( anyhow::bail!("Failed to get receipt") } -/// Send a transaction. -pub async fn send_transaction( - signer: &Account, +/// Wait for a successful transaction receipt. +pub async fn wait_for_successful_receipt( client: &(impl EthRpcClient + Send + Sync), + hash: H256, +) -> anyhow::Result { + let receipt = wait_for_receipt(client, hash).await?; + if receipt.is_success() { + Ok(receipt) + } else { + anyhow::bail!("Transaction failed") + } +} + +/// Transaction builder. +pub struct TransactionBuilder { + signer: Account, value: U256, input: Bytes, to: Option, -) -> anyhow::Result { - let from = signer.address(); - - let chain_id = Some(client.chain_id().await?); - - let gas_price = client.gas_price().await?; - let nonce = client - .get_transaction_count(from, BlockTag::Latest.into()) - .await - .with_context(|| "Failed to fetch account nonce")?; - - let gas = client - .estimate_gas( - GenericTransaction { - from: Some(from), - input: Some(input.clone()), - value: Some(value), - gas_price: Some(gas_price), - to, - ..Default::default() - }, - None, - ) - .await - .with_context(|| "Failed to fetch gas estimate")?; - - let unsigned_tx = TransactionLegacyUnsigned { - gas, - nonce, - to, - value, - input, - gas_price, - chain_id, - ..Default::default() - }; - - let tx = signer.sign_transaction(unsigned_tx.clone()); - let bytes = tx.rlp_bytes().to_vec(); - - let hash = client - .send_raw_transaction(bytes.clone().into()) - .await - .with_context(|| "transaction failed")?; - - Ok(hash) + mutate: Box, +} + +impl Default for TransactionBuilder { + fn default() -> Self { + Self { + signer: Account::default(), + value: U256::zero(), + input: Bytes::default(), + to: None, + mutate: Box::new(|_| {}), + } + } +} + +impl TransactionBuilder { + /// Set the signer. + pub fn signer(mut self, signer: Account) -> Self { + self.signer = signer; + self + } + + /// Set the value. + pub fn value(mut self, value: U256) -> Self { + self.value = value; + self + } + + /// Set the input. + pub fn input(mut self, input: Vec) -> Self { + self.input = Bytes(input); + self + } + + /// Set the destination. + pub fn to(mut self, to: H160) -> Self { + self.to = Some(to); + self + } + + /// Set a mutation function, that mutates the transaction before sending. + pub fn mutate(mut self, mutate: impl FnOnce(&mut TransactionLegacyUnsigned) + 'static) -> Self { + self.mutate = Box::new(mutate); + self + } + + /// Call eth_call to get the result of a view function + pub async fn eth_call( + self, + client: &(impl EthRpcClient + Send + Sync), + ) -> anyhow::Result> { + let TransactionBuilder { signer, value, input, to, .. } = self; + + let from = signer.address(); + let result = client + .call( + GenericTransaction { + from: Some(from), + input: Some(input.clone()), + value: Some(value), + to, + ..Default::default() + }, + None, + ) + .await + .with_context(|| "eth_call failed")?; + Ok(result.0) + } + + /// Send the transaction. + pub async fn send(self, client: &(impl EthRpcClient + Send + Sync)) -> anyhow::Result { + let TransactionBuilder { signer, value, input, to, mutate } = self; + + let from = signer.address(); + let chain_id = Some(client.chain_id().await?); + let gas_price = client.gas_price().await?; + let nonce = client + .get_transaction_count(from, BlockTag::Latest.into()) + .await + .with_context(|| "Failed to fetch account nonce")?; + + let gas = client + .estimate_gas( + GenericTransaction { + from: Some(from), + input: Some(input.clone()), + value: Some(value), + gas_price: Some(gas_price), + to, + ..Default::default() + }, + None, + ) + .await + .with_context(|| "Failed to fetch gas estimate")?; + + let mut unsigned_tx = TransactionLegacyUnsigned { + gas, + nonce, + to, + value, + input, + gas_price, + chain_id, + ..Default::default() + }; + + mutate(&mut unsigned_tx); + + let tx = signer.sign_transaction(unsigned_tx.into()); + let bytes = tx.signed_payload(); + + let hash = client + .send_raw_transaction(bytes.into()) + .await + .with_context(|| "transaction failed")?; + + Ok(hash) + } + + /// Send the transaction and wait for the receipt. + pub async fn send_and_wait_for_receipt( + self, + client: &(impl EthRpcClient + Send + Sync), + ) -> anyhow::Result { + let hash = self.send(client).await?; + wait_for_successful_receipt(client, hash).await + } } diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index a6d47063ef90..ccd8bb043e90 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -23,8 +23,8 @@ use jsonrpsee::{ core::{async_trait, RpcResult}, types::{ErrorCode, ErrorObjectOwned}, }; -use pallet_revive::{evm::*, EthContractResult}; -use sp_core::{H160, H256, U256}; +use pallet_revive::evm::*; +use sp_core::{keccak_256, H160, H256, U256}; use thiserror::Error; pub mod cli; @@ -35,6 +35,9 @@ pub mod subxt_client; #[cfg(test)] mod tests; +mod rpc_health; +pub use rpc_health::*; + mod rpc_methods_gen; pub use rpc_methods_gen::*; @@ -88,13 +91,13 @@ pub enum EthRpcError { TransactionTypeNotSupported(Byte), } +// TODO use https://eips.ethereum.org/EIPS/eip-1474#error-codes impl From for ErrorObjectOwned { fn from(value: EthRpcError) -> Self { - let code = match value { - EthRpcError::ClientError(_) => ErrorCode::InternalError, - _ => ErrorCode::InvalidRequest, - }; - Self::owned::(code.code(), value.to_string(), None) + match value { + EthRpcError::ClientError(err) => Self::from(err), + _ => Self::owned::(ErrorCode::InvalidRequest.code(), value.to_string(), None), + } } } @@ -118,20 +121,35 @@ impl EthRpcServer for EthRpcServerImpl { transaction_hash: H256, ) -> RpcResult> { let receipt = self.client.receipt(&transaction_hash).await; + log::debug!(target: LOG_TARGET, "transaction_receipt for {transaction_hash:?}: {}", receipt.is_some()); Ok(receipt) } async fn estimate_gas( &self, transaction: GenericTransaction, - _block: Option, + block: Option, ) -> RpcResult { - let result = self.client.estimate_gas(&transaction, BlockTag::Latest.into()).await?; - Ok(result) + let dry_run = self.client.dry_run(transaction, block.unwrap_or_default().into()).await?; + Ok(dry_run.eth_gas) + } + + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult { + let dry_run = self + .client + .dry_run(transaction, block.unwrap_or_else(|| BlockTag::Latest.into())) + .await?; + Ok(dry_run.data.into()) } async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult { - let tx = rlp::decode::(&transaction.0).map_err(|err| { + let hash = H256(keccak_256(&transaction.0)); + + let tx = TransactionSigned::decode(&transaction.0).map_err(|err| { log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); EthRpcError::from(err) })?; @@ -141,37 +159,28 @@ impl EthRpcServer for EthRpcServerImpl { EthRpcError::InvalidSignature })?; + let tx = GenericTransaction::from_signed(tx, Some(eth_addr)); + // Dry run the transaction to get the weight limit and storage deposit limit - let TransactionLegacyUnsigned { to, input, value, .. } = tx.transaction_legacy_unsigned; - let dry_run = self - .client - .dry_run( - &GenericTransaction { - from: Some(eth_addr), - input: Some(input.clone()), - to, - value: Some(value), - ..Default::default() - }, - BlockTag::Latest.into(), - ) - .await?; + let dry_run = self.client.dry_run(tx, BlockTag::Latest.into()).await?; - let EthContractResult { gas_required, storage_deposit, .. } = dry_run; let call = subxt_client::tx().revive().eth_transact( transaction.0, - gas_required.into(), - storage_deposit, + dry_run.gas_required.into(), + dry_run.storage_deposit, ); - let hash = self.client.submit(call).await?; + self.client.submit(call).await.map_err(|err| { + log::debug!(target: LOG_TARGET, "submit call failed: {err:?}"); + err + })?; + log::debug!(target: LOG_TARGET, "send_raw_transaction hash: {hash:?}"); Ok(hash) } - async fn send_transaction(&self, transaction: GenericTransaction) -> RpcResult { + async fn send_transaction(&self, mut transaction: GenericTransaction) -> RpcResult { log::debug!(target: LOG_TARGET, "{transaction:#?}"); - let GenericTransaction { from, gas, gas_price, input, to, value, r#type, .. } = transaction; - let Some(from) = from else { + let Some(from) = transaction.from else { log::debug!(target: LOG_TARGET, "Transaction must have a sender"); return Err(EthRpcError::InvalidTransaction.into()); }; @@ -182,27 +191,26 @@ impl EthRpcServer for EthRpcServerImpl { .find(|account| account.address() == from) .ok_or(EthRpcError::AccountNotFound(from))?; - let gas_price = gas_price.unwrap_or_else(|| U256::from(GAS_PRICE)); - let chain_id = Some(self.client.chain_id().into()); - let input = input.unwrap_or_default(); - let value = value.unwrap_or_default(); - let r#type = r#type.unwrap_or_default(); + if transaction.gas.is_none() { + transaction.gas = Some(self.estimate_gas(transaction.clone(), None).await?); + } - let Some(gas) = gas else { - log::debug!(target: LOG_TARGET, "Transaction must have a gas limit"); - return Err(EthRpcError::InvalidTransaction.into()); - }; + if transaction.gas_price.is_none() { + transaction.gas_price = Some(self.gas_price().await?); + } - let r#type = Type0::try_from_byte(r#type.clone()) - .map_err(|_| EthRpcError::TransactionTypeNotSupported(r#type))?; + if transaction.nonce.is_none() { + transaction.nonce = + Some(self.get_transaction_count(from, BlockTag::Latest.into()).await?); + } - let nonce = self.get_transaction_count(from, BlockTag::Latest.into()).await?; + if transaction.chain_id.is_none() { + transaction.chain_id = Some(self.chain_id().await?); + } - let tx = - TransactionLegacyUnsigned { chain_id, gas, gas_price, input, nonce, to, value, r#type }; - let tx = account.sign_transaction(tx); - let rlp_bytes = rlp::encode(&tx).to_vec(); - self.send_raw_transaction(Bytes(rlp_bytes)).await + let tx = transaction.try_into_unsigned().map_err(|_| EthRpcError::InvalidTransaction)?; + let payload = account.sign_transaction(tx).signed_payload(); + self.send_raw_transaction(Bytes(payload)).await } async fn get_block_by_hash( @@ -240,23 +248,6 @@ impl EthRpcServer for EthRpcServerImpl { Ok(self.accounts.iter().map(|account| account.address()).collect()) } - async fn call( - &self, - transaction: GenericTransaction, - block: Option, - ) -> RpcResult { - let dry_run = self - .client - .dry_run(&transaction, block.unwrap_or_else(|| BlockTag::Latest.into())) - .await?; - let output = dry_run.result.map_err(|err| { - log::debug!(target: LOG_TARGET, "Dry run failed: {err:?}"); - ClientError::DryRunFailed - })?; - - Ok(output.into()) - } - async fn get_block_by_number( &self, block: BlockNumberOrTag, diff --git a/substrate/frame/revive/rpc/src/rpc_health.rs b/substrate/frame/revive/rpc/src/rpc_health.rs new file mode 100644 index 000000000000..f94d4b82a80f --- /dev/null +++ b/substrate/frame/revive/rpc/src/rpc_health.rs @@ -0,0 +1,50 @@ +// 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. +//! Heatlh JSON-RPC methods. + +use super::*; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sc_rpc_api::system::helpers::Health; + +#[rpc(server, client)] +pub trait SystemHealthRpc { + /// Proxy the substrate chain system_health RPC call. + #[method(name = "system_health")] + async fn system_health(&self) -> RpcResult; +} + +pub struct SystemHealthRpcServerImpl { + client: client::Client, +} + +impl SystemHealthRpcServerImpl { + pub fn new(client: client::Client) -> Self { + Self { client } + } +} + +#[async_trait] +impl SystemHealthRpcServer for SystemHealthRpcServerImpl { + async fn system_health(&self) -> RpcResult { + let health = self.client.system_health().await?; + Ok(Health { + peers: health.peers, + is_syncing: health.is_syncing, + should_have_peers: health.should_have_peers, + }) + } +} diff --git a/substrate/frame/revive/rpc/src/rpc_methods_gen.rs b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs index 339080368969..ad34dbfdfb49 100644 --- a/substrate/frame/revive/rpc/src/rpc_methods_gen.rs +++ b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs @@ -14,6 +14,7 @@ // 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. + //! Generated JSON-RPC methods. #![allow(missing_docs)] diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs index cb2737beae70..1e1c395028a4 100644 --- a/substrate/frame/revive/rpc/src/subxt_client.rs +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -21,9 +21,26 @@ use subxt::config::{signed_extensions, Config, PolkadotConfig}; #[subxt::subxt( runtime_metadata_path = "revive_chain.metadata", + // TODO remove once subxt use the same U256 type substitute_type( - path = "pallet_revive::primitives::EthContractResult", - with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" + path = "primitive_types::U256", + with = "::subxt::utils::Static<::sp_core::U256>" + ), + substitute_type( + path = "pallet_revive::evm::api::rpc_types_gen::GenericTransaction", + with = "::subxt::utils::Static<::pallet_revive::evm::GenericTransaction>" + ), + substitute_type( + path = "pallet_revive::primitives::EthTransactInfo", + with = "::subxt::utils::Static<::pallet_revive::EthTransactInfo>" + ), + substitute_type( + path = "pallet_revive::primitives::EthTransactError", + with = "::subxt::utils::Static<::pallet_revive::EthTransactError>" + ), + substitute_type( + path = "pallet_revive::primitives::ExecReturnValue", + with = "::subxt::utils::Static<::pallet_revive::ExecReturnValue>" ), substitute_type( path = "sp_weights::weight_v2::Weight", diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 01fcb6ae3bd2..43b600c33d78 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -18,21 +18,23 @@ use crate::{ cli::{self, CliCommand}, - example::{send_transaction, wait_for_receipt}, + example::{wait_for_successful_receipt, TransactionBuilder}, EthRpcClient, }; use clap::Parser; +use ethabi::Token; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use pallet_revive::{ create1, - evm::{Account, BlockTag, Bytes, U256}, + evm::{Account, BlockTag, U256}, }; +use static_init::dynamic; use std::thread; use substrate_cli_test_utils::*; -/// Create a websocket client with a 30s timeout. +/// Create a websocket client with a 120s timeout. async fn ws_client_with_retry(url: &str) -> WsClient { - let timeout = tokio::time::Duration::from_secs(30); + let timeout = tokio::time::Duration::from_secs(120); tokio::time::timeout(timeout, async { loop { if let Ok(client) = WsClientBuilder::default().build(url).await { @@ -46,56 +48,126 @@ async fn ws_client_with_retry(url: &str) -> WsClient { .expect("Hit timeout") } -#[tokio::test] -async fn test_jsonrpsee_server() -> anyhow::Result<()> { - // Start the node. - let _ = thread::spawn(move || { - if let Err(e) = start_node_inline(vec![ +fn get_contract(name: &str) -> anyhow::Result<(Vec, ethabi::Contract)> { + let pvm_dir: std::path::PathBuf = "./examples/js/pvm".into(); + let abi_dir: std::path::PathBuf = "./examples/js/abi".into(); + let bytecode = std::fs::read(pvm_dir.join(format!("{}.polkavm", name)))?; + + let abi = std::fs::read(abi_dir.join(format!("{}.json", name)))?; + let contract = ethabi::Contract::load(abi.as_slice())?; + + Ok((bytecode, contract)) +} + +struct SharedResources { + _node_handle: std::thread::JoinHandle<()>, + _rpc_handle: std::thread::JoinHandle<()>, +} + +impl SharedResources { + fn start() -> Self { + // Start the node. + let _node_handle = thread::spawn(move || { + if let Err(e) = start_node_inline(vec![ + "--dev", + "--rpc-port=45789", + "--no-telemetry", + "--no-prometheus", + "-lerror,evm=debug,sc_rpc_server=info,runtime::revive=trace", + ]) { + panic!("Node exited with error: {e:?}"); + } + }); + + // Start the rpc server. + let args = CliCommand::parse_from([ "--dev", - "--rpc-port=45789", - "--no-telemetry", + "--rpc-port=45788", + "--node-rpc-url=ws://localhost:45789", "--no-prometheus", - "-lerror,evm=debug,sc_rpc_server=info,runtime::revive=debug", - ]) { - panic!("Node exited with error: {e:?}"); - } - }); - - // Start the rpc server. - let args = CliCommand::parse_from([ - "--dev", - "--rpc-port=45788", - "--node-rpc-url=ws://localhost:45789", - "--no-prometheus", - "-linfo,eth-rpc=debug", - ]); - let _ = thread::spawn(move || { - if let Err(e) = cli::run(args) { - panic!("eth-rpc exited with error: {e:?}"); + "-linfo,eth-rpc=debug", + ]); + + let _rpc_handle = thread::spawn(move || { + if let Err(e) = cli::run(args) { + panic!("eth-rpc exited with error: {e:?}"); + } + }); + + Self { _node_handle, _rpc_handle } + } + + async fn client() -> WsClient { + ws_client_with_retry("ws://localhost:45788").await + } +} + +#[dynamic(lazy)] +static mut SHARED_RESOURCES: SharedResources = SharedResources::start(); + +macro_rules! unwrap_call_err( + ($err:expr) => { + match $err.downcast_ref::().unwrap() { + jsonrpsee::core::client::Error::Call(call) => call, + _ => panic!("Expected Call error"), } - }); + } +); - let client = ws_client_with_retry("ws://localhost:45788").await; +#[tokio::test] +async fn transfer() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + + let ethan = Account::from(subxt_signer::eth::dev::ethan()); + let initial_balance = client.get_balance(ethan.address(), BlockTag::Latest.into()).await?; + + let value = 1_000_000_000_000_000_000_000u128.into(); + let hash = TransactionBuilder::default() + .value(value) + .to(ethan.address()) + .send(&client) + .await?; + + let receipt = wait_for_successful_receipt(&client, hash).await?; + assert_eq!( + Some(ethan.address()), + receipt.to, + "Receipt should have the correct contract address." + ); + + let increase = + client.get_balance(ethan.address(), BlockTag::Latest.into()).await? - initial_balance; + assert_eq!(value, increase); + Ok(()) +} + +#[tokio::test] +async fn deploy_and_call() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; let account = Account::default(); // Balance transfer let ethan = Account::from(subxt_signer::eth::dev::ethan()); - let ethan_balance = client.get_balance(ethan.address(), BlockTag::Latest.into()).await?; - assert_eq!(U256::zero(), ethan_balance); + let initial_balance = client.get_balance(ethan.address(), BlockTag::Latest.into()).await?; let value = 1_000_000_000_000_000_000_000u128.into(); - let hash = - send_transaction(&account, &client, value, Bytes::default(), Some(ethan.address())).await?; + let hash = TransactionBuilder::default() + .value(value) + .to(ethan.address()) + .send(&client) + .await?; - let receipt = wait_for_receipt(&client, hash).await?; + let receipt = wait_for_successful_receipt(&client, hash).await?; assert_eq!( Some(ethan.address()), receipt.to, "Receipt should have the correct contract address." ); - let ethan_balance = client.get_balance(ethan.address(), BlockTag::Latest.into()).await?; - assert_eq!(value, ethan_balance, "ethan's balance should be the same as the value sent."); + let updated_balance = client.get_balance(ethan.address(), BlockTag::Latest.into()).await?; + assert_eq!(value, updated_balance - initial_balance); // Deploy contract let data = b"hello world".to_vec(); @@ -103,8 +175,8 @@ async fn test_jsonrpsee_server() -> anyhow::Result<()> { let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; let input = bytes.into_iter().chain(data.clone()).collect::>(); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; - let hash = send_transaction(&account, &client, value, input.into(), None).await?; - let receipt = wait_for_receipt(&client, hash).await?; + let hash = TransactionBuilder::default().value(value).input(input).send(&client).await?; + let receipt = wait_for_successful_receipt(&client, hash).await?; let contract_address = create1(&account.address(), nonce.try_into().unwrap()); assert_eq!( Some(contract_address), @@ -116,15 +188,135 @@ async fn test_jsonrpsee_server() -> anyhow::Result<()> { assert_eq!(value, balance, "Contract balance should be the same as the value sent."); // Call contract - let hash = - send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) - .await?; - let receipt = wait_for_receipt(&client, hash).await?; + let hash = TransactionBuilder::default() + .value(value) + .to(contract_address) + .send(&client) + .await?; + let receipt = wait_for_successful_receipt(&client, hash).await?; + assert_eq!( Some(contract_address), receipt.to, "Receipt should have the correct contract address." ); + let increase = client.get_balance(contract_address, BlockTag::Latest.into()).await? - balance; + assert_eq!(value, increase, "contract's balance should have increased by the value sent."); + + // Balance transfer to contract + let balance = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + let hash = TransactionBuilder::default() + .value(value) + .to(contract_address) + .send(&client) + .await?; + + wait_for_successful_receipt(&client, hash).await?; + let increase = client.get_balance(contract_address, BlockTag::Latest.into()).await? - balance; + assert_eq!(value, increase, "contract's balance should have increased by the value sent."); + Ok(()) +} + +#[tokio::test] +async fn revert_call() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + let (bytecode, contract) = get_contract("ErrorTester")?; + let receipt = TransactionBuilder::default() + .input(bytecode) + .send_and_wait_for_receipt(&client) + .await?; + + let err = TransactionBuilder::default() + .to(receipt.contract_address.unwrap()) + .input(contract.function("triggerRequireError")?.encode_input(&[])?.to_vec()) + .send(&client) + .await + .unwrap_err(); + + let call_err = unwrap_call_err!(err.source().unwrap()); + assert_eq!(call_err.message(), "execution reverted: This is a require error"); + assert_eq!(call_err.code(), 3); + Ok(()) +} + +#[tokio::test] +async fn event_logs() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + let (bytecode, contract) = get_contract("EventExample")?; + let receipt = TransactionBuilder::default() + .input(bytecode) + .send_and_wait_for_receipt(&client) + .await?; + + let receipt = TransactionBuilder::default() + .to(receipt.contract_address.unwrap()) + .input(contract.function("triggerEvent")?.encode_input(&[])?.to_vec()) + .send_and_wait_for_receipt(&client) + .await?; + assert_eq!(receipt.logs.len(), 1, "There should be one log."); + Ok(()) +} + +#[tokio::test] +async fn invalid_transaction() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + let ethan = Account::from(subxt_signer::eth::dev::ethan()); + + let err = TransactionBuilder::default() + .value(U256::from(1_000_000_000_000u128)) + .to(ethan.address()) + .mutate(|tx| tx.chain_id = Some(42u32.into())) + .send(&client) + .await + .unwrap_err(); + + let call_err = unwrap_call_err!(err.source().unwrap()); + assert_eq!(call_err.message(), "Invalid Transaction"); + + Ok(()) +} + +#[tokio::test] +async fn native_evm_ratio_works() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + let (bytecode, contract) = get_contract("PiggyBank")?; + let contract_address = TransactionBuilder::default() + .input(bytecode) + .send_and_wait_for_receipt(&client) + .await? + .contract_address + .unwrap(); + + let value = 10_000_000_000_000_000_000u128; // 10 eth + TransactionBuilder::default() + .to(contract_address) + .input(contract.function("deposit")?.encode_input(&[])?.to_vec()) + .value(value.into()) + .send_and_wait_for_receipt(&client) + .await?; + + let contract_value = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + assert_eq!(contract_value, value.into()); + + let withdraw_value = 1_000_000_000_000_000_000u128; // 1 eth + TransactionBuilder::default() + .to(contract_address) + .input( + contract + .function("withdraw")? + .encode_input(&[Token::Uint(withdraw_value.into())])? + .to_vec(), + ) + .send_and_wait_for_receipt(&client) + .await?; + + let contract_value = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + assert_eq!(contract_value, (value - withdraw_value).into()); + Ok(()) } diff --git a/substrate/frame/revive/src/benchmarking/call_builder.rs b/substrate/frame/revive/src/benchmarking/call_builder.rs index c666383abb2f..1177d47aadc3 100644 --- a/substrate/frame/revive/src/benchmarking/call_builder.rs +++ b/substrate/frame/revive/src/benchmarking/call_builder.rs @@ -21,7 +21,7 @@ use crate::{ exec::{ExportedFunction, Ext, Key, Stack}, storage::meter::Meter, transient_storage::MeterEntry, - wasm::{ApiVersion, PreparedCall, Runtime}, + wasm::{PreparedCall, Runtime}, BalanceOf, Config, DebugBuffer, Error, GasMeter, MomentOf, Origin, WasmBlob, Weight, }; use alloc::{vec, vec::Vec}; @@ -45,7 +45,7 @@ pub struct CallSetup { impl Default for CallSetup where - T: Config + pallet_balances::Config, + T: Config, BalanceOf: Into + TryFrom, MomentOf: Into, T::Hash: frame_support::traits::IsType, @@ -57,7 +57,7 @@ where impl CallSetup where - T: Config + pallet_balances::Config, + T: Config, BalanceOf: Into + TryFrom, MomentOf: Into, T::Hash: frame_support::traits::IsType, @@ -164,13 +164,7 @@ where module: WasmBlob, input: Vec, ) -> PreparedCall<'a, StackExt<'a, T>> { - module - .prepare_call( - Runtime::new(ext, input), - ExportedFunction::Call, - ApiVersion::UnsafeNewest, - ) - .unwrap() + module.prepare_call(Runtime::new(ext, input), ExportedFunction::Call).unwrap() } /// Add transient_storage diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 3d1d7d2a224a..e67c39ec0899 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -23,6 +23,7 @@ mod call_builder; mod code; use self::{call_builder::CallSetup, code::WasmModule}; use crate::{ + evm::runtime::GAS_PRICE, exec::{Key, MomentOf}, limits, storage::WriteOutcome, @@ -34,11 +35,10 @@ use frame_benchmarking::v2::*; use frame_support::{ self, assert_ok, storage::child, - traits::{fungible::InspectHold, Currency}, + traits::fungible::InspectHold, weights::{Weight, WeightMeter}, }; use frame_system::RawOrigin; -use pallet_balances; use pallet_revive_uapi::{CallFlags, ReturnErrorCode, StorageFlags}; use sp_runtime::traits::{Bounded, Hash}; @@ -68,7 +68,7 @@ struct Contract { impl Contract where - T: Config + pallet_balances::Config, + T: Config, BalanceOf: Into + TryFrom, MomentOf: Into, T::Hash: frame_support::traits::IsType, @@ -103,7 +103,7 @@ where origin, 0u32.into(), Weight::MAX, - default_deposit_limit::(), + DepositLimit::Balance(default_deposit_limit::()), Code::Upload(module.code), data, salt, @@ -169,7 +169,7 @@ where }; if key == &key_new { - continue + continue; } child::put_raw(&child_trie_info, &key_new, &value); } @@ -220,11 +220,10 @@ fn default_deposit_limit() -> BalanceOf { #[benchmarks( where BalanceOf: Into + TryFrom, - T: Config + pallet_balances::Config, + T: Config, MomentOf: Into, ::RuntimeEvent: From>, ::RuntimeCall: From>, - as Currency>::Balance: From>, ::Hash: frame_support::traits::IsType, )] mod benchmarks { @@ -364,10 +363,10 @@ mod benchmarks { // We just call a dummy contract to measure the overhead of the call extrinsic. // The size of the data has no influence on the costs of this extrinsic as long as the contract - // won't call `seal_input` in its constructor to copy the data to contract memory. + // won't call `seal_call_data_copy` in its constructor to copy the data to contract memory. // The dummy contract used here does not do this. The costs for the data copy is billed as - // part of `seal_input`. The costs for invoking a contract of a specific size are not part - // of this benchmark because we cannot know the size of the contract when issuing a call + // part of `seal_call_data_copy`. The costs for invoking a contract of a specific size are not + // part of this benchmark because we cannot know the size of the contract when issuing a call // transaction. See `call_with_code_per_byte` for this. #[benchmark(pov_mode = Measured)] fn call() -> Result<(), BenchmarkError> { @@ -598,19 +597,15 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn seal_code_size() { let contract = Contract::::with_index(1, WasmModule::dummy(), vec![]).unwrap(); - build_runtime!(runtime, memory: [contract.address.encode(), vec![0u8; 32], ]); + build_runtime!(runtime, memory: [contract.address.encode(),]); let result; #[block] { - result = runtime.bench_code_size(memory.as_mut_slice(), 0, 20); + result = runtime.bench_code_size(memory.as_mut_slice(), 0); } - assert_ok!(result); - assert_eq!( - U256::from_little_endian(&memory[20..]), - U256::from(WasmModule::dummy().code.len()) - ); + assert_eq!(result.unwrap(), WasmModule::dummy().code.len() as u64); } #[benchmark(pov_mode = Measured)] @@ -673,6 +668,18 @@ mod benchmarks { ); } + #[benchmark(pov_mode = Measured)] + fn seal_ref_time_left() { + build_runtime!(runtime, memory: [vec![], ]); + + let result; + #[block] + { + result = runtime.bench_ref_time_left(memory.as_mut_slice()); + } + assert_eq!(result.unwrap(), runtime.ext().gas_meter().gas_left().ref_time()); + } + #[benchmark(pov_mode = Measured)] fn seal_balance() { build_runtime!(runtime, memory: [[0u8;32], ]); @@ -773,6 +780,70 @@ mod benchmarks { assert_eq!(U256::from_little_endian(&memory[..]), runtime.ext().minimum_balance()); } + #[benchmark(pov_mode = Measured)] + fn seal_return_data_size() { + let mut setup = CallSetup::::default(); + let (mut ext, _) = setup.ext(); + let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]); + let mut memory = memory!(vec![],); + *runtime.ext().last_frame_output_mut() = + ExecReturnValue { data: vec![42; 256], ..Default::default() }; + let result; + #[block] + { + result = runtime.bench_return_data_size(memory.as_mut_slice()); + } + assert_eq!(result.unwrap(), 256); + } + + #[benchmark(pov_mode = Measured)] + fn seal_call_data_size() { + let mut setup = CallSetup::::default(); + let (mut ext, _) = setup.ext(); + let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![42u8; 128 as usize]); + let mut memory = memory!(vec![0u8; 4],); + let result; + #[block] + { + result = runtime.bench_call_data_size(memory.as_mut_slice()); + } + assert_eq!(result.unwrap(), 128); + } + + #[benchmark(pov_mode = Measured)] + fn seal_gas_limit() { + build_runtime!(runtime, memory: []); + let result; + #[block] + { + result = runtime.bench_gas_limit(&mut memory); + } + assert_eq!(result.unwrap(), T::BlockWeights::get().max_block.ref_time()); + } + + #[benchmark(pov_mode = Measured)] + fn seal_gas_price() { + build_runtime!(runtime, memory: []); + let result; + #[block] + { + result = runtime.bench_gas_price(memory.as_mut_slice()); + } + assert_eq!(result.unwrap(), u64::from(GAS_PRICE)); + } + + #[benchmark(pov_mode = Measured)] + fn seal_base_fee() { + build_runtime!(runtime, memory: [[1u8;32], ]); + let result; + #[block] + { + result = runtime.bench_base_fee(memory.as_mut_slice(), 0); + } + assert_ok!(result); + assert_eq!(U256::from_little_endian(&memory[..]), U256::zero()); + } + #[benchmark(pov_mode = Measured)] fn seal_block_number() { build_runtime!(runtime, memory: [[0u8;32], ]); @@ -841,20 +912,58 @@ mod benchmarks { } #[benchmark(pov_mode = Measured)] - fn seal_input(n: Linear<0, { limits::code::BLOB_BYTES - 4 }>) { + fn seal_copy_to_contract(n: Linear<0, { limits::code::BLOB_BYTES - 4 }>) { let mut setup = CallSetup::::default(); let (mut ext, _) = setup.ext(); - let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![42u8; n as usize]); - let mut memory = memory!(n.to_le_bytes(), vec![0u8; n as usize],); + let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]); + let mut memory = memory!(n.encode(), vec![0u8; n as usize],); let result; #[block] { - result = runtime.bench_input(memory.as_mut_slice(), 4, 0); + result = runtime.write_sandbox_output( + memory.as_mut_slice(), + 4, + 0, + &vec![42u8; n as usize], + false, + |_| None, + ); } assert_ok!(result); + assert_eq!(&memory[..4], &n.encode()); assert_eq!(&memory[4..], &vec![42u8; n as usize]); } + #[benchmark(pov_mode = Measured)] + fn seal_call_data_load() { + let mut setup = CallSetup::::default(); + let (mut ext, _) = setup.ext(); + let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![42u8; 32]); + let mut memory = memory!(vec![0u8; 32],); + let result; + #[block] + { + result = runtime.bench_call_data_load(memory.as_mut_slice(), 0, 0); + } + assert_ok!(result); + assert_eq!(&memory[..], &vec![42u8; 32]); + } + + #[benchmark(pov_mode = Measured)] + fn seal_call_data_copy(n: Linear<0, { limits::code::BLOB_BYTES }>) { + let mut setup = CallSetup::::default(); + let (mut ext, _) = setup.ext(); + let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![42u8; n as usize]); + let mut memory = memory!(vec![0u8; n as usize],); + let result; + #[block] + { + result = runtime.bench_call_data_copy(memory.as_mut_slice(), 0, n, 0); + } + assert_ok!(result); + assert_eq!(&memory[..], &vec![42u8; n as usize]); + } + #[benchmark(pov_mode = Measured)] fn seal_return(n: Linear<0, { limits::code::BLOB_BYTES - 4 }>) { build_runtime!(runtime, memory: [n.to_le_bytes(), vec![42u8; n as usize], ]); @@ -1507,36 +1616,6 @@ mod benchmarks { Ok(()) } - // We transfer to unique accounts. - #[benchmark(pov_mode = Measured)] - fn seal_transfer() { - let account = account::("receiver", 0, 0); - let value = Pallet::::min_balance(); - assert!(value > 0u32.into()); - - let mut setup = CallSetup::::default(); - setup.set_balance(value); - let (mut ext, _) = setup.ext(); - let mut runtime = crate::wasm::Runtime::<_, [u8]>::new(&mut ext, vec![]); - - let account_bytes = account.encode(); - let account_len = account_bytes.len() as u32; - let value_bytes = Into::::into(value).encode(); - let mut memory = memory!(account_bytes, value_bytes,); - - let result; - #[block] - { - result = runtime.bench_transfer( - memory.as_mut_slice(), - 0, // account_ptr - account_len, // value_ptr - ); - } - - assert_ok!(result); - } - // t: with or without some value to transfer // i: size of the input data #[benchmark(pov_mode = Measured)] @@ -1546,7 +1625,7 @@ mod benchmarks { let callee_bytes = callee.encode(); let callee_len = callee_bytes.len() as u32; - let value: BalanceOf = t.into(); + let value: BalanceOf = (1_000_000 * t).into(); let value_bytes = Into::::into(value).encode(); let deposit: BalanceOf = (u32::MAX - 100).into(); @@ -1585,25 +1664,36 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn seal_delegate_call() -> Result<(), BenchmarkError> { - let hash = Contract::::with_index(1, WasmModule::dummy(), vec![])?.info()?.code_hash; + let Contract { account_id: address, .. } = + Contract::::with_index(1, WasmModule::dummy(), vec![]).unwrap(); + + let address_bytes = address.encode(); + let address_len = address_bytes.len() as u32; + + let deposit: BalanceOf = (u32::MAX - 100).into(); + let deposit_bytes = Into::::into(deposit).encode(); let mut setup = CallSetup::::default(); + setup.set_storage_deposit_limit(deposit); setup.set_origin(Origin::from_account_id(setup.contract().account_id.clone())); let (mut ext, _) = setup.ext(); let mut runtime = crate::wasm::Runtime::<_, [u8]>::new(&mut ext, vec![]); - let mut memory = memory!(hash.encode(),); + let mut memory = memory!(address_bytes, deposit_bytes,); let result; #[block] { result = runtime.bench_delegate_call( memory.as_mut_slice(), - 0, // flags - 0, // code_hash_ptr - 0, // input_data_ptr - 0, // input_data_len - SENTINEL, // output_ptr + 0, // flags + 0, // address_ptr + 0, // ref_time_limit + 0, // proof_size_limit + address_len, // deposit_ptr + 0, // input_data_ptr + 0, // input_data_len + SENTINEL, // output_ptr 0, ); } @@ -1621,7 +1711,7 @@ mod benchmarks { let hash_bytes = hash.encode(); let hash_len = hash_bytes.len() as u32; - let value: BalanceOf = 1u32.into(); + let value: BalanceOf = 1_000_000u32.into(); let value_bytes = Into::::into(value).encode(); let value_len = value_bytes.len() as u32; @@ -1675,7 +1765,10 @@ mod benchmarks { assert_ok!(result); assert!(ContractInfoOf::::get(&addr).is_some()); - assert_eq!(T::Currency::balance(&account_id), Pallet::::min_balance() + value); + assert_eq!( + T::Currency::balance(&account_id), + Pallet::::min_balance() + Pallet::::convert_evm_to_native(value.into()).unwrap() + ); Ok(()) } diff --git a/substrate/frame/revive/src/chain_extension.rs b/substrate/frame/revive/src/chain_extension.rs index ccea12945054..5b3e886a5628 100644 --- a/substrate/frame/revive/src/chain_extension.rs +++ b/substrate/frame/revive/src/chain_extension.rs @@ -75,7 +75,7 @@ use crate::{ Error, }; use alloc::vec::Vec; -use codec::{Decode, MaxEncodedLen}; +use codec::Decode; use frame_support::weights::Weight; use sp_runtime::DispatchError; @@ -304,16 +304,6 @@ impl<'a, 'b, E: Ext, M: ?Sized + Memory> Environment<'a, 'b, E, M> { Ok(()) } - /// Reads and decodes a type with a size fixed at compile time from contract memory. - /// - /// This function is secure and recommended for all input types of fixed size - /// as long as the cost of reading the memory is included in the overall already charged - /// weight of the chain extension. This should usually be the case when fixed input types - /// are used. - pub fn read_as(&mut self) -> Result { - self.memory.read_as(self.input_ptr) - } - /// Reads and decodes a type with a dynamic size from contract memory. /// /// Make sure to include `len` in your weight calculations. diff --git a/substrate/frame/revive/src/evm/api/account.rs b/substrate/frame/revive/src/evm/api/account.rs index 06fb6e7e9c21..ba1c68ea0cf7 100644 --- a/substrate/frame/revive/src/evm/api/account.rs +++ b/substrate/frame/revive/src/evm/api/account.rs @@ -16,10 +16,9 @@ // limitations under the License. //! Utilities for working with Ethereum accounts. use crate::{ - evm::{TransactionLegacySigned, TransactionLegacyUnsigned}, + evm::{TransactionSigned, TransactionUnsigned}, H160, }; -use rlp::Encodable; use sp_runtime::AccountId32; /// A simple account that can sign transactions @@ -38,9 +37,14 @@ impl From for Account { } impl Account { + /// Create a new account from a secret + pub fn from_secret_key(secret_key: [u8; 32]) -> Self { + subxt_signer::eth::Keypair::from_secret_key(secret_key).unwrap().into() + } + /// Get the [`H160`] address of the account. pub fn address(&self) -> H160 { - H160::from_slice(&self.0.account_id().as_ref()) + H160::from_slice(&self.0.public_key().to_account_id().as_ref()) } /// Get the substrate [`AccountId32`] of the account. @@ -52,9 +56,21 @@ impl Account { } /// Sign a transaction. - pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { - let rlp_encoded = tx.rlp_bytes(); - let signature = self.0.sign(&rlp_encoded); - TransactionLegacySigned::from(tx, signature.as_ref()) + pub fn sign_transaction(&self, tx: TransactionUnsigned) -> TransactionSigned { + let payload = tx.unsigned_payload(); + let signature = self.0.sign(&payload).0; + tx.with_signature(signature) } } + +#[test] +fn from_secret_key_works() { + let account = Account::from_secret_key(hex_literal::hex!( + "a872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f" + )); + + assert_eq!( + account.address(), + H160::from(hex_literal::hex!("75e480db528101a381ce68544611c169ad7eb342")) + ) +} diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index e5f24c28a482..9b61cd042ec5 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -21,17 +21,84 @@ use super::*; use alloc::vec::Vec; use rlp::{Decodable, Encodable}; -impl TransactionLegacyUnsigned { - /// Get the rlp encoded bytes of a signed transaction with a dummy 65 bytes signature. - pub fn dummy_signed_payload(&self) -> Vec { +impl TransactionUnsigned { + /// Return the bytes to be signed by the private key. + pub fn unsigned_payload(&self) -> Vec { + use TransactionUnsigned::*; let mut s = rlp::RlpStream::new(); - s.append(self); - const DUMMY_SIGNATURE: [u8; 65] = [0u8; 65]; - s.append_raw(&DUMMY_SIGNATURE.as_ref(), 1); + match self { + Transaction2930Unsigned(ref tx) => { + s.append(&tx.r#type.value()); + s.append(tx); + }, + Transaction1559Unsigned(ref tx) => { + s.append(&tx.r#type.value()); + s.append(tx); + }, + Transaction4844Unsigned(ref tx) => { + s.append(&tx.r#type.value()); + s.append(tx); + }, + TransactionLegacyUnsigned(ref tx) => { + s.append(tx); + }, + } + s.out().to_vec() } } +impl TransactionSigned { + /// Encode the Ethereum transaction into bytes. + pub fn signed_payload(&self) -> Vec { + use TransactionSigned::*; + let mut s = rlp::RlpStream::new(); + match self { + Transaction2930Signed(ref tx) => { + s.append(&tx.transaction_2930_unsigned.r#type.value()); + s.append(tx); + }, + Transaction1559Signed(ref tx) => { + s.append(&tx.transaction_1559_unsigned.r#type.value()); + s.append(tx); + }, + Transaction4844Signed(ref tx) => { + s.append(&tx.transaction_4844_unsigned.r#type.value()); + s.append(tx); + }, + TransactionLegacySigned(ref tx) => { + s.append(tx); + }, + } + + s.out().to_vec() + } + + /// Decode the Ethereum transaction from bytes. + pub fn decode(data: &[u8]) -> Result { + if data.len() < 1 { + return Err(rlp::DecoderError::RlpIsTooShort); + } + match data[0] { + TYPE_EIP2930 => rlp::decode::(&data[1..]).map(Into::into), + TYPE_EIP1559 => rlp::decode::(&data[1..]).map(Into::into), + TYPE_EIP4844 => rlp::decode::(&data[1..]).map(Into::into), + _ => rlp::decode::(data).map(Into::into), + } + } +} + +impl TransactionUnsigned { + /// Get a signed transaction payload with a dummy 65 bytes signature. + pub fn dummy_signed_payload(&self) -> Vec { + const DUMMY_SIGNATURE: [u8; 65] = [0u8; 65]; + self.unsigned_payload() + .into_iter() + .chain(DUMMY_SIGNATURE.iter().copied()) + .collect::>() + } +} + /// See impl Encodable for TransactionLegacyUnsigned { fn rlp_append(&self, s: &mut rlp::RlpStream) { @@ -47,8 +114,8 @@ impl Encodable for TransactionLegacyUnsigned { s.append(&self.value); s.append(&self.input.0); s.append(&chain_id); - s.append(&0_u8); - s.append(&0_u8); + s.append(&0u8); + s.append(&0u8); } else { s.begin_list(6); s.append(&self.nonce); @@ -64,7 +131,6 @@ impl Encodable for TransactionLegacyUnsigned { } } -/// See impl Decodable for TransactionLegacyUnsigned { fn decode(rlp: &rlp::Rlp) -> Result { Ok(TransactionLegacyUnsigned { @@ -95,16 +161,18 @@ impl Decodable for TransactionLegacyUnsigned { impl Encodable for TransactionLegacySigned { fn rlp_append(&self, s: &mut rlp::RlpStream) { + let tx = &self.transaction_legacy_unsigned; + s.begin_list(9); - s.append(&self.transaction_legacy_unsigned.nonce); - s.append(&self.transaction_legacy_unsigned.gas_price); - s.append(&self.transaction_legacy_unsigned.gas); - match self.transaction_legacy_unsigned.to { + s.append(&tx.nonce); + s.append(&tx.gas_price); + s.append(&tx.gas); + match tx.to { Some(ref to) => s.append(to), None => s.append_empty_data(), }; - s.append(&self.transaction_legacy_unsigned.value); - s.append(&self.transaction_legacy_unsigned.input.0); + s.append(&tx.value); + s.append(&tx.input.0); s.append(&self.v); s.append(&self.r); @@ -112,6 +180,232 @@ impl Encodable for TransactionLegacySigned { } } +impl Encodable for AccessListEntry { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(2); + s.append(&self.address); + s.append_list(&self.storage_keys); + } +} + +impl Decodable for AccessListEntry { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(AccessListEntry { address: rlp.val_at(0)?, storage_keys: rlp.list_at(1)? }) + } +} + +/// See +impl Encodable for Transaction1559Unsigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(9); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + match self.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&self.value); + s.append(&self.input.0); + s.append_list(&self.access_list); + } +} + +/// See +impl Encodable for Transaction1559Signed { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + let tx = &self.transaction_1559_unsigned; + s.begin_list(12); + s.append(&tx.chain_id); + s.append(&tx.nonce); + s.append(&tx.max_priority_fee_per_gas); + s.append(&tx.max_fee_per_gas); + s.append(&tx.gas); + match tx.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&tx.value); + s.append(&tx.input.0); + s.append_list(&tx.access_list); + + s.append(&self.y_parity); + s.append(&self.r); + s.append(&self.s); + } +} + +impl Decodable for Transaction1559Signed { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(Transaction1559Signed { + transaction_1559_unsigned: { + Transaction1559Unsigned { + chain_id: rlp.val_at(0)?, + nonce: rlp.val_at(1)?, + max_priority_fee_per_gas: rlp.val_at(2)?, + max_fee_per_gas: rlp.val_at(3)?, + gas: rlp.val_at(4)?, + to: { + let to = rlp.at(5)?; + if to.is_empty() { + None + } else { + Some(to.as_val()?) + } + }, + value: rlp.val_at(6)?, + input: Bytes(rlp.val_at(7)?), + access_list: rlp.list_at(8)?, + ..Default::default() + } + }, + y_parity: rlp.val_at(9)?, + r: rlp.val_at(10)?, + s: rlp.val_at(11)?, + ..Default::default() + }) + } +} + +//See https://eips.ethereum.org/EIPS/eip-2930 +impl Encodable for Transaction2930Unsigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(8); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + match self.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&self.value); + s.append(&self.input.0); + s.append_list(&self.access_list); + } +} + +//See https://eips.ethereum.org/EIPS/eip-2930 +impl Encodable for Transaction2930Signed { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + let tx = &self.transaction_2930_unsigned; + s.begin_list(11); + s.append(&tx.chain_id); + s.append(&tx.nonce); + s.append(&tx.gas_price); + s.append(&tx.gas); + match tx.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&tx.value); + s.append(&tx.input.0); + s.append_list(&tx.access_list); + s.append(&self.y_parity); + s.append(&self.r); + s.append(&self.s); + } +} + +impl Decodable for Transaction2930Signed { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(Transaction2930Signed { + transaction_2930_unsigned: { + Transaction2930Unsigned { + chain_id: rlp.val_at(0)?, + nonce: rlp.val_at(1)?, + gas_price: rlp.val_at(2)?, + gas: rlp.val_at(3)?, + to: { + let to = rlp.at(4)?; + if to.is_empty() { + None + } else { + Some(to.as_val()?) + } + }, + value: rlp.val_at(5)?, + input: Bytes(rlp.val_at(6)?), + access_list: rlp.list_at(7)?, + ..Default::default() + } + }, + y_parity: rlp.val_at(8)?, + r: rlp.val_at(9)?, + s: rlp.val_at(10)?, + ..Default::default() + }) + } +} + +//See https://eips.ethereum.org/EIPS/eip-4844 +impl Encodable for Transaction4844Unsigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(11); + s.append(&self.chain_id); + s.append(&self.nonce); + s.append(&self.max_priority_fee_per_gas); + s.append(&self.max_fee_per_gas); + s.append(&self.gas); + s.append(&self.to); + s.append(&self.value); + s.append(&self.input.0); + s.append_list(&self.access_list); + s.append(&self.max_fee_per_blob_gas); + s.append_list(&self.blob_versioned_hashes); + } +} + +//See https://eips.ethereum.org/EIPS/eip-4844 +impl Encodable for Transaction4844Signed { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + let tx = &self.transaction_4844_unsigned; + s.begin_list(14); + s.append(&tx.chain_id); + s.append(&tx.nonce); + s.append(&tx.max_priority_fee_per_gas); + s.append(&tx.max_fee_per_gas); + s.append(&tx.gas); + s.append(&tx.to); + s.append(&tx.value); + s.append(&tx.input.0); + s.append_list(&tx.access_list); + s.append(&tx.max_fee_per_blob_gas); + s.append_list(&tx.blob_versioned_hashes); + s.append(&self.y_parity); + s.append(&self.r); + s.append(&self.s); + } +} + +impl Decodable for Transaction4844Signed { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(Transaction4844Signed { + transaction_4844_unsigned: { + Transaction4844Unsigned { + chain_id: rlp.val_at(0)?, + nonce: rlp.val_at(1)?, + max_priority_fee_per_gas: rlp.val_at(2)?, + max_fee_per_gas: rlp.val_at(3)?, + gas: rlp.val_at(4)?, + to: rlp.val_at(5)?, + value: rlp.val_at(6)?, + input: Bytes(rlp.val_at(7)?), + access_list: rlp.list_at(8)?, + max_fee_per_blob_gas: rlp.val_at(9)?, + blob_versioned_hashes: rlp.list_at(10)?, + ..Default::default() + } + }, + y_parity: rlp.val_at(11)?, + r: rlp.val_at(12)?, + s: rlp.val_at(13)?, + }) + } +} + /// See impl Decodable for TransactionLegacySigned { fn decode(rlp: &rlp::Rlp) -> Result { @@ -142,7 +436,7 @@ impl Decodable for TransactionLegacySigned { value: rlp.val_at(4)?, input: Bytes(rlp.val_at(5)?), chain_id: extract_chain_id(v).map(|v| v.into()), - r#type: Type0 {}, + r#type: TypeLegacy {}, } }, v, @@ -157,31 +451,123 @@ mod test { use super::*; #[test] - fn encode_decode_legacy_transaction_works() { - let tx = TransactionLegacyUnsigned { - chain_id: Some(596.into()), - gas: U256::from(21000), - nonce: U256::from(1), - gas_price: U256::from("0x640000006a"), - to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()), - value: U256::from(123123), - input: Bytes(vec![]), - r#type: Type0, - }; + fn encode_decode_tx_works() { + let txs = [ + // Legacy + ( + "f86080808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d87808025a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + r#" + { + "chainId": "0x1", + "gas": "0x1e241", + "gasPrice": "0x0", + "input": "0x", + "nonce": "0x0", + "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", + "type": "0x0", + "value": "0x0", + "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0", + "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + "v": "0x25" + } + "# + ), + // type 1: EIP2930 + ( + "01f89b0180808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + r#" + { + "accessList": [ + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"] + } + ], + "chainId": "0x1", + "gas": "0x1e241", + "gasPrice": "0x0", + "input": "0x", + "nonce": "0x0", + "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", + "type": "0x1", + "value": "0x0", + "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0", + "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + "yParity": "0x0" + } + "# + ), + // type 2: EIP1559 + ( + "02f89c018080018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + r#" + { + "accessList": [ + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"] + } + ], + "chainId": "0x1", + "gas": "0x1e241", + "gasPrice": "0x0", + "input": "0x", + "maxFeePerGas": "0x1", + "maxPriorityFeePerGas": "0x0", + "nonce": "0x0", + "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", + "type": "0x2", + "value": "0x0", + "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0", + "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + "yParity": "0x0" - let rlp_bytes = rlp::encode(&tx); - let decoded = rlp::decode::(&rlp_bytes).unwrap(); - assert_eq!(&tx, &decoded); + } + "# + ), + // type 3: EIP4844 + ( - let tx = Account::default().sign_transaction(tx); - let rlp_bytes = rlp::encode(&tx); - let decoded = rlp::decode::(&rlp_bytes).unwrap(); - assert_eq!(&tx, &decoded); + "03f8bf018002018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + r#" + { + "accessList": [ + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ["0x0000000000000000000000000000000000000000000000000000000000000000"] + } + ], + "blobVersionedHashes": ["0x0000000000000000000000000000000000000000000000000000000000000000"], + "chainId": "0x1", + "gas": "0x1e241", + "input": "0x", + "maxFeePerBlobGas": "0x0", + "maxFeePerGas": "0x1", + "maxPriorityFeePerGas": "0x2", + "nonce": "0x0", + "to": "0x095e7baea6a6c7c4c2dfeb977efac326af552d87", + "type": "0x3", + "value": "0x0", + "r": "0xfe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0", + "s": "0x6de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8", + "yParity": "0x0" + } + "# + ) + ]; + + for (tx, json) in txs { + let raw_tx = hex::decode(tx).unwrap(); + let tx = TransactionSigned::decode(&raw_tx).unwrap(); + assert_eq!(tx.signed_payload(), raw_tx); + let expected_tx = serde_json::from_str(json).unwrap(); + assert_eq!(tx, expected_tx); + } } #[test] fn dummy_signed_payload_works() { - let tx = TransactionLegacyUnsigned { + let tx: TransactionUnsigned = TransactionLegacyUnsigned { chain_id: Some(596.into()), gas: U256::from(21000), nonce: U256::from(1), @@ -189,31 +575,12 @@ mod test { to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()), value: U256::from(123123), input: Bytes(vec![]), - r#type: Type0, - }; - - let signed_tx = Account::default().sign_transaction(tx.clone()); - let rlp_bytes = rlp::encode(&signed_tx); - assert_eq!(tx.dummy_signed_payload().len(), rlp_bytes.len()); - } - - #[test] - fn recover_address_works() { - let account = Account::default(); - - let unsigned_tx = TransactionLegacyUnsigned { - value: 200_000_000_000_000_000_000u128.into(), - gas_price: 100_000_000_200u64.into(), - gas: 100_107u32.into(), - nonce: 3.into(), - to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()), - chain_id: Some(596.into()), - ..Default::default() - }; - - let tx = account.sign_transaction(unsigned_tx.clone()); - let recovered_address = tx.recover_eth_address().unwrap(); + r#type: TypeLegacy, + } + .into(); - assert_eq!(account.address(), recovered_address); + let dummy_signed_payload = tx.dummy_signed_payload(); + let payload = Account::default().sign_transaction(tx).signed_payload(); + assert_eq!(dummy_signed_payload.len(), payload.len()); } } diff --git a/substrate/frame/revive/src/evm/api/rpc_types.rs b/substrate/frame/revive/src/evm/api/rpc_types.rs index b15a0a53cd07..ed046cb4da44 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types.rs @@ -15,7 +15,30 @@ // See the License for the specific language governing permissions and // limitations under the License. //! Utility impl for the RPC types. -use super::{ReceiptInfo, TransactionInfo, TransactionSigned}; +use super::*; +use alloc::vec::Vec; +use sp_core::{H160, U256}; + +impl From for BlockNumberOrTagOrHash { + fn from(b: BlockNumberOrTag) -> Self { + match b { + BlockNumberOrTag::U256(n) => BlockNumberOrTagOrHash::U256(n), + BlockNumberOrTag::BlockTag(t) => BlockNumberOrTagOrHash::BlockTag(t), + } + } +} + +impl From for TransactionUnsigned { + fn from(tx: TransactionSigned) -> Self { + use TransactionSigned::*; + match tx { + Transaction4844Signed(tx) => tx.transaction_4844_unsigned.into(), + Transaction1559Signed(tx) => tx.transaction_1559_unsigned.into(), + Transaction2930Signed(tx) => tx.transaction_2930_unsigned.into(), + TransactionLegacySigned(tx) => tx.transaction_legacy_unsigned.into(), + } + } +} impl TransactionInfo { /// Create a new [`TransactionInfo`] from a receipt and a signed transaction. @@ -30,3 +53,240 @@ impl TransactionInfo { } } } + +impl ReceiptInfo { + /// Initialize a new Receipt + pub fn new( + block_hash: H256, + block_number: U256, + contract_address: Option
, + from: Address, + logs: Vec, + to: Option
, + effective_gas_price: U256, + gas_used: U256, + success: bool, + transaction_hash: H256, + transaction_index: U256, + r#type: Byte, + ) -> Self { + let logs_bloom = Self::logs_bloom(&logs); + ReceiptInfo { + block_hash, + block_number, + contract_address, + from, + logs, + logs_bloom, + to, + effective_gas_price, + gas_used, + status: Some(if success { U256::one() } else { U256::zero() }), + transaction_hash, + transaction_index, + r#type: Some(r#type), + ..Default::default() + } + } + + /// Returns `true` if the transaction was successful. + pub fn is_success(&self) -> bool { + self.status.map_or(false, |status| status == U256::one()) + } + + /// Calculate receipt logs bloom. + fn logs_bloom(logs: &[Log]) -> Bytes256 { + let mut bloom = [0u8; 256]; + for log in logs { + m3_2048(&mut bloom, &log.address.as_ref()); + for topic in &log.topics { + m3_2048(&mut bloom, topic.as_ref()); + } + } + bloom.into() + } +} +/// Specialised Bloom filter that sets three bits out of 2048, given an +/// arbitrary byte sequence. +/// +/// See Section 4.4.1 "Transaction Receipt" of the [Ethereum Yellow Paper][ref]. +/// +/// [ref]: https://ethereum.github.io/yellowpaper/paper.pdf +fn m3_2048(bloom: &mut [u8; 256], bytes: &[u8]) { + let hash = sp_core::keccak_256(bytes); + for i in [0, 2, 4] { + let bit = (hash[i + 1] as usize + ((hash[i] as usize) << 8)) & 0x7FF; + bloom[256 - 1 - bit / 8] |= 1 << (bit % 8); + } +} + +#[test] +fn logs_bloom_works() { + let receipt: ReceiptInfo = serde_json::from_str( + r#" + { + "blockHash": "0x835ee379aaabf4802a22a93ad8164c02bbdde2cc03d4552d5c642faf4e09d1f3", + "blockNumber": "0x2", + "contractAddress": null, + "cumulativeGasUsed": "0x5d92", + "effectiveGasPrice": "0x2dcd5c2d", + "from": "0xb4f1f9ecfe5a28633a27f57300bda217e99b8969", + "gasUsed": "0x5d92", + "logs": [ + { + "address": "0x82bdb002b9b1f36c42df15fbdc6886abcb2ab31d", + "topics": [ + "0x1585375487296ff2f0370daeec4214074a032b31af827c12622fa9a58c16c7d0", + "0x000000000000000000000000b4f1f9ecfe5a28633a27f57300bda217e99b8969" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20776f726c64000000000000000000000000000000000000000000", + "blockNumber": "0x2", + "transactionHash": "0xad0075127962bdf73d787f2944bdb5f351876f23c35e6a48c1f5b6463a100af4", + "transactionIndex": "0x0", + "blockHash": "0x835ee379aaabf4802a22a93ad8164c02bbdde2cc03d4552d5c642faf4e09d1f3", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000008000000000000000000000000000000000000000000000000800000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000004000000000000000800000000000000000080000000000000000000000000000000000000000000", + "status": "0x1", + "to": "0x82bdb002b9b1f36c42df15fbdc6886abcb2ab31d", + "transactionHash": "0xad0075127962bdf73d787f2944bdb5f351876f23c35e6a48c1f5b6463a100af4", + "transactionIndex": "0x0", + "type": "0x2" + } + "#, + ) + .unwrap(); + assert_eq!(receipt.logs_bloom, ReceiptInfo::logs_bloom(&receipt.logs)); +} + +impl GenericTransaction { + /// Create a new [`GenericTransaction`] from a signed transaction. + pub fn from_signed(tx: TransactionSigned, from: Option) -> Self { + Self::from_unsigned(tx.into(), from) + } + + /// Create a new [`GenericTransaction`] from a unsigned transaction. + pub fn from_unsigned(tx: TransactionUnsigned, from: Option) -> Self { + use TransactionUnsigned::*; + match tx { + TransactionLegacyUnsigned(tx) => GenericTransaction { + from, + r#type: Some(tx.r#type.as_byte()), + chain_id: tx.chain_id, + input: Some(tx.input), + nonce: Some(tx.nonce), + value: Some(tx.value), + to: tx.to, + gas: Some(tx.gas), + gas_price: Some(tx.gas_price), + ..Default::default() + }, + Transaction4844Unsigned(tx) => GenericTransaction { + from, + r#type: Some(tx.r#type.as_byte()), + chain_id: Some(tx.chain_id), + input: Some(tx.input), + nonce: Some(tx.nonce), + value: Some(tx.value), + to: Some(tx.to), + gas: Some(tx.gas), + gas_price: Some(tx.max_fee_per_blob_gas), + access_list: Some(tx.access_list), + blob_versioned_hashes: tx.blob_versioned_hashes, + max_fee_per_blob_gas: Some(tx.max_fee_per_blob_gas), + max_fee_per_gas: Some(tx.max_fee_per_gas), + max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas), + ..Default::default() + }, + Transaction1559Unsigned(tx) => GenericTransaction { + from, + r#type: Some(tx.r#type.as_byte()), + chain_id: Some(tx.chain_id), + input: Some(tx.input), + nonce: Some(tx.nonce), + value: Some(tx.value), + to: tx.to, + gas: Some(tx.gas), + gas_price: Some(tx.gas_price), + access_list: Some(tx.access_list), + max_fee_per_gas: Some(tx.max_fee_per_gas), + max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas), + ..Default::default() + }, + Transaction2930Unsigned(tx) => GenericTransaction { + from, + r#type: Some(tx.r#type.as_byte()), + chain_id: Some(tx.chain_id), + input: Some(tx.input), + nonce: Some(tx.nonce), + value: Some(tx.value), + to: tx.to, + gas: Some(tx.gas), + gas_price: Some(tx.gas_price), + access_list: Some(tx.access_list), + ..Default::default() + }, + } + } + + /// Convert to a [`TransactionUnsigned`]. + pub fn try_into_unsigned(self) -> Result { + match self.r#type.unwrap_or_default().0 { + TYPE_LEGACY => Ok(TransactionLegacyUnsigned { + r#type: TypeLegacy {}, + chain_id: self.chain_id, + input: self.input.unwrap_or_default(), + nonce: self.nonce.unwrap_or_default(), + value: self.value.unwrap_or_default(), + to: self.to, + gas: self.gas.unwrap_or_default(), + gas_price: self.gas_price.unwrap_or_default(), + } + .into()), + TYPE_EIP1559 => Ok(Transaction1559Unsigned { + r#type: TypeEip1559 {}, + chain_id: self.chain_id.unwrap_or_default(), + input: self.input.unwrap_or_default(), + nonce: self.nonce.unwrap_or_default(), + value: self.value.unwrap_or_default(), + to: self.to, + gas: self.gas.unwrap_or_default(), + gas_price: self.gas_price.unwrap_or_default(), + access_list: self.access_list.unwrap_or_default(), + max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(), + max_priority_fee_per_gas: self.max_priority_fee_per_gas.unwrap_or_default(), + } + .into()), + TYPE_EIP2930 => Ok(Transaction2930Unsigned { + r#type: TypeEip2930 {}, + chain_id: self.chain_id.unwrap_or_default(), + input: self.input.unwrap_or_default(), + nonce: self.nonce.unwrap_or_default(), + value: self.value.unwrap_or_default(), + to: self.to, + gas: self.gas.unwrap_or_default(), + gas_price: self.gas_price.unwrap_or_default(), + access_list: self.access_list.unwrap_or_default(), + } + .into()), + TYPE_EIP4844 => Ok(Transaction4844Unsigned { + r#type: TypeEip4844 {}, + chain_id: self.chain_id.unwrap_or_default(), + input: self.input.unwrap_or_default(), + nonce: self.nonce.unwrap_or_default(), + value: self.value.unwrap_or_default(), + to: self.to.unwrap_or_default(), + gas: self.gas.unwrap_or_default(), + max_fee_per_gas: self.max_fee_per_gas.unwrap_or_default(), + max_fee_per_blob_gas: self.max_fee_per_blob_gas.unwrap_or_default(), + max_priority_fee_per_gas: self.max_priority_fee_per_gas.unwrap_or_default(), + access_list: self.access_list.unwrap_or_default(), + blob_versioned_hashes: self.blob_versioned_hashes, + } + .into()), + _ => Err(()), + } + } +} diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs index 1f391ae846a5..1d65fdefdde6 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -17,7 +17,7 @@ //! Generated JSON-RPC types. #![allow(missing_docs)] -use super::{byte::*, Type0, Type1, Type2, Type3}; +use super::{byte::*, TypeEip1559, TypeEip2930, TypeEip4844, TypeLegacy}; use alloc::vec::Vec; use codec::{Decode, Encode}; use derive_more::{From, TryInto}; @@ -94,8 +94,8 @@ pub struct Block { /// Uncles pub uncles: Vec, /// Withdrawals - #[serde(skip_serializing_if = "Option::is_none")] - pub withdrawals: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub withdrawals: Vec, /// Withdrawals root #[serde(rename = "withdrawalsRoot", skip_serializing_if = "Option::is_none")] pub withdrawals_root: Option, @@ -114,7 +114,7 @@ pub enum BlockNumberOrTag { } impl Default for BlockNumberOrTag { fn default() -> Self { - BlockNumberOrTag::U256(Default::default()) + BlockNumberOrTag::BlockTag(Default::default()) } } @@ -133,7 +133,7 @@ pub enum BlockNumberOrTagOrHash { } impl Default for BlockNumberOrTagOrHash { fn default() -> Self { - BlockNumberOrTagOrHash::U256(Default::default()) + BlockNumberOrTagOrHash::BlockTag(Default::default()) } } @@ -148,12 +148,12 @@ pub struct GenericTransaction { pub access_list: Option, /// blobVersionedHashes /// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs. - #[serde(rename = "blobVersionedHashes", skip_serializing_if = "Option::is_none")] - pub blob_versioned_hashes: Option>, + #[serde(rename = "blobVersionedHashes", default, skip_serializing_if = "Vec::is_empty")] + pub blob_versioned_hashes: Vec, /// blobs /// Raw blob data. - #[serde(skip_serializing_if = "Option::is_none")] - pub blobs: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub blobs: Vec, /// chainId /// Chain ID that this transaction is valid on. #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] @@ -319,7 +319,7 @@ pub enum TransactionUnsigned { } impl Default for TransactionUnsigned { fn default() -> Self { - TransactionUnsigned::Transaction4844Unsigned(Default::default()) + TransactionUnsigned::TransactionLegacyUnsigned(Default::default()) } } @@ -341,13 +341,13 @@ pub type AccessList = Vec; )] pub enum BlockTag { #[serde(rename = "earliest")] - #[default] Earliest, #[serde(rename = "finalized")] Finalized, #[serde(rename = "safe")] Safe, #[serde(rename = "latest")] + #[default] Latest, #[serde(rename = "pending")] Pending, @@ -375,8 +375,7 @@ impl Default for H256OrTransactionInfo { )] pub struct Log { /// address - #[serde(skip_serializing_if = "Option::is_none")] - pub address: Option
, + pub address: Address, /// block hash #[serde(rename = "blockHash", skip_serializing_if = "Option::is_none")] pub block_hash: Option, @@ -393,8 +392,8 @@ pub struct Log { #[serde(skip_serializing_if = "Option::is_none")] pub removed: Option, /// topics - #[serde(skip_serializing_if = "Option::is_none")] - pub topics: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub topics: Vec, /// transaction hash #[serde(rename = "transactionHash")] pub transaction_hash: H256, @@ -456,7 +455,7 @@ pub struct Transaction1559Unsigned { /// to address pub to: Option
, /// type - pub r#type: Type2, + pub r#type: TypeEip1559, /// value pub value: U256, } @@ -487,7 +486,7 @@ pub struct Transaction2930Unsigned { /// to address pub to: Option
, /// type - pub r#type: Type1, + pub r#type: TypeEip2930, /// value pub value: U256, } @@ -531,7 +530,7 @@ pub struct Transaction4844Unsigned { /// to address pub to: Address, /// type - pub r#type: Type3, + pub r#type: TypeEip4844, /// value pub value: U256, } @@ -558,7 +557,7 @@ pub struct TransactionLegacyUnsigned { /// to address pub to: Option
, /// type - pub r#type: Type0, + pub r#type: TypeLegacy, /// value pub value: U256, } @@ -575,7 +574,7 @@ pub enum TransactionSigned { } impl Default for TransactionSigned { fn default() -> Self { - TransactionSigned::Transaction4844Signed(Default::default()) + TransactionSigned::TransactionLegacySigned(Default::default()) } } @@ -623,8 +622,8 @@ pub struct Transaction1559Signed { pub v: Option, /// yParity /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. - #[serde(rename = "yParity", skip_serializing_if = "Option::is_none")] - pub y_parity: Option, + #[serde(rename = "yParity")] + pub y_parity: U256, } /// Signed 2930 Transaction @@ -662,8 +661,8 @@ pub struct Transaction4844Signed { pub s: U256, /// yParity /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. - #[serde(rename = "yParity", skip_serializing_if = "Option::is_none")] - pub y_parity: Option, + #[serde(rename = "yParity")] + pub y_parity: U256, } /// Signed Legacy Transaction diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs index 957d50c8e324..9f39b92b461e 100644 --- a/substrate/frame/revive/src/evm/api/signature.rs +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -15,49 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. //! Ethereum signature utilities -use super::{TransactionLegacySigned, TransactionLegacyUnsigned}; -use rlp::Encodable; +use super::*; use sp_core::{H160, U256}; use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; -impl TransactionLegacyUnsigned { - /// Recover the Ethereum address, from an RLP encoded transaction and a 65 bytes signature. - pub fn recover_eth_address(rlp_encoded: &[u8], signature: &[u8; 65]) -> Result { - let hash = keccak_256(rlp_encoded); - let mut addr = H160::default(); - let pk = secp256k1_ecdsa_recover(&signature, &hash).map_err(|_| ())?; - addr.assign_from_slice(&keccak_256(&pk[..])[12..]); - - Ok(addr) - } -} - impl TransactionLegacySigned { - /// Create a signed transaction from an [`TransactionLegacyUnsigned`] and a signature. - pub fn from( - transaction_legacy_unsigned: TransactionLegacyUnsigned, - signature: &[u8; 65], - ) -> TransactionLegacySigned { - let r = U256::from_big_endian(&signature[..32]); - let s = U256::from_big_endian(&signature[32..64]); - let recovery_id = signature[64] as u32; - let v = transaction_legacy_unsigned - .chain_id - .map(|chain_id| chain_id * 2 + 35 + recovery_id) - .unwrap_or_else(|| U256::from(27) + recovery_id); - - TransactionLegacySigned { transaction_legacy_unsigned, r, s, v } - } - - /// Get the raw 65 bytes signature from the signed transaction. - pub fn raw_signature(&self) -> Result<[u8; 65], ()> { - let mut s = [0u8; 65]; - self.r.write_as_big_endian(s[0..32].as_mut()); - self.s.write_as_big_endian(s[32..64].as_mut()); - s[64] = self.extract_recovery_id().ok_or(())?; - Ok(s) - } - /// Get the recovery ID from the signed transaction. /// See https://eips.ethereum.org/EIPS/eip-155 fn extract_recovery_id(&self) -> Option { @@ -71,10 +33,154 @@ impl TransactionLegacySigned { self.v.try_into().ok() } } +} + +impl TransactionUnsigned { + /// Extract the unsigned transaction from a signed transaction. + pub fn from_signed(tx: TransactionSigned) -> Self { + match tx { + TransactionSigned::TransactionLegacySigned(signed) => + Self::TransactionLegacyUnsigned(signed.transaction_legacy_unsigned), + TransactionSigned::Transaction4844Signed(signed) => + Self::Transaction4844Unsigned(signed.transaction_4844_unsigned), + TransactionSigned::Transaction1559Signed(signed) => + Self::Transaction1559Unsigned(signed.transaction_1559_unsigned), + TransactionSigned::Transaction2930Signed(signed) => + Self::Transaction2930Unsigned(signed.transaction_2930_unsigned), + } + } + + /// Create a signed transaction from an [`TransactionUnsigned`] and a signature. + pub fn with_signature(self, signature: [u8; 65]) -> TransactionSigned { + let r = U256::from_big_endian(&signature[..32]); + let s = U256::from_big_endian(&signature[32..64]); + let recovery_id = signature[64]; + + match self { + TransactionUnsigned::Transaction2930Unsigned(transaction_2930_unsigned) => + Transaction2930Signed { + transaction_2930_unsigned, + r, + s, + v: None, + y_parity: U256::from(recovery_id), + } + .into(), + TransactionUnsigned::Transaction1559Unsigned(transaction_1559_unsigned) => + Transaction1559Signed { + transaction_1559_unsigned, + r, + s, + v: None, + y_parity: U256::from(recovery_id), + } + .into(), + + TransactionUnsigned::Transaction4844Unsigned(transaction_4844_unsigned) => + Transaction4844Signed { + transaction_4844_unsigned, + r, + s, + y_parity: U256::from(recovery_id), + } + .into(), + + TransactionUnsigned::TransactionLegacyUnsigned(transaction_legacy_unsigned) => { + let v = transaction_legacy_unsigned + .chain_id + .map(|chain_id| { + chain_id + .saturating_mul(U256::from(2)) + .saturating_add(U256::from(35u32 + recovery_id as u32)) + }) + .unwrap_or_else(|| U256::from(27u32 + recovery_id as u32)); + + TransactionLegacySigned { transaction_legacy_unsigned, r, s, v }.into() + }, + } + } +} + +impl TransactionSigned { + /// Get the raw 65 bytes signature from the signed transaction. + pub fn raw_signature(&self) -> Result<[u8; 65], ()> { + use TransactionSigned::*; + let (r, s, v) = match self { + TransactionLegacySigned(tx) => (tx.r, tx.s, tx.extract_recovery_id().ok_or(())?), + Transaction4844Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), + Transaction1559Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), + Transaction2930Signed(tx) => (tx.r, tx.s, tx.y_parity.try_into().map_err(|_| ())?), + }; + let mut sig = [0u8; 65]; + r.write_as_big_endian(sig[0..32].as_mut()); + s.write_as_big_endian(sig[32..64].as_mut()); + sig[64] = v; + Ok(sig) + } - /// Recover the Ethereum address from the signed transaction. + /// Recover the Ethereum address, from a signed transaction. pub fn recover_eth_address(&self) -> Result { - let rlp_encoded = self.transaction_legacy_unsigned.rlp_bytes(); - TransactionLegacyUnsigned::recover_eth_address(&rlp_encoded, &self.raw_signature()?) + use TransactionSigned::*; + + let mut s = rlp::RlpStream::new(); + match self { + TransactionLegacySigned(tx) => { + let tx = &tx.transaction_legacy_unsigned; + s.append(tx); + }, + Transaction4844Signed(tx) => { + let tx = &tx.transaction_4844_unsigned; + s.append(&tx.r#type.value()); + s.append(tx); + }, + Transaction1559Signed(tx) => { + let tx = &tx.transaction_1559_unsigned; + s.append(&tx.r#type.value()); + s.append(tx); + }, + Transaction2930Signed(tx) => { + let tx = &tx.transaction_2930_unsigned; + s.append(&tx.r#type.value()); + s.append(tx); + }, + } + let bytes = s.out().to_vec(); + let signature = self.raw_signature()?; + + let hash = keccak_256(&bytes); + let mut addr = H160::default(); + let pk = secp256k1_ecdsa_recover(&signature, &hash).map_err(|_| ())?; + addr.assign_from_slice(&keccak_256(&pk[..])[12..]); + Ok(addr) + } +} + +#[test] +fn sign_and_recover_work() { + use crate::evm::TransactionUnsigned; + let txs = [ + // Legacy + "f86080808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d87808026a07b2e762a17a71a46b422e60890a04512cf0d907ccf6b78b5bd6e6977efdc2bf5a01ea673d50bbe7c2236acb498ceb8346a8607c941f0b8cbcde7cf439aa9369f1f", + //// type 1: EIP2930 + "01f89b0180808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0c45a61b3d1d00169c649e7326e02857b850efb96e587db4b9aad29afc80d0752a070ae1eb47ab4097dbed2f19172ae286492621b46ac737ee6c32fb18a00c94c9c", + // type 2: EIP1559 + "02f89c018080018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a055d72bbc3047d4b9d3e4b8099f187143202407746118204cc2e0cb0c85a68baea04f6ef08a1418c70450f53398d9f0f2d78d9e9d6b8a80cba886b67132c4a744f2", + // type 3: EIP4844 + "03f8bf018002018301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080e1a0000000000000000000000000000000000000000000000000000000000000000001a0672b8bac466e2cf1be3148c030988d40d582763ecebbc07700dfc93bb070d8a4a07c635887005b11cb58964c04669ac2857fa633aa66f662685dadfd8bcacb0f21", + ]; + let account = Account::from_secret_key(hex_literal::hex!( + "a872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f" + )); + + for tx in txs { + let raw_tx = hex::decode(tx).unwrap(); + let tx = TransactionSigned::decode(&raw_tx).unwrap(); + + let address = tx.recover_eth_address(); + assert_eq!(address.unwrap(), account.address()); + + let unsigned = TransactionUnsigned::from_signed(tx.clone()); + let signed = account.sign_transaction(unsigned); + assert_eq!(tx, signed); } } diff --git a/substrate/frame/revive/src/evm/api/type_id.rs b/substrate/frame/revive/src/evm/api/type_id.rs index 7434ca6e9b7f..c6e018a379b3 100644 --- a/substrate/frame/revive/src/evm/api/type_id.rs +++ b/substrate/frame/revive/src/evm/api/type_id.rs @@ -17,6 +17,7 @@ //! Ethereum Typed Transaction types use super::Byte; use codec::{Decode, Encode}; +use paste::paste; use rlp::Decodable; use scale_info::TypeInfo; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -29,8 +30,14 @@ macro_rules! transaction_type { #[derive(Clone, Default, Debug, Eq, PartialEq)] pub struct $name; + // upper case const name + paste! { + #[doc = concat!("Transaction value for type identifier: ", $value)] + pub const [<$name:snake:upper>]: u8 = $value; + } + impl $name { - /// Get the value of the type + /// Convert to u8 pub fn value(&self) -> u8 { $value } @@ -107,7 +114,12 @@ macro_rules! transaction_type { }; } -transaction_type!(Type0, 0); -transaction_type!(Type1, 1); -transaction_type!(Type2, 2); -transaction_type!(Type3, 3); +transaction_type!(TypeLegacy, 0); +transaction_type!(TypeEip2930, 1); +transaction_type!(TypeEip1559, 2); +transaction_type!(TypeEip4844, 3); + +#[test] +fn transaction_type() { + assert_eq!(TYPE_EIP2930, 1u8); +} diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 9b360c7de712..24b75de83569 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -16,7 +16,7 @@ // limitations under the License. //! Runtime types for integrating `pallet-revive` with the EVM. use crate::{ - evm::api::{TransactionLegacySigned, TransactionLegacyUnsigned}, + evm::api::{GenericTransaction, TransactionSigned}, AccountIdOf, AddressMapper, BalanceOf, MomentOf, Weight, LOG_TARGET, }; use codec::{Decode, Encode}; @@ -92,8 +92,12 @@ impl ExtrinsicLike impl ExtrinsicMetadata for UncheckedExtrinsic { - const VERSION: u8 = - generic::UncheckedExtrinsic::, Signature, E::Extension>::VERSION; + const VERSIONS: &'static [u8] = generic::UncheckedExtrinsic::< + Address, + CallOf, + Signature, + E::Extension, + >::VERSIONS; type TransactionExtensions = E::Extension; } @@ -190,7 +194,7 @@ impl<'a, Address: Decode, Signature: Decode, E: EthExtra> serde::Deserialize<'a> { let r = sp_core::bytes::deserialize(de)?; Decode::decode(&mut &r[..]) - .map_err(|e| serde::de::Error::custom(sp_runtime::format!("Decode error: {}", e))) + .map_err(|e| serde::de::Error::custom(alloc::format!("Decode error: {}", e))) } } @@ -293,7 +297,7 @@ pub trait EthExtra { CallOf: From>, ::Hash: frame_support::traits::IsType, { - let tx = rlp::decode::(&payload).map_err(|err| { + let tx = TransactionSigned::decode(&payload).map_err(|err| { log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); InvalidTransaction::Call })?; @@ -305,32 +309,33 @@ pub trait EthExtra { let signer = ::AddressMapper::to_fallback_account_id(&signer); - let TransactionLegacyUnsigned { nonce, chain_id, to, value, input, gas, gas_price, .. } = - tx.transaction_legacy_unsigned; + let GenericTransaction { nonce, chain_id, to, value, input, gas, gas_price, .. } = + GenericTransaction::from_signed(tx, None); if chain_id.unwrap_or_default() != ::ChainId::get().into() { log::debug!(target: LOG_TARGET, "Invalid chain_id {chain_id:?}"); return Err(InvalidTransaction::Call); } - let value = (value / U256::from(::NativeToEthRatio::get())) - .try_into() - .map_err(|_| InvalidTransaction::Call)?; + let value = crate::Pallet::::convert_evm_to_native(value.unwrap_or_default()) + .map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to convert value to native: {err:?}"); + InvalidTransaction::Call + })?; + let data = input.unwrap_or_default().0; let call = if let Some(dest) = to { crate::Call::call:: { dest, value, gas_limit, storage_deposit_limit, - data: input.0, + data, } } else { - let blob = match polkavm::ProgramBlob::blob_length(&input.0) { - Some(blob_len) => blob_len - .try_into() - .ok() - .and_then(|blob_len| (input.0.split_at_checked(blob_len))), + let blob = match polkavm::ProgramBlob::blob_length(&data) { + Some(blob_len) => + blob_len.try_into().ok().and_then(|blob_len| (data.split_at_checked(blob_len))), _ => None, }; @@ -349,17 +354,18 @@ pub trait EthExtra { } }; - let nonce = nonce.try_into().map_err(|_| InvalidTransaction::Call)?; + let nonce = nonce.unwrap_or_default().try_into().map_err(|_| InvalidTransaction::Call)?; - // Fees calculated with the fixed `GAS_PRICE` that should be used to estimate the gas. + // Fees calculated with the fixed `GAS_PRICE` + // When we dry-run the transaction, we set the gas to `Fee / GAS_PRICE` let eth_fee_no_tip = U256::from(GAS_PRICE) - .saturating_mul(gas) + .saturating_mul(gas.unwrap_or_default()) .try_into() .map_err(|_| InvalidTransaction::Call)?; // Fees with the actual gas_price from the transaction. - let eth_fee: BalanceOf = U256::from(gas_price) - .saturating_mul(gas) + let eth_fee: BalanceOf = U256::from(gas_price.unwrap_or_default()) + .saturating_mul(gas.unwrap_or_default()) .try_into() .map_err(|_| InvalidTransaction::Call)?; @@ -376,6 +382,8 @@ pub trait EthExtra { .into(); log::trace!(target: LOG_TARGET, "try_into_checked_extrinsic: encoded_len: {encoded_len:?} actual_fee: {actual_fee:?} eth_fee: {eth_fee:?}"); + // The fees from the Ethereum transaction should be greater or equal to the actual fees paid + // by the account. if eth_fee < actual_fee { log::debug!(target: LOG_TARGET, "fees {eth_fee:?} too low for the extrinsic {actual_fee:?}"); return Err(InvalidTransaction::Payment.into()) @@ -410,48 +418,12 @@ mod test { }; use frame_support::{error::LookupError, traits::fungible::Mutate}; use pallet_revive_fixtures::compile_module; - use rlp::Encodable; use sp_runtime::{ traits::{Checkable, DispatchTransaction}, MultiAddress, MultiSignature, }; type AccountIdOf = ::AccountId; - /// A simple account that can sign transactions - pub struct Account(subxt_signer::eth::Keypair); - - impl Default for Account { - fn default() -> Self { - Self(subxt_signer::eth::dev::alith()) - } - } - - impl From for Account { - fn from(kp: subxt_signer::eth::Keypair) -> Self { - Self(kp) - } - } - - impl Account { - /// Get the [`AccountId`] of the account. - pub fn account_id(&self) -> AccountIdOf { - let address = self.address(); - ::AddressMapper::to_fallback_account_id(&address) - } - - /// Get the [`H160`] address of the account. - pub fn address(&self) -> H160 { - H160::from_slice(&self.0.account_id().as_ref()) - } - - /// Sign a transaction. - pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { - let rlp_encoded = tx.rlp_bytes(); - let signature = self.0.sign(&rlp_encoded); - TransactionLegacySigned::from(tx, signature.as_ref()) - } - } - #[derive(Clone, PartialEq, Eq, Debug)] pub struct Extra; type SignedExtra = (frame_system::CheckNonce, ChargeTransactionPayment); @@ -483,235 +455,265 @@ mod test { /// A builder for creating an unchecked extrinsic, and test that the check function works. #[derive(Clone)] struct UncheckedExtrinsicBuilder { - tx: TransactionLegacyUnsigned, + tx: GenericTransaction, gas_limit: Weight, storage_deposit_limit: BalanceOf, + before_validate: Option>, } impl UncheckedExtrinsicBuilder { /// Create a new builder with default values. fn new() -> Self { Self { - tx: TransactionLegacyUnsigned { + tx: GenericTransaction { + from: Some(Account::default().address()), chain_id: Some(::ChainId::get().into()), - gas_price: U256::from(GAS_PRICE), + gas_price: Some(U256::from(GAS_PRICE)), ..Default::default() }, gas_limit: Weight::zero(), storage_deposit_limit: 0, + before_validate: None, } } fn estimate_gas(&mut self) { - let dry_run = crate::Pallet::::bare_eth_transact( - Account::default().account_id(), - self.tx.to, - self.tx.value.try_into().unwrap(), - self.tx.input.clone().0, - Weight::MAX, - u64::MAX, - |call| { + let dry_run = + crate::Pallet::::bare_eth_transact(self.tx.clone(), Weight::MAX, |call| { let call = RuntimeCall::Contracts(call); let uxt: Ex = sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into(); uxt.encoded_size() as u32 + }); + + match dry_run { + Ok(dry_run) => { + log::debug!(target: LOG_TARGET, "Estimated gas: {:?}", dry_run.eth_gas); + self.tx.gas = Some(dry_run.eth_gas); + }, + Err(err) => { + log::debug!(target: LOG_TARGET, "Failed to estimate gas: {:?}", err); }, - crate::DebugInfo::Skip, - crate::CollectEvents::Skip, - ); - self.tx.gas = ((dry_run.fee + GAS_PRICE as u64) / (GAS_PRICE as u64)).into(); + } } /// Create a new builder with a call to the given address. fn call_with(dest: H160) -> Self { let mut builder = Self::new(); builder.tx.to = Some(dest); - builder.estimate_gas(); + ExtBuilder::default().build().execute_with(|| builder.estimate_gas()); builder } /// Create a new builder with an instantiate call. fn instantiate_with(code: Vec, data: Vec) -> Self { let mut builder = Self::new(); - builder.tx.input = Bytes(code.into_iter().chain(data.into_iter()).collect()); - builder.estimate_gas(); + builder.tx.input = Some(Bytes(code.into_iter().chain(data.into_iter()).collect())); + ExtBuilder::default().build().execute_with(|| builder.estimate_gas()); builder } /// Update the transaction with the given function. - fn update(mut self, f: impl FnOnce(&mut TransactionLegacyUnsigned) -> ()) -> Self { + fn update(mut self, f: impl FnOnce(&mut GenericTransaction) -> ()) -> Self { f(&mut self.tx); self } + /// Set before_validate function. + fn before_validate(mut self, f: impl Fn() + Send + Sync + 'static) -> Self { + self.before_validate = Some(std::sync::Arc::new(f)); + self + } /// Call `check` on the unchecked extrinsic, and `pre_dispatch` on the signed extension. fn check(&self) -> Result<(RuntimeCall, SignedExtra), TransactionValidityError> { - let UncheckedExtrinsicBuilder { tx, gas_limit, storage_deposit_limit } = self.clone(); - - // Fund the account. - let account = Account::default(); - let _ = ::Currency::set_balance( - &account.account_id(), - 100_000_000_000_000, - ); - - let payload = account.sign_transaction(tx).rlp_bytes().to_vec(); - let call = RuntimeCall::Contracts(crate::Call::eth_transact { - payload, - gas_limit, - storage_deposit_limit, - }); - - let encoded_len = call.encoded_size(); - let uxt: Ex = generic::UncheckedExtrinsic::new_bare(call).into(); - let result: CheckedExtrinsic<_, _, _> = uxt.check(&TestContext {})?; - let (account_id, extra): (AccountId32, SignedExtra) = match result.format { - ExtrinsicFormat::Signed(signer, extra) => (signer, extra), - _ => unreachable!(), - }; - - extra.clone().validate_and_prepare( - RuntimeOrigin::signed(account_id), - &result.function, - &result.function.get_dispatch_info(), - encoded_len, - )?; + ExtBuilder::default().build().execute_with(|| { + let UncheckedExtrinsicBuilder { + tx, + gas_limit, + storage_deposit_limit, + before_validate, + } = self.clone(); + + // Fund the account. + let account = Account::default(); + let _ = ::Currency::set_balance( + &account.substrate_account(), + 100_000_000_000_000, + ); + + let payload = + account.sign_transaction(tx.try_into_unsigned().unwrap()).signed_payload(); + let call = RuntimeCall::Contracts(crate::Call::eth_transact { + payload, + gas_limit, + storage_deposit_limit, + }); + + let encoded_len = call.encoded_size(); + let uxt: Ex = generic::UncheckedExtrinsic::new_bare(call).into(); + let result: CheckedExtrinsic<_, _, _> = uxt.check(&TestContext {})?; + let (account_id, extra): (AccountId32, SignedExtra) = match result.format { + ExtrinsicFormat::Signed(signer, extra) => (signer, extra), + _ => unreachable!(), + }; - Ok((result.function, extra)) + before_validate.map(|f| f()); + extra.clone().validate_and_prepare( + RuntimeOrigin::signed(account_id), + &result.function, + &result.function.get_dispatch_info(), + encoded_len, + 0, + )?; + + Ok((result.function, extra)) + }) } } #[test] fn check_eth_transact_call_works() { - ExtBuilder::default().build().execute_with(|| { - let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); - assert_eq!( - builder.check().unwrap().0, - crate::Call::call:: { - dest: builder.tx.to.unwrap(), - value: builder.tx.value.as_u64(), - gas_limit: builder.gas_limit, - storage_deposit_limit: builder.storage_deposit_limit, - data: builder.tx.input.0 - } - .into() - ); - }); + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); + assert_eq!( + builder.check().unwrap().0, + crate::Call::call:: { + dest: builder.tx.to.unwrap(), + value: builder.tx.value.unwrap_or_default().as_u64(), + gas_limit: builder.gas_limit, + storage_deposit_limit: builder.storage_deposit_limit, + data: builder.tx.input.unwrap_or_default().0 + } + .into() + ); } #[test] fn check_eth_transact_instantiate_works() { - ExtBuilder::default().build().execute_with(|| { - let (code, _) = compile_module("dummy").unwrap(); - let data = vec![]; - let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); - - assert_eq!( - builder.check().unwrap().0, - crate::Call::instantiate_with_code:: { - value: builder.tx.value.as_u64(), - gas_limit: builder.gas_limit, - storage_deposit_limit: builder.storage_deposit_limit, - code, - data, - salt: None - } - .into() - ); - }); + let (code, _) = compile_module("dummy").unwrap(); + let data = vec![]; + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); + + assert_eq!( + builder.check().unwrap().0, + crate::Call::instantiate_with_code:: { + value: builder.tx.value.unwrap_or_default().as_u64(), + gas_limit: builder.gas_limit, + storage_deposit_limit: builder.storage_deposit_limit, + code, + data, + salt: None + } + .into() + ); } #[test] fn check_eth_transact_nonce_works() { - ExtBuilder::default().build().execute_with(|| { - let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) - .update(|tx| tx.nonce = 1u32.into()); - - assert_eq!( - builder.check(), - Err(TransactionValidityError::Invalid(InvalidTransaction::Future)) - ); - - >::inc_account_nonce(Account::default().account_id()); - - let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); - assert_eq!( - builder.check(), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)) - ); - }); + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) + .update(|tx| tx.nonce = Some(1u32.into())); + + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Future)) + ); + + let builder = + UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])).before_validate(|| { + >::inc_account_nonce(Account::default().substrate_account()); + }); + + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)) + ); } #[test] fn check_eth_transact_chain_id_works() { - ExtBuilder::default().build().execute_with(|| { - let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) - .update(|tx| tx.chain_id = Some(42.into())); - - assert_eq!( - builder.check(), - Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) - ); - }); + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) + .update(|tx| tx.chain_id = Some(42.into())); + + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); } #[test] fn check_instantiate_data() { - ExtBuilder::default().build().execute_with(|| { - let code = b"invalid code".to_vec(); - let data = vec![1]; - let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); - - // Fail because the tx input fail to get the blob length - assert_eq!( - builder.clone().update(|tx| tx.input = Bytes(vec![1, 2, 3])).check(), - Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) - ); - }); + let code = b"invalid code".to_vec(); + let data = vec![1]; + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); + + // Fail because the tx input fail to get the blob length + assert_eq!( + builder.clone().update(|tx| tx.input = Some(Bytes(vec![1, 2, 3]))).check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); } #[test] fn check_transaction_fees() { - ExtBuilder::default().build().execute_with(|| { - let scenarios: [(_, Box, _); 5] = [ - ("Eth fees too low", Box::new(|tx| tx.gas_price /= 2), InvalidTransaction::Payment), - ("Gas fees too high", Box::new(|tx| tx.gas *= 2), InvalidTransaction::Call), - ("Gas fees too low", Box::new(|tx| tx.gas *= 2), InvalidTransaction::Call), - ( - "Diff > 10%", - Box::new(|tx| tx.gas = tx.gas * 111 / 100), - InvalidTransaction::Call, - ), - ( - "Diff < 10%", - Box::new(|tx| { - tx.gas_price *= 2; - tx.gas = tx.gas * 89 / 100 - }), - InvalidTransaction::Call, - ), - ]; - - for (msg, update_tx, err) in scenarios { - let builder = - UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])).update(update_tx); - - assert_eq!(builder.check(), Err(TransactionValidityError::Invalid(err)), "{}", msg); - } - }); + let scenarios: [(_, Box, _); 5] = [ + ( + "Eth fees too low", + Box::new(|tx| { + tx.gas_price = Some(tx.gas_price.unwrap() / 2); + }), + InvalidTransaction::Payment, + ), + ( + "Gas fees too high", + Box::new(|tx| { + tx.gas = Some(tx.gas.unwrap() * 2); + }), + InvalidTransaction::Call, + ), + ( + "Gas fees too low", + Box::new(|tx| { + tx.gas = Some(tx.gas.unwrap() * 2); + }), + InvalidTransaction::Call, + ), + ( + "Diff > 10%", + Box::new(|tx| { + tx.gas = Some(tx.gas.unwrap() * 111 / 100); + }), + InvalidTransaction::Call, + ), + ( + "Diff < 10%", + Box::new(|tx| { + tx.gas_price = Some(tx.gas_price.unwrap() * 2); + tx.gas = Some(tx.gas.unwrap() * 89 / 100); + }), + InvalidTransaction::Call, + ), + ]; + + for (msg, update_tx, err) in scenarios { + let builder = + UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])).update(update_tx); + + assert_eq!(builder.check(), Err(TransactionValidityError::Invalid(err)), "{}", msg); + } } #[test] fn check_transaction_tip() { - ExtBuilder::default().build().execute_with(|| { - let (code, _) = compile_module("dummy").unwrap(); - let data = vec![]; - let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()) - .update(|tx| tx.gas_price = tx.gas_price * 103 / 100); - - let tx = &builder.tx; - let expected_tip = tx.gas_price * tx.gas - U256::from(GAS_PRICE) * tx.gas; - let (_, extra) = builder.check().unwrap(); - assert_eq!(U256::from(extra.1.tip()), expected_tip); - }); + let (code, _) = compile_module("dummy").unwrap(); + let data = vec![]; + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()) + .update(|tx| { + tx.gas_price = Some(tx.gas_price.unwrap() * 103 / 100); + log::debug!(target: LOG_TARGET, "Gas price: {:?}", tx.gas_price); + }); + + let tx = &builder.tx; + let expected_tip = + tx.gas_price.unwrap() * tx.gas.unwrap() - U256::from(GAS_PRICE) * tx.gas.unwrap(); + let (_, extra) = builder.check().unwrap(); + assert_eq!(U256::from(extra.1.tip()), expected_tip); } } diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 943c377e504d..a6a259149768 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -210,7 +210,13 @@ pub trait Ext: sealing::Sealed { /// 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<(), ExecError>; + fn delegate_call( + &mut self, + gas_limit: Weight, + deposit_limit: U256, + address: H160, + input_data: Vec, + ) -> Result<(), ExecError>; /// Instantiate a contract from the given code. /// @@ -236,9 +242,6 @@ pub trait Ext: sealing::Sealed { /// call stack. fn terminate(&mut self, beneficiary: &H160) -> DispatchResult; - /// Transfer some amount of funds into the specified account. - fn transfer(&mut self, to: &H160, value: U256) -> DispatchResult; - /// Returns the storage entry of the executing account by the given `key`. /// /// Returns `None` if the `key` wasn't previously set by `set_storage` or @@ -295,7 +298,7 @@ pub trait Ext: sealing::Sealed { fn code_hash(&self, address: &H160) -> H256; /// Returns the code size of the contract at the given `address` or zero. - fn code_size(&self, address: &H160) -> U256; + fn code_size(&self, address: &H160) -> u64; /// Returns the code hash of the contract being executed. fn own_code_hash(&mut self) -> &H256; @@ -559,6 +562,9 @@ pub struct Stack<'a, T: Config, E> { debug_message: Option<&'a mut DebugBuffer>, /// Transient storage used to store data, which is kept for the duration of a transaction. transient_storage: TransientStorage, + /// Whether or not actual transfer of funds should be performed. + /// This is set to `true` exclusively when we simulate a call through eth_transact. + skip_transfer: bool, /// No executable is held by the struct but influences its behaviour. _phantom: PhantomData, } @@ -572,8 +578,8 @@ struct Frame { account_id: T::AccountId, /// The cached in-storage data of the contract. contract_info: CachedContract, - /// The amount of balance transferred by the caller as part of the call. - value_transferred: BalanceOf, + /// The EVM balance transferred by the caller as part of the call. + value_transferred: U256, /// Determines whether this is a call or instantiate frame. entry_point: ExportedFunction, /// The gas meter capped to the supplied gas limit. @@ -584,18 +590,30 @@ struct Frame { allows_reentry: bool, /// If `true` subsequent calls cannot modify storage. read_only: bool, - /// The caller of the currently executing frame which was spawned by `delegate_call`. - delegate_caller: Option>, + /// The delegate call info of the currently executing frame which was spawned by + /// `delegate_call`. + delegate: Option>, /// The output of the last executed call frame. last_frame_output: ExecReturnValue, } +/// This structure is used to represent the arguments in a delegate call frame in order to +/// distinguish who delegated the call and where it was delegated to. +struct DelegateInfo { + /// The caller of the contract. + pub caller: Origin, + /// The address of the contract the call was delegated to. + pub callee: H160, +} + /// Used in a delegate call frame arguments in order to override the executable and caller. struct DelegatedCall { /// The executable which is run instead of the contracts own `executable`. executable: E, /// The caller of the contract. caller: Origin, + /// The address of the contract the call was delegated to. + callee: H160, } /// Parameter passed in when creating a new `Frame`. @@ -760,8 +778,9 @@ where dest: H160, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, input_data: Vec, + skip_transfer: bool, debug_message: Option<&'a mut DebugBuffer>, ) -> ExecResult { let dest = T::AddressMapper::to_account_id(&dest); @@ -771,11 +790,12 @@ where gas_meter, storage_meter, value, + skip_transfer, debug_message, )? { stack.run(executable, input_data).map(|_| stack.first_frame.last_frame_output) } else { - Self::transfer_from_origin(&origin, &dest, value) + Self::transfer_from_origin(&origin, &origin, &dest, value) } } @@ -794,9 +814,10 @@ where executable: E, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, input_data: Vec, salt: Option<&[u8; 32]>, + skip_transfer: bool, debug_message: Option<&'a mut DebugBuffer>, ) -> Result<(H160, ExecReturnValue), ExecError> { let (mut stack, executable) = Self::new( @@ -810,6 +831,7 @@ where gas_meter, storage_meter, value, + skip_transfer, debug_message, )? .expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE); @@ -837,7 +859,8 @@ where origin, gas_meter, storage_meter, - value, + value.into(), + false, debug_message, ) .unwrap() @@ -846,14 +869,15 @@ where /// Create a new call stack. /// - /// Returns `None` when calling a non existant contract. This is not an error case + /// Returns `None` when calling a non existent contract. This is not an error case /// since this will result in a value transfer. fn new( args: FrameArgs, origin: Origin, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, + skip_transfer: bool, debug_message: Option<&'a mut DebugBuffer>, ) -> Result, ExecError> { origin.ensure_mapped()?; @@ -881,6 +905,7 @@ where frames: Default::default(), debug_message, transient_storage: TransientStorage::new(limits::TRANSIENT_STORAGE_BYTES), + skip_transfer, _phantom: Default::default(), }; @@ -893,7 +918,7 @@ where /// not initialized, yet. fn new_frame( frame_args: FrameArgs, - value_transferred: BalanceOf, + value_transferred: U256, gas_meter: &mut GasMeter, gas_limit: Weight, storage_meter: &mut storage::meter::GenericMeter, @@ -901,8 +926,7 @@ where read_only: bool, origin_is_caller: bool, ) -> Result, E)>, ExecError> { - let (account_id, contract_info, executable, delegate_caller, entry_point) = match frame_args - { + let (account_id, contract_info, executable, delegate, entry_point) = match frame_args { FrameArgs::Call { dest, cached_info, delegated_call } => { let contract = if let Some(contract) = cached_info { contract @@ -917,8 +941,8 @@ where }; let (executable, delegate_caller) = - if let Some(DelegatedCall { executable, caller }) = delegated_call { - (executable, Some(caller)) + if let Some(DelegatedCall { executable, caller, callee }) = delegated_call { + (executable, Some(DelegateInfo { caller, callee })) } else { (E::from_storage(contract.code_hash, gas_meter)?, None) }; @@ -934,8 +958,8 @@ where use sp_runtime::Saturating; address::create1( &deployer, - // the Nonce from the origin has been incremented pre-dispatch, so we need - // to subtract 1 to get the nonce at the time of the call. + // the Nonce from the origin has been incremented pre-dispatch, so we + // need to subtract 1 to get the nonce at the time of the call. if origin_is_caller { account_nonce.saturating_sub(1u32.into()).saturated_into() } else { @@ -959,7 +983,7 @@ where }; let frame = Frame { - delegate_caller, + delegate, value_transferred, contract_info: CachedContract::Cached(contract_info), account_id, @@ -978,7 +1002,7 @@ where fn push_frame( &mut self, frame_args: FrameArgs, - value_transferred: BalanceOf, + value_transferred: U256, gas_limit: Weight, deposit_limit: BalanceOf, read_only: bool, @@ -1028,7 +1052,7 @@ where 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 }; + if frame.delegate.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. @@ -1044,7 +1068,7 @@ where self.transient_storage.start_transaction(); - let do_transaction = || { + let do_transaction = || -> ExecResult { let caller = self.caller(); let frame = top_frame_mut!(self); @@ -1059,6 +1083,7 @@ where &frame.account_id, frame.contract_info.get(&frame.account_id), executable.code_info(), + self.skip_transfer, )?; // Needs to be incremented before calling into the code so that it is visible // in case of recursion. @@ -1069,7 +1094,12 @@ where // If it is a delegate call, then we've already transferred tokens in the // last non-delegate frame. if delegated_code_hash.is_none() { - Self::transfer_from_origin(&caller, &frame.account_id, frame.value_transferred)?; + Self::transfer_from_origin( + &self.origin, + &caller, + &frame.account_id, + frame.value_transferred, + )?; } let contract_address = T::AddressMapper::to_address(&top_frame!(self).account_id); @@ -1077,11 +1107,8 @@ where let call_span = T::Debug::new_call_span(&contract_address, entry_point, &input_data); let output = T::Debug::intercept_call(&contract_address, entry_point, &input_data) - .unwrap_or_else(|| { - executable - .execute(self, entry_point, input_data) - .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee }) - })?; + .unwrap_or_else(|| executable.execute(self, entry_point, input_data)) + .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?; call_span.after_call(&output); @@ -1101,7 +1128,16 @@ where frame.nested_storage.enforce_limit(contract)?; } - let frame = self.top_frame(); + let frame = self.top_frame_mut(); + + // If a special limit was set for the sub-call, we enforce it here. + // The sub-call will be rolled back in case the limit is exhausted. + let contract = frame.contract_info.as_contract(); + frame + .nested_storage + .enforce_subcall_limit(contract) + .map_err(|e| ExecError { error: e, origin: ErrorOrigin::Callee })?; + let account_id = T::AddressMapper::to_address(&frame.account_id); match (entry_point, delegated_code_hash) { (ExportedFunction::Constructor, _) => { @@ -1110,15 +1146,7 @@ where return Err(Error::::TerminatedInConstructor.into()); } - // If a special limit was set for the sub-call, we enforce it here. - // This is needed because contract constructor might write to storage. - // The sub-call will be rolled back in case the limit is exhausted. - let frame = self.top_frame_mut(); - let contract = frame.contract_info.as_contract(); - frame.nested_storage.enforce_subcall_limit(contract)?; - let caller = T::AddressMapper::to_address(self.caller().account_id()?); - // Deposit an instantiation event. Contracts::::deposit_event(Event::Instantiated { deployer: caller, @@ -1132,12 +1160,6 @@ where }); }, (ExportedFunction::Call, None) => { - // If a special limit was set for the sub-call, we enforce it here. - // The sub-call will be rolled back in case the limit is exhausted. - let frame = self.top_frame_mut(); - let contract = frame.contract_info.as_contract(); - frame.nested_storage.enforce_subcall_limit(contract)?; - let caller = self.caller(); Contracts::::deposit_event(Event::Called { caller: caller.clone(), @@ -1265,22 +1287,52 @@ where } /// Transfer some funds from `from` to `to`. - fn transfer(from: &T::AccountId, to: &T::AccountId, value: BalanceOf) -> ExecResult { - // this avoids events to be emitted for zero balance transfers - if !value.is_zero() { - T::Currency::transfer(from, to, value, Preservation::Preserve).map_err(|err| { - log::debug!(target: LOG_TARGET, "Transfer of {value:?} from {from:?} to {to:?} failed: {err:?}"); - Error::::TransferFailed - })?; + /// + /// This is a no-op for zero `value`, avoiding events to be emitted for zero balance transfers. + /// + /// If the destination account does not exist, it is pulled into existence by transferring the + /// ED from `origin` to the new account. The total amount transferred to `to` will be ED + + /// `value`. This makes the ED fully transparent for contracts. + /// The ED transfer is executed atomically with the actual transfer, avoiding the possibility of + /// the ED transfer succeeding but the actual transfer failing. In other words, if the `to` does + /// not exist, the transfer does fail and nothing will be sent to `to` if either `origin` can + /// not provide the ED or transferring `value` from `from` to `to` fails. + /// Note: This will also fail if `origin` is root. + fn transfer( + origin: &Origin, + from: &T::AccountId, + to: &T::AccountId, + value: U256, + ) -> ExecResult { + let value = crate::Pallet::::convert_evm_to_native(value)?; + if value.is_zero() { + return Ok(Default::default()); + } + + if >::account_exists(to) { + return T::Currency::transfer(from, to, value, Preservation::Preserve) + .map(|_| Default::default()) + .map_err(|_| Error::::TransferFailed.into()); } - Ok(Default::default()) + + let origin = origin.account_id()?; + let ed = ::Currency::minimum_balance(); + with_transaction(|| -> TransactionOutcome { + match T::Currency::transfer(origin, to, ed, Preservation::Preserve) + .and_then(|_| T::Currency::transfer(from, to, value, Preservation::Preserve)) + { + Ok(_) => TransactionOutcome::Commit(Ok(Default::default())), + Err(_) => TransactionOutcome::Rollback(Err(Error::::TransferFailed.into())), + } + }) } /// Same as `transfer` but `from` is an `Origin`. fn transfer_from_origin( + origin: &Origin, from: &Origin, to: &T::AccountId, - value: BalanceOf, + value: U256, ) -> ExecResult { // If the from address is root there is no account to transfer from, and therefore we can't // take any `value` other than 0. @@ -1289,7 +1341,7 @@ where Origin::Root if value.is_zero() => return Ok(Default::default()), Origin::Root => return Err(DispatchError::RootNotAllowed.into()), }; - Self::transfer(from, to, value) + Self::transfer(origin, from, to, value) } /// Reference to the current (top) frame. @@ -1327,7 +1379,11 @@ where /// Returns the *free* balance of the supplied AccountId. fn account_balance(&self, who: &T::AccountId) -> U256 { - T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Polite).into() + crate::Pallet::::convert_native_to_evm(T::Currency::reducible_balance( + who, + Preservation::Preserve, + Fortitude::Polite, + )) } /// Certain APIs, e.g. `{set,get}_immutable_data` behave differently depending @@ -1413,7 +1469,13 @@ where )? { self.run(executable, input_data) } else { - Self::transfer(&self.account_id(), &dest, value).map(|_| ()) + Self::transfer_from_origin( + &self.origin, + &Origin::from_account_id(self.account_id().clone()), + &dest, + value, + )?; + Ok(()) } }; @@ -1426,11 +1488,20 @@ where result } - fn delegate_call(&mut self, code_hash: H256, input_data: Vec) -> Result<(), ExecError> { + fn delegate_call( + &mut self, + gas_limit: Weight, + deposit_limit: U256, + address: H160, + input_data: Vec, + ) -> Result<(), ExecError> { // We reset the return data now, so it is cleared out even if no new frame was executed. // This is for example the case for unknown code hashes or creating the frame fails. *self.last_frame_output_mut() = Default::default(); + let code_hash = ContractInfoOf::::get(&address) + .ok_or(Error::::CodeNotFound) + .map(|c| c.code_hash)?; 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(); @@ -1440,11 +1511,15 @@ where FrameArgs::Call { dest: account_id, cached_info: Some(contract_info), - delegated_call: Some(DelegatedCall { executable, caller: self.caller().clone() }), + delegated_call: Some(DelegatedCall { + executable, + caller: self.caller().clone(), + callee: address, + }), }, value, - Weight::zero(), - BalanceOf::::zero(), + gas_limit, + deposit_limit.try_into().map_err(|_| Error::::BalanceConversionFailed)?, self.is_read_only(), )?; self.run(executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE), input_data) @@ -1511,16 +1586,6 @@ where Ok(()) } - fn transfer(&mut self, to: &H160, value: U256) -> DispatchResult { - Self::transfer( - &self.top_frame().account_id, - &T::AddressMapper::to_account_id(to), - value.try_into().map_err(|_| Error::::BalanceConversionFailed)?, - ) - .map(|_| ()) - .map_err(|error| error.error) - } - fn get_storage(&mut self, key: &Key) -> Option> { self.top_frame_mut().contract_info().read(key) } @@ -1569,7 +1634,7 @@ where } fn caller(&self) -> Origin { - if let Some(caller) = &self.top_frame().delegate_caller { + if let Some(DelegateInfo { caller, .. }) = &self.top_frame().delegate { caller.clone() } else { self.frames() @@ -1598,7 +1663,7 @@ where }) } - fn code_size(&self, address: &H160) -> U256 { + fn code_size(&self, address: &H160) -> u64 { >::get(&address) .and_then(|contract| CodeInfoOf::::get(contract.code_hash)) .map(|info| info.code_len()) @@ -1623,7 +1688,13 @@ where return Err(Error::::InvalidImmutableAccess.into()); } - let address = T::AddressMapper::to_address(self.account_id()); + // Immutable is read from contract code being executed + let address = self + .top_frame() + .delegate + .as_ref() + .map(|d| d.callee) + .unwrap_or(T::AddressMapper::to_address(self.account_id())); Ok(>::get(address).ok_or_else(|| Error::::InvalidImmutableAccess)?) } @@ -1885,7 +1956,7 @@ mod tests { AddressMapper, Error, }; use assert_matches::assert_matches; - use frame_support::{assert_err, assert_ok, parameter_types}; + use frame_support::{assert_err, assert_noop, assert_ok, parameter_types}; use frame_system::{AccountInfo, EventRecord, Phase}; use pallet_revive_uapi::ReturnFlags; use pretty_assertions::assert_eq; @@ -2039,8 +2110,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - value, + value.into(), vec![], + false, None, ), Ok(_) @@ -2058,10 +2130,55 @@ mod tests { set_balance(&ALICE, 100); set_balance(&BOB, 0); - MockStack::transfer(&ALICE, &BOB, 55).unwrap(); + let origin = Origin::from_account_id(ALICE); + MockStack::transfer(&origin, &ALICE, &BOB, 55u64.into()).unwrap(); - assert_eq!(get_balance(&ALICE), 45); - assert_eq!(get_balance(&BOB), 55); + let min_balance = ::Currency::minimum_balance(); + assert_eq!(get_balance(&ALICE), 45 - min_balance); + assert_eq!(get_balance(&BOB), 55 + min_balance); + }); + } + + #[test] + fn transfer_to_nonexistent_account_works() { + // This test verifies that a contract is able to transfer + // some funds to a nonexistant account and that those transfers + // are not able to reap accounts. + ExtBuilder::default().build().execute_with(|| { + let ed = ::Currency::minimum_balance(); + let value = 1024; + + // Transfers to nonexistant accounts should work + set_balance(&ALICE, ed * 2); + set_balance(&BOB, ed + value); + + assert_ok!(MockStack::transfer( + &Origin::from_account_id(ALICE), + &BOB, + &CHARLIE, + value.into() + )); + assert_eq!(get_balance(&ALICE), ed); + assert_eq!(get_balance(&BOB), ed); + assert_eq!(get_balance(&CHARLIE), ed + value); + + // Do not reap the origin account + set_balance(&ALICE, ed); + set_balance(&BOB, ed + value); + assert_err!( + MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &DJANGO, value.into()), + >::TransferFailed + ); + + // Do not reap the sender account + set_balance(&ALICE, ed * 2); + set_balance(&BOB, value); + assert_err!( + MockStack::transfer(&Origin::from_account_id(ALICE), &BOB, &EVE, value.into()), + >::TransferFailed + ); + // The ED transfer would work. But it should only be executed with the actual transfer + assert!(!System::account_exists(&EVE)); }); } @@ -2086,8 +2203,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], + false, None, ) .unwrap(); @@ -2108,33 +2226,87 @@ mod tests { let delegate_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), U256::from(value)); - let _ = ctx.ext.delegate_call(success_ch, Vec::new())?; + let _ = + ctx.ext.delegate_call(Weight::zero(), U256::zero(), CHARLIE_ADDR, Vec::new())?; Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { place_contract(&BOB, delegate_ch); + place_contract(&CHARLIE, success_ch); set_balance(&ALICE, 100); let balance = get_balance(&BOB_FALLBACK); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 0, 55).unwrap(); - let _ = MockStack::run_call( + assert_ok!(MockStack::run_call( origin, BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], + false, None, - ) - .unwrap(); + )); assert_eq!(get_balance(&ALICE), 100 - value); assert_eq!(get_balance(&BOB_FALLBACK), balance + value); }); } + #[test] + fn delegate_call_missing_contract() { + let missing_ch = MockLoader::insert(Call, move |_ctx, _| { + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) + }); + + let delegate_ch = MockLoader::insert(Call, move |ctx, _| { + let _ = + ctx.ext.delegate_call(Weight::zero(), U256::zero(), CHARLIE_ADDR, Vec::new())?; + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, delegate_ch); + set_balance(&ALICE, 100); + + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 0, 55).unwrap(); + + // contract code missing + assert_noop!( + MockStack::run_call( + origin.clone(), + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + U256::zero(), + vec![], + false, + None, + ), + ExecError { + error: Error::::CodeNotFound.into(), + origin: ErrorOrigin::Callee, + } + ); + + // add missing contract code + place_contract(&CHARLIE, missing_ch); + assert_ok!(MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + U256::zero(), + vec![], + false, + None, + )); + }); + } + #[test] fn changes_are_reverted_on_failing_call() { // This test verifies that changes are reverted on a call which fails (or equally, returns @@ -2156,8 +2328,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 55, + 55u64.into(), vec![], + false, None, ) .unwrap(); @@ -2172,16 +2345,17 @@ mod tests { fn balance_too_low() { // This test verifies that a contract can't send value if it's // balance is too low. - let origin = ALICE; + let from = ALICE; + let origin = Origin::from_account_id(ALICE); let dest = BOB; ExtBuilder::default().build().execute_with(|| { - set_balance(&origin, 0); + set_balance(&from, 0); - let result = MockStack::transfer(&origin, &dest, 100); + let result = MockStack::transfer(&origin, &from, &dest, 100u64.into()); assert_eq!(result, Err(Error::::TransferFailed.into())); - assert_eq!(get_balance(&origin), 0); + assert_eq!(get_balance(&from), 0); assert_eq!(get_balance(&dest), 0); }); } @@ -2204,8 +2378,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); @@ -2233,8 +2408,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); @@ -2262,8 +2438,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![1, 2, 3, 4], + false, None, ); assert_matches!(result, Ok(_)); @@ -2297,9 +2474,10 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - min_balance, + min_balance.into(), vec![1, 2, 3, 4], Some(&[0; 32]), + false, None, ); assert_matches!(result, Ok(_)); @@ -2352,8 +2530,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], + false, None, ); @@ -2416,8 +2595,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); @@ -2481,8 +2661,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); @@ -2513,8 +2694,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); assert_matches!(result, Ok(_)); @@ -2550,8 +2732,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -2576,8 +2759,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -2620,8 +2804,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -2646,8 +2831,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -2672,8 +2858,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 1, + 1u64.into(), vec![0], + false, None, ); assert_matches!(result, Err(_)); @@ -2716,8 +2903,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -2761,8 +2949,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); @@ -2786,9 +2975,10 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 0, // <- zero value + U256::zero(), // <- zero value vec![], Some(&[0; 32]), + false, None, ), Err(_) @@ -2821,10 +3011,10 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - - min_balance, + min_balance.into(), vec![], Some(&[0 ;32]), + false, None, ), Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address @@ -2876,10 +3066,10 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - - min_balance, + min_balance.into(), vec![], Some(&[0; 32]), + false, None, ), Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address @@ -2942,8 +3132,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - min_balance * 10, + (min_balance * 10).into(), vec![], + false, None, ), Ok(_) @@ -3022,8 +3213,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ), Ok(_) @@ -3064,9 +3256,10 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 100, + 100u64.into(), vec![], Some(&[0; 32]), + false, None, ), Err(Error::::TerminatedInConstructor.into()) @@ -3129,8 +3322,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -3190,9 +3384,10 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 10, + 10u64.into(), vec![], Some(&[0; 32]), + false, None, ); assert_matches!(result, Ok(_)); @@ -3217,7 +3412,7 @@ mod tests { true, false ), - >::TransferFailed + >::TransferFailed, ); exec_success() }); @@ -3237,8 +3432,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap(); @@ -3268,8 +3464,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, Some(&mut debug_buffer), ) .unwrap(); @@ -3301,8 +3498,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, Some(&mut debug_buffer), ); assert!(result.is_err()); @@ -3334,8 +3532,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, Some(&mut debug_buf_after), ) .unwrap(); @@ -3367,8 +3566,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), CHARLIE_ADDR.as_bytes().to_vec(), + false, None, )); @@ -3379,8 +3579,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), BOB_ADDR.as_bytes().to_vec(), + false, None, ) .map_err(|e| e.error), @@ -3429,8 +3630,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ) .map_err(|e| e.error), @@ -3463,8 +3665,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap(); @@ -3547,8 +3750,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap(); @@ -3672,9 +3876,10 @@ mod tests { fail_executable, &mut gas_meter, &mut storage_meter, - min_balance * 100, + (min_balance * 100).into(), vec![], Some(&[0; 32]), + false, None, ) .ok(); @@ -3685,9 +3890,10 @@ mod tests { success_executable, &mut gas_meter, &mut storage_meter, - min_balance * 100, + (min_balance * 100).into(), vec![], Some(&[0; 32]), + false, None, )); assert_eq!(System::account_nonce(&ALICE), 1); @@ -3697,9 +3903,10 @@ mod tests { succ_fail_executable, &mut gas_meter, &mut storage_meter, - min_balance * 200, + (min_balance * 200).into(), vec![], Some(&[0; 32]), + false, None, )); assert_eq!(System::account_nonce(&ALICE), 2); @@ -3709,9 +3916,10 @@ mod tests { succ_succ_executable, &mut gas_meter, &mut storage_meter, - min_balance * 200, + (min_balance * 200).into(), vec![], Some(&[0; 32]), + false, None, )); assert_eq!(System::account_nonce(&ALICE), 3); @@ -3778,8 +3986,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -3889,8 +4098,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -3928,8 +4138,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -3967,8 +4178,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -4020,8 +4232,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -4076,8 +4289,9 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -4151,8 +4365,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -4221,8 +4436,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -4259,8 +4475,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, )); }); @@ -4321,8 +4538,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -4354,8 +4572,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); assert_matches!(result, Ok(_)); @@ -4385,12 +4604,19 @@ mod tests { &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] } - ); + // Balance transfers should reset the output + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &address, + U256::from(1), + vec![], + true, + false, + ) + .unwrap(); + assert_eq!(ctx.ext.last_frame_output(), &Default::default()); // Reverted instantiation should set the output ctx.ext @@ -4430,8 +4656,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap() @@ -4498,8 +4725,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ); assert_matches!(result, Ok(_)); @@ -4531,7 +4759,12 @@ mod tests { // An unknown code hash to fail the delegate_call on the first condition. *ctx.ext.last_frame_output_mut() = output_revert(); assert_eq!( - ctx.ext.delegate_call(invalid_code_hash, Default::default()), + ctx.ext.delegate_call( + Weight::zero(), + U256::zero(), + H160([0xff; 20]), + Default::default() + ), Err(Error::::CodeNotFound.into()) ); assert_eq!(ctx.ext.last_frame_output(), &Default::default()); @@ -4564,8 +4797,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ); assert_matches!(result, Ok(_)); @@ -4615,8 +4849,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap() @@ -4648,14 +4883,12 @@ mod tests { Ok(vec![2]), ); - // In a delegate call, we should witness the caller immutable data + // Also in a delegate call, we should witness the callee immutable data assert_eq!( - ctx.ext.delegate_call(charlie_ch, Vec::new()).map(|_| ctx - .ext - .last_frame_output() - .data - .clone()), - Ok(vec![1]) + ctx.ext + .delegate_call(Weight::zero(), U256::zero(), CHARLIE_ADDR, Vec::new()) + .map(|_| ctx.ext.last_frame_output().data.clone()), + Ok(vec![2]) ); exec_success() @@ -4686,8 +4919,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap() @@ -4732,8 +4966,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap() @@ -4776,8 +5011,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], + false, None, ) .unwrap() @@ -4831,8 +5067,9 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], + false, None, ), Ok(_) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 5038ae44afad..b9a39e7ce4d3 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -41,13 +41,13 @@ pub mod test_utils; pub mod weights; use crate::{ - evm::{runtime::GAS_PRICE, TransactionLegacyUnsigned}, + evm::{runtime::GAS_PRICE, GenericTransaction}, exec::{AccountIdOf, ExecError, Executable, Ext, Key, Origin, Stack as ExecStack}, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager}, wasm::{CodeInfo, RuntimeCosts, WasmBlob}, }; -use alloc::boxed::Box; +use alloc::{boxed::Box, format, vec}; use codec::{Codec, Decode, Encode}; use environmental::*; use frame_support::{ @@ -59,6 +59,7 @@ use frame_support::{ pallet_prelude::DispatchClass, traits::{ fungible::{Inspect, Mutate, MutateHold}, + tokens::{Fortitude::Polite, Preservation::Preserve}, ConstU32, ConstU64, Contains, EnsureOrigin, Get, IsType, OriginTrait, Time, }, weights::{Weight, WeightMeter}, @@ -73,7 +74,7 @@ use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_core::{H160, H256, U256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Saturating}, + traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating, Zero}, DispatchError, }; @@ -114,19 +115,6 @@ const SENTINEL: u32 = u32::MAX; /// Example: `RUST_LOG=runtime::revive=debug my_code --dev` const LOG_TARGET: &str = "runtime::revive"; -/// This version determines which syscalls are available to contracts. -/// -/// Needs to be bumped every time a versioned syscall is added. -const API_VERSION: u16 = 0; - -#[test] -fn api_version_up_to_date() { - assert!( - API_VERSION == crate::wasm::HIGHEST_API_VERSION, - "A new versioned API has been added. The `API_VERSION` needs to be bumped." - ); -} - #[frame_support::pallet] pub mod pallet { use super::*; @@ -379,7 +367,7 @@ pub mod pallet { type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; type ChainId = ConstU64<0>; - type NativeToEthRatio = ConstU32<1_000_000>; + type NativeToEthRatio = ConstU32<1>; } } @@ -561,6 +549,8 @@ pub mod pallet { ExecutionFailed, /// Failed to convert a U256 to a Balance. BalanceConversionFailed, + /// Failed to convert an EVM balance to a native balance. + DecimalPrecisionLoss, /// Immutable data can only be set during deploys and only be read during calls. /// Additionally, it is only valid to set the data once and it must not be empty. InvalidImmutableAccess, @@ -620,14 +610,6 @@ pub mod pallet { #[pallet::storage] pub(crate) type AddressSuffix = StorageMap<_, Identity, H160, [u8; 12]>; - #[pallet::extra_constants] - impl Pallet { - #[pallet::constant_name(ApiVersion)] - fn api_version() -> u16 { - API_VERSION - } - } - #[pallet::hooks] impl Hooks> for Pallet { fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { @@ -765,7 +747,7 @@ pub mod pallet { /// /// # Parameters /// - /// * `payload`: The RLP-encoded [`crate::evm::TransactionLegacySigned`]. + /// * `payload`: The encoded [`crate::evm::TransactionSigned`]. /// * `gas_limit`: The gas limit enforced during contract execution. /// * `storage_deposit_limit`: The maximum balance that can be charged to the caller for /// storage usage. @@ -820,7 +802,7 @@ pub mod pallet { dest, value, gas_limit, - storage_deposit_limit, + DepositLimit::Balance(storage_deposit_limit), data, DebugInfo::Skip, CollectEvents::Skip, @@ -856,7 +838,7 @@ pub mod pallet { origin, value, gas_limit, - storage_deposit_limit, + DepositLimit::Balance(storage_deposit_limit), Code::Existing(code_hash), data, salt, @@ -922,7 +904,7 @@ pub mod pallet { origin, value, gas_limit, - storage_deposit_limit, + DepositLimit::Balance(storage_deposit_limit), Code::Upload(code), data, salt, @@ -1080,7 +1062,7 @@ fn dispatch_result( impl Pallet where - BalanceOf: Into + TryFrom, + BalanceOf: Into + TryFrom + Bounded, MomentOf: Into, T::Hash: frame_support::traits::IsType, { @@ -1095,7 +1077,7 @@ where dest: H160, value: BalanceOf, gas_limit: Weight, - storage_deposit_limit: BalanceOf, + storage_deposit_limit: DepositLimit>, data: Vec, debug: DebugInfo, collect_events: CollectEvents, @@ -1109,17 +1091,25 @@ where }; let try_call = || { let origin = Origin::from_runtime_origin(origin)?; - let mut storage_meter = StorageMeter::new(&origin, storage_deposit_limit, value)?; + let mut storage_meter = match storage_deposit_limit { + DepositLimit::Balance(limit) => StorageMeter::new(&origin, limit, value)?, + DepositLimit::Unchecked => StorageMeter::new_unchecked(BalanceOf::::max_value()), + }; let result = ExecStack::>::run_call( origin.clone(), dest, &mut gas_meter, &mut storage_meter, - value, + Self::convert_native_to_evm(value), data, + storage_deposit_limit.is_unchecked(), debug_message.as_mut(), )?; - storage_deposit = storage_meter.try_into_deposit(&origin)?; + storage_deposit = storage_meter + .try_into_deposit(&origin, storage_deposit_limit.is_unchecked()) + .inspect_err(|err| { + log::error!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}"); + })?; Ok(result) }; let result = Self::run_guarded(try_call); @@ -1148,7 +1138,7 @@ where origin: OriginFor, value: BalanceOf, gas_limit: Weight, - mut storage_deposit_limit: BalanceOf, + storage_deposit_limit: DepositLimit>, code: Code, data: Vec, salt: Option<[u8; 32]>, @@ -1159,13 +1149,24 @@ where let mut storage_deposit = Default::default(); let mut debug_message = if debug == DebugInfo::UnsafeDebug { Some(DebugBuffer::default()) } else { None }; + + let unchecked_deposit_limit = storage_deposit_limit.is_unchecked(); + let mut storage_deposit_limit = match storage_deposit_limit { + DepositLimit::Balance(limit) => limit, + DepositLimit::Unchecked => BalanceOf::::max_value(), + }; + let try_instantiate = || { let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?; let (executable, upload_deposit) = match code { Code::Upload(code) => { let upload_account = T::UploadOrigin::ensure_origin(origin)?; - let (executable, upload_deposit) = - Self::try_upload_code(upload_account, code, storage_deposit_limit)?; + let (executable, upload_deposit) = Self::try_upload_code( + upload_account, + code, + storage_deposit_limit, + unchecked_deposit_limit, + )?; storage_deposit_limit.saturating_reduce(upload_deposit); (executable, upload_deposit) }, @@ -1173,20 +1174,25 @@ where (WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()), }; let instantiate_origin = Origin::from_account_id(instantiate_account.clone()); - let mut storage_meter = - StorageMeter::new(&instantiate_origin, storage_deposit_limit, value)?; + let mut storage_meter = if unchecked_deposit_limit { + StorageMeter::new_unchecked(storage_deposit_limit) + } else { + StorageMeter::new(&instantiate_origin, storage_deposit_limit, value)? + }; + let result = ExecStack::>::run_instantiate( instantiate_account, executable, &mut gas_meter, &mut storage_meter, - value, + Self::convert_native_to_evm(value), data, salt.as_ref(), + unchecked_deposit_limit, debug_message.as_mut(), ); storage_deposit = storage_meter - .try_into_deposit(&instantiate_origin)? + .try_into_deposit(&instantiate_origin, unchecked_deposit_limit)? .saturating_add(&StorageDeposit::Charge(upload_deposit)); result }; @@ -1212,28 +1218,15 @@ where /// /// # Parameters /// - /// - `origin`: The origin of the call. - /// - `dest`: The destination address of the call. - /// - `value`: The value to transfer. - /// - `input`: The input data. + /// - `tx`: The Ethereum transaction to simulate. /// - `gas_limit`: The gas limit enforced during contract execution. - /// - `storage_deposit_limit`: The maximum balance that can be charged to the caller for storage - /// usage. /// - `utx_encoded_size`: A function that takes a call and returns the encoded size of the /// unchecked extrinsic. - /// - `debug`: Debugging configuration. - /// - `collect_events`: Event collection configuration. pub fn bare_eth_transact( - origin: T::AccountId, - dest: Option, - value: BalanceOf, - input: Vec, + mut tx: GenericTransaction, gas_limit: Weight, - storage_deposit_limit: BalanceOf, utx_encoded_size: impl Fn(Call) -> u32, - debug: DebugInfo, - collect_events: CollectEvents, - ) -> EthContractResult> + ) -> Result>, EthTransactError> where T: pallet_transaction_payment::Config, ::RuntimeCall: @@ -1244,149 +1237,205 @@ where T::Nonce: Into, T::Hash: frame_support::traits::IsType, { - log::debug!(target: LOG_TARGET, "bare_eth_transact: dest: {dest:?} value: {value:?} gas_limit: {gas_limit:?} storage_deposit_limit: {storage_deposit_limit:?}"); - // Get the nonce to encode in the tx. - let nonce: T::Nonce = >::account_nonce(&origin); - - // Use a big enough gas price to ensure that the encoded size is large enough. - let max_gas_fee: BalanceOf = - (pallet_transaction_payment::Pallet::::weight_to_fee(Weight::MAX) / - GAS_PRICE.into()) - .into(); + log::debug!(target: LOG_TARGET, "bare_eth_transact: tx: {tx:?} gas_limit: {gas_limit:?}"); - // A contract call. - if let Some(dest) = dest { - // Dry run the call. - let result = crate::Pallet::::bare_call( - T::RuntimeOrigin::signed(origin), - dest, - value, - gas_limit, - storage_deposit_limit, - input.clone(), - debug, - collect_events, - ); + let from = tx.from.unwrap_or_default(); + let origin = T::AddressMapper::to_account_id(&from); - // Get the encoded size of the transaction. - let tx = TransactionLegacyUnsigned { - value: value.into().saturating_mul(T::NativeToEthRatio::get().into()), - input: input.into(), - nonce: nonce.into(), - chain_id: Some(T::ChainId::get().into()), - gas_price: GAS_PRICE.into(), - gas: max_gas_fee.into(), - to: Some(dest), - ..Default::default() - }; + let storage_deposit_limit = if tx.gas.is_some() { + DepositLimit::Balance(BalanceOf::::max_value()) + } else { + DepositLimit::Unchecked + }; - let eth_dispatch_call = crate::Call::::eth_transact { - payload: tx.dummy_signed_payload(), - gas_limit: result.gas_required, - storage_deposit_limit: result.storage_deposit.charge_or_zero(), - }; - let encoded_len = utx_encoded_size(eth_dispatch_call); + // TODO remove once we have revisited how we encode the gas limit. + if tx.nonce.is_none() { + tx.nonce = Some(>::account_nonce(&origin).into()); + } + if tx.gas_price.is_none() { + tx.gas_price = Some(GAS_PRICE.into()); + } + if tx.chain_id.is_none() { + tx.chain_id = Some(T::ChainId::get().into()); + } - // Get the dispatch info of the call. - let dispatch_call: ::RuntimeCall = crate::Call::::call { - dest, - value, - gas_limit: result.gas_required, - storage_deposit_limit: result.storage_deposit.charge_or_zero(), - data: tx.input.0, + // Convert the value to the native balance type. + let evm_value = tx.value.unwrap_or_default(); + let native_value = match Self::convert_evm_to_native(evm_value) { + Ok(v) => v, + Err(_) => return Err(EthTransactError::Message("Failed to convert value".into())), + }; + + let input = tx.input.clone().unwrap_or_default().0; + let debug = DebugInfo::Skip; + let collect_events = CollectEvents::Skip; + + let extract_error = |err| { + if err == Error::::TransferFailed.into() || + err == Error::::StorageDepositNotEnoughFunds.into() || + err == Error::::StorageDepositLimitExhausted.into() + { + let balance = Self::evm_balance(&from); + return Err(EthTransactError::Message( + format!("insufficient funds for gas * price + value: address {from:?} have {balance} (supplied gas {})", + tx.gas.unwrap_or_default())) + ); } - .into(); - let dispatch_info = dispatch_call.get_dispatch_info(); - // Compute the fee. - let fee = pallet_transaction_payment::Pallet::::compute_fee( - encoded_len, - &dispatch_info, - 0u32.into(), - ) - .into(); + return Err(EthTransactError::Message(format!( + "Failed to instantiate contract: {err:?}" + ))); + }; - log::trace!(target: LOG_TARGET, "bare_eth_call: len: {encoded_len:?} fee: {fee:?}"); - EthContractResult { - gas_required: result.gas_required, - storage_deposit: result.storage_deposit.charge_or_zero(), - result: result.result.map(|v| v.data), - fee, - } + // Dry run the call + let (mut result, dispatch_info) = match tx.to { + // A contract call. + Some(dest) => { + // Dry run the call. + let result = crate::Pallet::::bare_call( + T::RuntimeOrigin::signed(origin), + dest, + native_value, + gas_limit, + storage_deposit_limit, + input.clone(), + debug, + collect_events, + ); + + let data = match result.result { + Ok(return_value) => { + if return_value.did_revert() { + return Err(EthTransactError::Data(return_value.data)); + } + return_value.data + }, + Err(err) => { + log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}"); + return extract_error(err) + }, + }; + + let result = EthTransactInfo { + gas_required: result.gas_required, + storage_deposit: result.storage_deposit.charge_or_zero(), + data, + eth_gas: Default::default(), + }; + // Get the dispatch info of the call. + let dispatch_call: ::RuntimeCall = crate::Call::::call { + dest, + value: native_value, + gas_limit: result.gas_required, + storage_deposit_limit: result.storage_deposit, + data: input.clone(), + } + .into(); + (result, dispatch_call.get_dispatch_info()) + }, // A contract deployment - } else { - // Extract code and data from the input. - let (code, data) = match polkavm::ProgramBlob::blob_length(&input) { - Some(blob_len) => blob_len - .try_into() - .ok() - .and_then(|blob_len| (input.split_at_checked(blob_len))) - .unwrap_or_else(|| (&input[..], &[][..])), - _ => { - log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length"); - (&input[..], &[][..]) - }, - }; + None => { + // Extract code and data from the input. + let (code, data) = match polkavm::ProgramBlob::blob_length(&input) { + Some(blob_len) => blob_len + .try_into() + .ok() + .and_then(|blob_len| (input.split_at_checked(blob_len))) + .unwrap_or_else(|| (&input[..], &[][..])), + _ => { + log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length"); + (&input[..], &[][..]) + }, + }; - // Dry run the call. - let result = crate::Pallet::::bare_instantiate( - T::RuntimeOrigin::signed(origin), - value, - gas_limit, - storage_deposit_limit, - Code::Upload(code.to_vec()), - data.to_vec(), - None, - debug, - collect_events, - ); + // Dry run the call. + let result = crate::Pallet::::bare_instantiate( + T::RuntimeOrigin::signed(origin), + native_value, + gas_limit, + storage_deposit_limit, + Code::Upload(code.to_vec()), + data.to_vec(), + None, + debug, + collect_events, + ); + + let returned_data = match result.result { + Ok(return_value) => { + if return_value.result.did_revert() { + return Err(EthTransactError::Data(return_value.result.data)); + } + return_value.result.data + }, + Err(err) => { + log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}"); + return extract_error(err) + }, + }; + + let result = EthTransactInfo { + gas_required: result.gas_required, + storage_deposit: result.storage_deposit.charge_or_zero(), + data: returned_data, + eth_gas: Default::default(), + }; - // Get the encoded size of the transaction. - let tx = TransactionLegacyUnsigned { - gas: max_gas_fee.into(), - nonce: nonce.into(), - value: value.into().saturating_mul(T::NativeToEthRatio::get().into()), - input: input.clone().into(), - gas_price: GAS_PRICE.into(), - chain_id: Some(T::ChainId::get().into()), - ..Default::default() + // Get the dispatch info of the call. + let dispatch_call: ::RuntimeCall = + crate::Call::::instantiate_with_code { + value: native_value, + gas_limit: result.gas_required, + storage_deposit_limit: result.storage_deposit, + code: code.to_vec(), + data: data.to_vec(), + salt: None, + } + .into(); + (result, dispatch_call.get_dispatch_info()) + }, + }; + + // The transaction fees depend on the extrinsic's length, which in turn is influenced by + // the encoded length of the gas limit specified in the transaction (tx.gas). + // We iteratively compute the fee by adjusting tx.gas until the fee stabilizes. + // with a maximum of 3 iterations to avoid an infinite loop. + for _ in 0..3 { + let Ok(unsigned_tx) = tx.clone().try_into_unsigned() else { + log::debug!(target: LOG_TARGET, "Failed to convert to unsigned"); + return Err(EthTransactError::Message("Invalid transaction".into())); }; + let eth_dispatch_call = crate::Call::::eth_transact { - payload: tx.dummy_signed_payload(), + payload: unsigned_tx.dummy_signed_payload(), gas_limit: result.gas_required, - storage_deposit_limit: result.storage_deposit.charge_or_zero(), + storage_deposit_limit: result.storage_deposit, }; let encoded_len = utx_encoded_size(eth_dispatch_call); - - // Get the dispatch info of the call. - let dispatch_call: ::RuntimeCall = - crate::Call::::instantiate_with_code { - value, - gas_limit: result.gas_required, - storage_deposit_limit: result.storage_deposit.charge_or_zero(), - code: code.to_vec(), - data: data.to_vec(), - salt: None, - } - .into(); - let dispatch_info = dispatch_call.get_dispatch_info(); - - // Compute the fee. let fee = pallet_transaction_payment::Pallet::::compute_fee( encoded_len, &dispatch_info, 0u32.into(), ) .into(); + let eth_gas: U256 = (fee / GAS_PRICE.into()).into(); - log::trace!(target: LOG_TARGET, "bare_eth_call: len: {encoded_len:?} fee: {fee:?}"); - EthContractResult { - gas_required: result.gas_required, - storage_deposit: result.storage_deposit.charge_or_zero(), - result: result.result.map(|v| v.result.data), - fee, + if eth_gas == result.eth_gas { + log::trace!(target: LOG_TARGET, "bare_eth_call: encoded_len: {encoded_len:?} eth_gas: {eth_gas:?}"); + break; } + result.eth_gas = eth_gas; + tx.gas = Some(eth_gas.into()); + log::debug!(target: LOG_TARGET, "Adjusting Eth gas to: {eth_gas:?}"); } + + Ok(result) + } + + /// Get the balance with EVM decimals of the given `address`. + pub fn evm_balance(address: &H160) -> U256 { + let account = T::AddressMapper::to_account_id(&address); + Self::convert_native_to_evm(T::Currency::reducible_balance(&account, Preserve, Polite)) } /// A generalized version of [`Self::upload_code`]. @@ -1398,7 +1447,7 @@ where storage_deposit_limit: BalanceOf, ) -> CodeUploadResult> { let origin = T::UploadOrigin::ensure_origin(origin)?; - let (module, deposit) = Self::try_upload_code(origin, code, storage_deposit_limit)?; + let (module, deposit) = Self::try_upload_code(origin, code, storage_deposit_limit, false)?; Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit }) } @@ -1416,9 +1465,10 @@ where origin: T::AccountId, code: Vec, storage_deposit_limit: BalanceOf, + skip_transfer: bool, ) -> Result<(WasmBlob, BalanceOf), DispatchError> { let mut module = WasmBlob::from_code(code, origin)?; - let deposit = module.store_code()?; + let deposit = module.store_code(skip_transfer)?; ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); Ok((module, deposit)) } @@ -1441,6 +1491,25 @@ where .and_then(|r| r) }) } + + /// Convert a native balance to EVM balance. + fn convert_native_to_evm(value: BalanceOf) -> U256 { + value.into().saturating_mul(T::NativeToEthRatio::get().into()) + } + + /// Convert an EVM balance to a native balance. + fn convert_evm_to_native(value: U256) -> Result, Error> { + if value.is_zero() { + return Ok(Zero::zero()) + } + let ratio = T::NativeToEthRatio::get().into(); + let res = value.checked_div(ratio).expect("divisor is non-zero; qed"); + if res.saturating_mul(ratio) == value { + res.try_into().map_err(|_| Error::::BalanceConversionFailed) + } else { + Err(Error::::DecimalPrecisionLoss) + } + } } impl Pallet { @@ -1468,8 +1537,8 @@ sp_api::decl_runtime_apis! { BlockNumber: Codec, EventRecord: Codec, { - /// Returns the free balance of the given `[H160]` address. - fn balance(address: H160) -> Balance; + /// Returns the free balance of the given `[H160]` address, using EVM decimals. + fn balance(address: H160) -> U256; /// Returns the nonce of the given `[H160]` address. fn nonce(address: H160) -> Nonce; @@ -1503,14 +1572,7 @@ sp_api::decl_runtime_apis! { /// Perform an Ethereum call. /// /// See [`crate::Pallet::bare_eth_transact`] - fn eth_transact( - origin: H160, - dest: Option, - value: Balance, - input: Vec, - gas_limit: Option, - storage_deposit_limit: Option, - ) -> EthContractResult; + fn eth_transact(tx: GenericTransaction) -> Result, EthTransactError>; /// Upload new code without instantiating a contract from it. /// diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs index 64e66382b9ab..3b55106c67d8 100644 --- a/substrate/frame/revive/src/limits.rs +++ b/substrate/frame/revive/src/limits.rs @@ -47,7 +47,7 @@ pub const NUM_EVENT_TOPICS: u32 = 4; pub const DELEGATE_DEPENDENCIES: u32 = 32; /// Maximum size of events (including topics) and storage values. -pub const PAYLOAD_BYTES: u32 = 512; +pub const PAYLOAD_BYTES: u32 = 448; /// The maximum size of the transient storage in bytes. /// @@ -116,7 +116,10 @@ pub mod code { const BASIC_BLOCK_SIZE: u32 = 1000; /// Make sure that the various program parts are within the defined limits. - pub fn enforce(blob: Vec) -> Result { + pub fn enforce( + blob: Vec, + available_syscalls: &[&[u8]], + ) -> Result { fn round_page(n: u32) -> u64 { // performing the rounding in u64 in order to prevent overflow u64::from(n).next_multiple_of(PAGE_SIZE.into()) @@ -129,23 +132,56 @@ pub mod code { Error::::CodeRejected })?; + if !program.is_64_bit() { + log::debug!(target: LOG_TARGET, "32bit programs are not supported."); + Err(Error::::CodeRejected)?; + } + + // Need to check that no non-existent syscalls are used. This allows us to add + // new syscalls later without affecting already deployed code. + for (idx, import) in program.imports().iter().enumerate() { + // We are being defensive in case an attacker is able to somehow include + // a lot of imports. This is important because we search the array of host + // functions for every import. + if idx == available_syscalls.len() { + log::debug!(target: LOG_TARGET, "Program contains too many imports."); + Err(Error::::CodeRejected)?; + } + let Some(import) = import else { + log::debug!(target: LOG_TARGET, "Program contains malformed import."); + return Err(Error::::CodeRejected.into()); + }; + if !available_syscalls.contains(&import.as_bytes()) { + log::debug!(target: LOG_TARGET, "Program references unknown syscall: {}", import); + Err(Error::::CodeRejected)?; + } + } + // This scans the whole program but we only do it once on code deployment. // It is safe to do unchecked math in u32 because the size of the program // was already checked above. - use polkavm::program::ISA32_V1_NoSbrk as ISA; + use polkavm::program::ISA64_V1 as ISA; let mut num_instructions: u32 = 0; let mut max_basic_block_size: u32 = 0; let mut basic_block_size: u32 = 0; for inst in program.instructions(ISA) { + use polkavm::program::Instruction; num_instructions += 1; basic_block_size += 1; if inst.kind.opcode().starts_new_basic_block() { max_basic_block_size = max_basic_block_size.max(basic_block_size); basic_block_size = 0; } - if matches!(inst.kind, polkavm::program::Instruction::invalid) { - log::debug!(target: LOG_TARGET, "invalid instruction at offset {}", inst.offset); - return Err(>::InvalidInstruction.into()) + match inst.kind { + Instruction::invalid => { + log::debug!(target: LOG_TARGET, "invalid instruction at offset {}", inst.offset); + return Err(>::InvalidInstruction.into()) + }, + Instruction::sbrk(_, _) => { + log::debug!(target: LOG_TARGET, "sbrk instruction is not allowed. offset {}", inst.offset); + return Err(>::InvalidInstruction.into()) + }, + _ => (), } } diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index af0100d59cbe..a7127f812b4b 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -17,8 +17,8 @@ //! A crate that hosts a common definitions that are relevant for the pallet-revive. -use crate::H160; -use alloc::vec::Vec; +use crate::{H160, U256}; +use alloc::{string::String, vec::Vec}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::weights::Weight; use pallet_revive_uapi::ReturnFlags; @@ -28,6 +28,30 @@ use sp_runtime::{ DispatchError, RuntimeDebug, }; +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum DepositLimit { + /// Allows bypassing all balance transfer checks. + Unchecked, + + /// Specifies a maximum allowable balance for a deposit. + Balance(Balance), +} + +impl DepositLimit { + pub fn is_unchecked(&self) -> bool { + match self { + Self::Unchecked => true, + _ => false, + } + } +} + +impl From for DepositLimit { + fn from(value: T) -> Self { + Self::Balance(value) + } +} + /// Result type of a `bare_call` or `bare_instantiate` call as well as `ContractsApi::call` and /// `ContractsApi::instantiate`. /// @@ -84,15 +108,22 @@ pub struct ContractResult { /// The result of the execution of a `eth_transact` call. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct EthContractResult { - /// The fee charged for the execution. - pub fee: Balance, +pub struct EthTransactInfo { /// The amount of gas that was necessary to execute the transaction. pub gas_required: Weight, /// Storage deposit charged. pub storage_deposit: Balance, - /// The execution result. - pub result: Result, DispatchError>, + /// The weight and deposit equivalent in EVM Gas. + pub eth_gas: U256, + /// The execution return value. + pub data: Vec, +} + +/// Error type of a `eth_transact` call. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum EthTransactError { + Data(Vec), + Message(String), } /// Result type of a `bare_code_upload` call. diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index 712010bc8257..6eddf048be98 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -373,24 +373,36 @@ where } } + /// Create new storage meter without checking the limit. + pub fn new_unchecked(limit: BalanceOf) -> Self { + return Self { limit, ..Default::default() } + } + /// The total amount of deposit that should change hands as result of the execution /// that this meter was passed into. This will also perform all the charges accumulated /// in the whole contract stack. /// /// This drops the root meter in order to make sure it is only called when the whole /// execution did finish. - pub fn try_into_deposit(self, origin: &Origin) -> Result, DispatchError> { - // Only refund or charge deposit if the origin is not root. - let origin = match origin { - Origin::Root => return Ok(Deposit::Charge(Zero::zero())), - Origin::Signed(o) => o, - }; - for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Refund(_))) { - E::charge(origin, &charge.contract, &charge.amount, &charge.state)?; - } - for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Charge(_))) { - E::charge(origin, &charge.contract, &charge.amount, &charge.state)?; + pub fn try_into_deposit( + self, + origin: &Origin, + skip_transfer: bool, + ) -> Result, DispatchError> { + if !skip_transfer { + // Only refund or charge deposit if the origin is not root. + let origin = match origin { + Origin::Root => return Ok(Deposit::Charge(Zero::zero())), + Origin::Signed(o) => o, + }; + for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Refund(_))) { + E::charge(origin, &charge.contract, &charge.amount, &charge.state)?; + } + for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Charge(_))) { + E::charge(origin, &charge.contract, &charge.amount, &charge.state)?; + } } + Ok(self.total_deposit) } } @@ -425,13 +437,18 @@ impl> RawMeter { contract: &T::AccountId, contract_info: &mut ContractInfo, code_info: &CodeInfo, + skip_transfer: bool, ) -> Result<(), DispatchError> { debug_assert!(matches!(self.contract_state(), ContractState::Alive)); // We need to make sure that the contract's account exists. let ed = Pallet::::min_balance(); self.total_deposit = Deposit::Charge(ed); - T::Currency::transfer(origin, contract, ed, Preservation::Preserve)?; + if skip_transfer { + T::Currency::set_balance(contract, ed); + } else { + T::Currency::transfer(origin, contract, ed, Preservation::Preserve)?; + } // A consumer is added at account creation and removed it on termination, otherwise the // runtime could remove the account. As long as a contract exists its account must exist. @@ -479,6 +496,7 @@ impl> RawMeter { } if let Deposit::Charge(amount) = total_deposit { if amount > self.limit { + log::debug!( target: LOG_TARGET, "Storage deposit limit exhausted: {:?} > {:?}", amount, self.limit); return Err(>::StorageDepositLimitExhausted.into()) } } @@ -811,7 +829,10 @@ mod tests { nested0.enforce_limit(Some(&mut nested0_info)).unwrap(); meter.absorb(nested0, &BOB, Some(&mut nested0_info)); - assert_eq!(meter.try_into_deposit(&test_case.origin).unwrap(), test_case.deposit); + assert_eq!( + meter.try_into_deposit(&test_case.origin, false).unwrap(), + test_case.deposit + ); assert_eq!(nested0_info.extra_deposit(), 112); assert_eq!(nested1_info.extra_deposit(), 110); @@ -882,7 +903,10 @@ mod tests { nested0.absorb(nested1, &CHARLIE, None); meter.absorb(nested0, &BOB, None); - assert_eq!(meter.try_into_deposit(&test_case.origin).unwrap(), test_case.deposit); + assert_eq!( + meter.try_into_deposit(&test_case.origin, false).unwrap(), + test_case.deposit + ); assert_eq!(TestExtTestValue::get(), test_case.expected) } } diff --git a/substrate/frame/revive/src/test_utils/builder.rs b/substrate/frame/revive/src/test_utils/builder.rs index e64f58894432..8ba5e7384070 100644 --- a/substrate/frame/revive/src/test_utils/builder.rs +++ b/substrate/frame/revive/src/test_utils/builder.rs @@ -18,7 +18,8 @@ use super::{deposit_limit, GAS_LIMIT}; use crate::{ address::AddressMapper, AccountIdOf, BalanceOf, Code, CollectEvents, Config, ContractResult, - DebugInfo, EventRecordOf, ExecReturnValue, InstantiateReturnValue, OriginFor, Pallet, Weight, + DebugInfo, DepositLimit, EventRecordOf, ExecReturnValue, InstantiateReturnValue, OriginFor, + Pallet, Weight, }; use frame_support::pallet_prelude::DispatchResultWithPostInfo; use paste::paste; @@ -133,7 +134,7 @@ builder!( origin: OriginFor, value: BalanceOf, gas_limit: Weight, - storage_deposit_limit: BalanceOf, + storage_deposit_limit: DepositLimit>, code: Code, data: Vec, salt: Option<[u8; 32]>, @@ -159,7 +160,7 @@ builder!( origin, value: 0u32.into(), gas_limit: GAS_LIMIT, - storage_deposit_limit: deposit_limit::(), + storage_deposit_limit: DepositLimit::Balance(deposit_limit::()), code, data: vec![], salt: Some([0; 32]), @@ -198,7 +199,7 @@ builder!( dest: H160, value: BalanceOf, gas_limit: Weight, - storage_deposit_limit: BalanceOf, + storage_deposit_limit: DepositLimit>, data: Vec, debug: DebugInfo, collect_events: CollectEvents, @@ -216,7 +217,7 @@ builder!( dest, value: 0u32.into(), gas_limit: GAS_LIMIT, - storage_deposit_limit: deposit_limit::(), + storage_deposit_limit: DepositLimit::Balance(deposit_limit::()), data: vec![], debug: DebugInfo::UnsafeDebug, collect_events: CollectEvents::Skip, diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 2d9cae16c441..664578bf7672 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -29,6 +29,7 @@ use crate::{ ChainExtension, Environment, Ext, RegisteredChainExtension, Result as ExtensionResult, RetVal, ReturnFlags, }, + evm::{runtime::GAS_PRICE, GenericTransaction}, exec::Key, limits, primitives::CodeUploadReturnValue, @@ -38,8 +39,8 @@ use crate::{ wasm::Memory, weights::WeightInfo, AccountId32Mapper, BalanceOf, Code, CodeInfoOf, CollectEvents, Config, ContractInfo, - ContractInfoOf, DebugInfo, DeletionQueueCounter, Error, HoldReason, Origin, Pallet, - PristineCode, H160, + ContractInfoOf, DebugInfo, DeletionQueueCounter, DepositLimit, Error, EthTransactError, + HoldReason, Origin, Pallet, PristineCode, H160, }; use crate::test_utils::builder::Contract; @@ -373,7 +374,7 @@ impl RegisteredChainExtension for TempStorageExtension { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( - Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + Weight::from_parts(2 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), ); pub static ExistentialDeposit: u64 = 1; } @@ -381,6 +382,7 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; + type BlockWeights = BlockWeights; type AccountId = AccountId32; type Lookup = IdentityLookup; type AccountData = pallet_balances::AccountData; @@ -416,6 +418,7 @@ impl pallet_proxy::Config for Test { type CallHasher = BlakeTwo256; type AnnouncementDepositBase = ConstU64<1>; type AnnouncementDepositFactor = ConstU64<1>; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { @@ -436,7 +439,7 @@ parameter_types! { pub static DepositPerByte: BalanceOf = 1; pub const DepositPerItem: BalanceOf = 2; pub static CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0); - pub static ChainId: u64 = 384; + pub static ChainId: u64 = 448; } impl Convert> for Test { @@ -631,7 +634,10 @@ fn calling_plain_account_is_balance_transfer() { assert!(!>::contains_key(BOB_ADDR)); assert_eq!(test_utils::get_balance(&BOB_FALLBACK), 0); let result = builder::bare_call(BOB_ADDR).value(42).build_and_unwrap_result(); - assert_eq!(test_utils::get_balance(&BOB_FALLBACK), 42); + assert_eq!( + test_utils::get_balance(&BOB_FALLBACK), + 42 + ::Currency::minimum_balance() + ); assert_eq!(result, Default::default()); }); } @@ -1124,7 +1130,7 @@ fn deploy_and_call_other_contract() { #[test] fn delegate_call() { let (caller_wasm, _caller_code_hash) = compile_module("delegate_call").unwrap(); - let (callee_wasm, callee_code_hash) = compile_module("delegate_call_lib").unwrap(); + let (callee_wasm, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); @@ -1134,12 +1140,88 @@ fn delegate_call() { builder::bare_instantiate(Code::Upload(caller_wasm)) .value(300_000) .build_and_unwrap_contract(); - // Only upload 'callee' code - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), callee_wasm, 100_000,)); + + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_wasm)) + .value(100_000) + .build_and_unwrap_contract(); assert_ok!(builder::call(caller_addr) .value(1337) - .data(callee_code_hash.as_ref().to_vec()) + .data((callee_addr, 0u64, 0u64).encode()) + .build()); + }); +} + +#[test] +fn delegate_call_with_weight_limit() { + let (caller_wasm, _caller_code_hash) = compile_module("delegate_call").unwrap(); + let (callee_wasm, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(300_000) + .build_and_unwrap_contract(); + + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_wasm)) + .value(100_000) + .build_and_unwrap_contract(); + + // fails, not enough weight + assert_err!( + builder::bare_call(caller_addr) + .value(1337) + .data((callee_addr, 100u64, 100u64).encode()) + .build() + .result, + Error::::ContractTrapped, + ); + + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 500_000_000u64, 100_000u64).encode()) + .build()); + }); +} + +#[test] +fn delegate_call_with_deposit_limit() { + let (caller_pvm, _caller_code_hash) = compile_module("delegate_call_deposit_limit").unwrap(); + let (callee_pvm, _callee_code_hash) = compile_module("delegate_call_lib").unwrap(); + + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_pvm)) + .value(300_000) + .build_and_unwrap_contract(); + + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_pvm)) + .value(100_000) + .build_and_unwrap_contract(); + + // Delegate call will write 1 storage and deposit of 2 (1 item) + 32 (bytes) is required. + // Fails, not enough deposit + let ret = builder::bare_call(caller_addr) + .value(1337) + .data((callee_addr, 33u64).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); + + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 34u64).encode()) .build()); }); } @@ -1166,7 +1248,7 @@ fn transfer_expendable_cannot_kill_account() { test_utils::contract_info_storage_deposit(&addr) ); - // Some ot the total balance is held, so it can't be transferred. + // Some or the total balance is held, so it can't be transferred. assert_err!( <::Currency as Mutate>::transfer( &account, @@ -1508,20 +1590,8 @@ fn call_return_code() { .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); - // Sending less than the minimum balance will also make the transfer fail - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&DJANGO_ADDR) - .iter() - .chain(&u256_bytes(42)) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - - // Sending at least the minimum balance should result in success but - // no code called. + // Sending below the minimum balance should result in success. + // The ED is charged from the call origin. assert_eq!(test_utils::get_balance(&DJANGO_FALLBACK), 0); let result = builder::bare_call(bob.addr) .data( @@ -1533,7 +1603,7 @@ fn call_return_code() { ) .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::Success); - assert_eq!(test_utils::get_balance(&DJANGO_FALLBACK), 55); + assert_eq!(test_utils::get_balance(&DJANGO_FALLBACK), 55 + min_balance); let django = builder::bare_instantiate(Code::Upload(callee_code)) .origin(RuntimeOrigin::signed(CHARLIE)) @@ -1607,8 +1677,8 @@ fn instantiate_return_code() { // Contract has enough balance but the passed code hash is invalid ::Currency::set_balance(&contract.account_id, min_balance + 10_000); - let result = builder::bare_call(contract.addr).data(vec![0; 33]).build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CodeNotFound); + let result = builder::bare_call(contract.addr).data(vec![0; 33]).build(); + assert_err!(result.result, >::CodeNotFound); // Contract has enough balance but callee reverts because "1" is passed. let result = builder::bare_call(contract.addr) @@ -1805,6 +1875,27 @@ fn lazy_batch_removal_works() { }); } +#[test] +fn ref_time_left_api_works() { + let (code, _) = compile_module("ref_time_left").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor calls ref_time_left twice and asserts it to decrease + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the ref_time returned by the ref_time_left API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + + let returned_value = u64::from_le_bytes(received.data[..8].try_into().unwrap()); + assert!(returned_value > 0); + assert!(returned_value < GAS_LIMIT.ref_time()); + }); +} + #[test] fn lazy_removal_partial_remove_works() { let (code, _hash) = compile_module("self_destruct").unwrap(); @@ -2219,7 +2310,7 @@ fn gas_estimation_for_subcalls() { // Make the same call using the estimated gas. Should succeed. let result = builder::bare_call(addr_caller) .gas_limit(result_orig.gas_required) - .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero()) + .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) .data(input.clone()) .build(); assert_ok!(&result.result); @@ -2227,7 +2318,7 @@ fn gas_estimation_for_subcalls() { // Check that it fails with too little ref_time let result = builder::bare_call(addr_caller) .gas_limit(result_orig.gas_required.sub_ref_time(1)) - .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero()) + .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) .data(input.clone()) .build(); assert_err!(result.result, error); @@ -2235,7 +2326,7 @@ fn gas_estimation_for_subcalls() { // Check that it fails with too little proof_size let result = builder::bare_call(addr_caller) .gas_limit(result_orig.gas_required.sub_proof_size(1)) - .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero()) + .storage_deposit_limit(result_orig.storage_deposit.charge_or_zero().into()) .data(input.clone()) .build(); assert_err!(result.result, error); @@ -3392,13 +3483,11 @@ fn deposit_limit_in_nested_calls() { // nested call. This should fail as callee adds up 2 bytes to the storage, meaning // that the nested call should have a deposit limit of at least 2 Balance. The // sub-call should be rolled back, which is covered by the next test case. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(16) - .data((102u32, &addr_callee, U256::from(1u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); + let ret = builder::bare_call(addr_caller) + .storage_deposit_limit(DepositLimit::Balance(16)) + .data((102u32, &addr_callee, U256::from(1u64)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); // Refund in the callee contract but not enough to cover the 14 Balance required by the // caller. Note that if previous sub-call wouldn't roll back, this call would pass @@ -3414,13 +3503,11 @@ fn deposit_limit_in_nested_calls() { let _ = ::Currency::set_balance(&ALICE, 511); // Require more than the sender's balance. - // We don't set a special limit for the nested call. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((512u32, &addr_callee, U256::from(1u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); + // Limit the sub call to little balance so it should fail in there + let ret = builder::bare_call(addr_caller) + .data((448, &addr_callee, U256::from(1u64)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); // Same as above but allow for the additional deposit of 1 Balance in parent. // We set the special deposit limit of 1 Balance for the nested call, which isn't @@ -3492,14 +3579,12 @@ fn deposit_limit_in_nested_instantiate() { // Now we set enough limit in parent call, but an insufficient limit for child // instantiate. This should fail during the charging for the instantiation in // `RawMeter::charge_instantiate()` - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(callee_info_len + 2 + ED + 2) - .data((0u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 1)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); + let ret = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(DepositLimit::Balance(callee_info_len + 2 + ED + 2)) + .data((0u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 1)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); // The charges made on the instantiation should be rolled back. assert_eq!(::Currency::free_balance(&BOB), 1_000_000); @@ -3507,21 +3592,19 @@ fn deposit_limit_in_nested_instantiate() { // item of 1 byte to be covered by the limit, which implies 3 more Balance. // Now we set enough limit for the parent call, but insufficient limit for child // instantiate. This should fail right after the constructor execution. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(callee_info_len + 2 + ED + 3) // enough parent limit - .data((1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 2)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); + let ret = builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(DepositLimit::Balance(callee_info_len + 2 + ED + 3)) // enough parent limit + .data((1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 2)).encode()) + .build_and_unwrap_result(); + assert_return_code!(ret, RuntimeReturnCode::OutOfResources); // The charges made on the instantiation should be rolled back. assert_eq!(::Currency::free_balance(&BOB), 1_000_000); // Set enough deposit limit for the child instantiate. This should succeed. let result = builder::bare_call(addr_caller) .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(callee_info_len + 2 + ED + 4 + 2) + .storage_deposit_limit((callee_info_len + 2 + ED + 4 + 2).into()) .data((1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 3 + 2)).encode()) .build(); @@ -3675,6 +3758,12 @@ fn locking_delegate_dependency_works() { .map(|c| sp_core::H256(sp_io::hashing::keccak_256(c))) .collect(); + let hash2addr = |code_hash: &H256| { + let mut addr = H160::zero(); + addr.as_bytes_mut().copy_from_slice(&code_hash.as_ref()[..20]); + addr + }; + // Define inputs with various actions to test locking / unlocking delegate_dependencies. // See the contract for more details. let noop_input = (0u32, callee_hashes[0]); @@ -3684,17 +3773,19 @@ fn locking_delegate_dependency_works() { // Instantiate the caller contract with the given input. let instantiate = |input: &(u32, H256)| { + let (action, code_hash) = input; builder::bare_instantiate(Code::Upload(wasm_caller.clone())) .origin(RuntimeOrigin::signed(ALICE_FALLBACK)) - .data(input.encode()) + .data((action, hash2addr(code_hash), code_hash).encode()) .build() }; // Call contract with the given input. let call = |addr_caller: &H160, input: &(u32, H256)| { + let (action, code_hash) = input; builder::bare_call(*addr_caller) .origin(RuntimeOrigin::signed(ALICE_FALLBACK)) - .data(input.encode()) + .data((action, hash2addr(code_hash), code_hash).encode()) .build() }; const ED: u64 = 2000; @@ -3711,7 +3802,7 @@ fn locking_delegate_dependency_works() { // Upload all the delegated codes (they all have the same size) let mut deposit = Default::default(); for code in callee_codes.iter() { - let CodeUploadReturnValue { deposit: deposit_per_code, .. } = + let CodeUploadReturnValue { deposit: deposit_per_code, code_hash } = Contracts::bare_upload_code( RuntimeOrigin::signed(ALICE_FALLBACK), code.clone(), @@ -3719,6 +3810,9 @@ fn locking_delegate_dependency_works() { ) .unwrap(); deposit = deposit_per_code; + // Mock contract info by using first 20 bytes of code_hash as address. + let addr = hash2addr(&code_hash); + ContractInfoOf::::set(&addr, ContractInfo::new(&addr, 0, code_hash).ok()); } // Instantiate should now work. @@ -3755,7 +3849,11 @@ fn locking_delegate_dependency_works() { // Locking self should fail. assert_err!( - call(&addr_caller, &(1u32, self_code_hash)).result, + builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(ALICE_FALLBACK)) + .data((1u32, &addr_caller, self_code_hash).encode()) + .build() + .result, Error::::CannotAddSelfAsDelegateDependency ); @@ -3793,8 +3891,8 @@ fn locking_delegate_dependency_works() { // Locking a dependency with a storage limit too low should fail. assert_err!( builder::bare_call(addr_caller) - .storage_deposit_limit(dependency_deposit - 1) - .data(lock_delegate_dependency_input.encode()) + .storage_deposit_limit((dependency_deposit - 1).into()) + .data((1u32, hash2addr(&callee_hashes[0]), callee_hashes[0]).encode()) .build() .result, Error::::StorageDepositLimitExhausted @@ -3804,7 +3902,7 @@ fn locking_delegate_dependency_works() { assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE_FALLBACK), callee_hashes[0])); // Calling should fail since the delegated contract is not on chain anymore. - assert_err!(call(&addr_caller, &noop_input).result, Error::::ContractTrapped); + assert_err!(call(&addr_caller, &noop_input).result, Error::::CodeNotFound); // Add the dependency back. Contracts::upload_code( @@ -4266,6 +4364,80 @@ fn create1_with_value_works() { }); } +#[test] +fn gas_price_api_works() { + let (code, _) = compile_module("gas_price").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the gas price API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(u64::from_le_bytes(received.data[..].try_into().unwrap()), u64::from(GAS_PRICE)); + }); +} + +#[test] +fn base_fee_api_works() { + let (code, _) = compile_module("base_fee").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the base fee API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(received.data[..].try_into().unwrap()), U256::zero()); + }); +} + +#[test] +fn call_data_size_api_works() { + let (code, _) = compile_module("call_data_size").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the call data size API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(u64::from_le_bytes(received.data.try_into().unwrap()), 0); + + let received = builder::bare_call(addr).data(vec![1; 256]).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(u64::from_le_bytes(received.data.try_into().unwrap()), 256); + }); +} + +#[test] +fn call_data_copy_api_works() { + let (code, _) = compile_module("call_data_copy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call fixture: Expects an input of [255; 32] and executes tests. + assert_ok!(builder::call(addr).data(vec![255; 32]).build()); + }); +} + #[test] fn static_data_limit_is_enforced() { let (oom_rw_trailing, _) = compile_module("oom_rw_trailing").unwrap(); @@ -4331,6 +4503,48 @@ fn chain_id_works() { }); } +#[test] +fn call_data_load_api_works() { + let (code, _) = compile_module("call_data_load").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It reads a byte for the offset and then returns + // what call data load returned using this byte as the offset. + let input = (3u8, U256::max_value(), U256::max_value()).encode(); + let received = builder::bare_call(addr).data(input).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::max_value()); + + // Edge case + let input = (2u8, U256::from(255).to_big_endian()).encode(); + let received = builder::bare_call(addr).data(input).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::from(65280)); + + // Edge case + let received = builder::bare_call(addr).data(vec![1]).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::zero()); + + // OOB case + let input = (42u8).encode(); + let received = builder::bare_call(addr).data(input).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::zero()); + + // No calldata should return the zero value + let received = builder::bare_call(addr).build().result.unwrap(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!(U256::from_little_endian(&received.data), U256::zero()); + }); +} + #[test] fn return_data_api_works() { let (code_return_data_api, _) = compile_module("return_data_api").unwrap(); @@ -4580,3 +4794,153 @@ fn mapped_address_works() { assert_eq!(::Currency::total_balance(&EVE), 1_100); }); } + +#[test] +fn skip_transfer_works() { + let (code_caller, _) = compile_module("call").unwrap(); + let (code, _) = compile_module("set_empty_storage").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + ::Currency::set_balance(&BOB, 0); + + // fails to instantiate when gas is specified. + assert_err!( + Pallet::::bare_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + input: Some(code.clone().into()), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_| 0u32 + ), + EthTransactError::Message(format!( + "insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)" + )) + ); + + // works when no gas is specified. + assert_ok!(Pallet::::bare_eth_transact( + GenericTransaction { + from: Some(ALICE_ADDR), + input: Some(code.clone().into()), + ..Default::default() + }, + Weight::MAX, + |_| 0u32 + )); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(code_caller)).build_and_unwrap_contract(); + + // fails to call when gas is specified. + assert_err!( + Pallet::::bare_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(addr), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_| 0u32 + ), + EthTransactError::Message(format!( + "insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)" + )) + ); + + // fails when calling from a contract when gas is specified. + assert_err!( + Pallet::::bare_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(caller_addr), + input: Some((0u32, &addr).encode().into()), + gas: Some(1u32.into()), + ..Default::default() + }, + Weight::MAX, + |_| 0u32 + ), + EthTransactError::Message(format!("insufficient funds for gas * price + value: address {BOB_ADDR:?} have 0 (supplied gas 1)")) + ); + + // works when no gas is specified. + assert_ok!(Pallet::::bare_eth_transact( + GenericTransaction { from: Some(BOB_ADDR), to: Some(addr), ..Default::default() }, + Weight::MAX, + |_| 0u32 + )); + + // works when calling from a contract when no gas is specified. + assert_ok!(Pallet::::bare_eth_transact( + GenericTransaction { + from: Some(BOB_ADDR), + to: Some(caller_addr), + input: Some((0u32, &addr).encode().into()), + ..Default::default() + }, + Weight::MAX, + |_| 0u32 + )); + }); +} + +#[test] +fn gas_limit_api_works() { + let (code, _) = compile_module("gas_limit").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: It echoes back the value returned by the gas limit API. + let received = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(received.flags, ReturnFlags::empty()); + assert_eq!( + u64::from_le_bytes(received.data[..].try_into().unwrap()), + ::BlockWeights::get().max_block.ref_time() + ); + }); +} + +#[test] +fn unknown_syscall_rejected() { + let (code, _) = compile_module("unknown_syscall").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + assert_err!( + builder::bare_instantiate(Code::Upload(code)).build().result, + >::CodeRejected, + ) + }); +} + +#[test] +fn unstable_interface_rejected() { + let (code, _) = compile_module("unstable_interface").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + Test::set_unstable_interface(false); + assert_err!( + builder::bare_instantiate(Code::Upload(code.clone())).build().result, + >::CodeRejected, + ); + + Test::set_unstable_interface(true); + assert_ok!(builder::bare_instantiate(Code::Upload(code)).build().result); + }); +} diff --git a/substrate/frame/revive/src/tests/test_debug.rs b/substrate/frame/revive/src/tests/test_debug.rs index 7c4fbba71f65..c9e19e52ace1 100644 --- a/substrate/frame/revive/src/tests/test_debug.rs +++ b/substrate/frame/revive/src/tests/test_debug.rs @@ -21,6 +21,7 @@ use crate::{ debug::{CallInterceptor, CallSpan, ExecResult, ExportedFunction, Tracing}, primitives::ExecReturnValue, test_utils::*, + DepositLimit, }; use frame_support::traits::Currency; use pretty_assertions::assert_eq; @@ -114,7 +115,7 @@ fn debugging_works() { RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, - deposit_limit::(), + DepositLimit::Balance(deposit_limit::()), Code::Upload(wasm), vec![], Some([0u8; 32]), @@ -198,7 +199,7 @@ fn call_interception_works() { RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, - deposit_limit::(), + deposit_limit::().into(), Code::Upload(wasm), vec![], // some salt to ensure that the address of this contract is unique among all tests diff --git a/substrate/frame/revive/src/wasm/mod.rs b/substrate/frame/revive/src/wasm/mod.rs index f10c4f5fddf8..b24de61314f9 100644 --- a/substrate/frame/revive/src/wasm/mod.rs +++ b/substrate/frame/revive/src/wasm/mod.rs @@ -23,13 +23,10 @@ mod runtime; #[cfg(doc)] pub use crate::wasm::runtime::SyscallDoc; -#[cfg(test)] -pub use runtime::HIGHEST_API_VERSION; - #[cfg(feature = "runtime-benchmarks")] pub use crate::wasm::runtime::{ReturnData, TrapReason}; -pub use crate::wasm::runtime::{ApiVersion, Memory, Runtime, RuntimeCosts}; +pub use crate::wasm::runtime::{Memory, Runtime, RuntimeCosts}; use crate::{ address::AddressMapper, @@ -39,7 +36,7 @@ use crate::{ storage::meter::Diff, weights::WeightInfo, AccountIdOf, BadOrigin, BalanceOf, CodeInfoOf, CodeVec, Config, Error, Event, ExecError, - HoldReason, Pallet, PristineCode, Weight, API_VERSION, LOG_TARGET, + HoldReason, Pallet, PristineCode, Weight, LOG_TARGET, }; use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; @@ -87,11 +84,6 @@ pub struct CodeInfo { refcount: u64, /// Length of the code in bytes. code_len: u32, - /// The API version that this contract operates under. - /// - /// This determines which host functions are available to the contract. This - /// prevents that new host functions become available to already deployed contracts. - api_version: u16, /// The behaviour version that this contract operates under. /// /// Whenever any observeable change (with the exception of weights) are made we need @@ -99,7 +91,7 @@ pub struct CodeInfo { /// exposing the old behaviour depending on the set behaviour version of the contract. /// /// As of right now this is a reserved field that is always set to 0. - behaviour_version: u16, + behaviour_version: u32, } impl ExportedFunction { @@ -130,9 +122,10 @@ where { /// We only check for size and nothing else when the code is uploaded. pub fn from_code(code: Vec, owner: AccountIdOf) -> Result { - // We do size checks when new code is deployed. This allows us to increase + // We do validation only when new code is deployed. This allows us to increase // the limits later without affecting already deployed code. - let code = limits::code::enforce::(code)?; + let available_syscalls = runtime::list_syscalls(T::UnsafeUnstableInterface::get()); + let code = limits::code::enforce::(code, available_syscalls)?; let code_len = code.len() as u32; let bytes_added = code_len.saturating_add(>::max_encoded_len() as u32); @@ -144,7 +137,6 @@ where deposit, refcount: 0, code_len, - api_version: API_VERSION, behaviour_version: Default::default(), }; let code_hash = H256(sp_io::hashing::keccak_256(&code)); @@ -183,7 +175,7 @@ where } /// Puts the module blob into storage, and returns the deposit collected for the storage. - pub fn store_code(&mut self) -> Result, Error> { + pub fn store_code(&mut self, skip_transfer: bool) -> Result, Error> { let code_hash = *self.code_hash(); >::mutate(code_hash, |stored_code_info| { match stored_code_info { @@ -195,15 +187,16 @@ where // the `owner` is always the origin of the current transaction. None => { let deposit = self.code_info.deposit; - T::Currency::hold( + + if !skip_transfer { + T::Currency::hold( &HoldReason::CodeUploadDepositReserve.into(), &self.code_info.owner, deposit, - ) - .map_err(|err| { - log::debug!(target: LOG_TARGET, "failed to store code for owner: {:?}: {err:?}", self.code_info.owner); + ) .map_err(|err| { log::debug!(target: LOG_TARGET, "failed to store code for owner: {:?}: {err:?}", self.code_info.owner); >::StorageDepositNotEnoughFunds })?; + } self.code_info.refcount = 0; >::insert(code_hash, &self.code); @@ -229,7 +222,6 @@ impl CodeInfo { deposit: Default::default(), refcount: 0, code_len: 0, - api_version: API_VERSION, behaviour_version: Default::default(), } } @@ -250,7 +242,7 @@ impl CodeInfo { } /// Returns the code length. - pub fn code_len(&self) -> U256 { + pub fn code_len(&self) -> u64 { self.code_len.into() } } @@ -259,7 +251,6 @@ pub struct PreparedCall<'a, E: Ext> { module: polkavm::Module, instance: polkavm::RawInstance, runtime: Runtime<'a, E, polkavm::RawInstance>, - api_version: ApiVersion, } impl<'a, E: Ext> PreparedCall<'a, E> @@ -270,12 +261,9 @@ where pub fn call(mut self) -> ExecResult { let exec_result = loop { let interrupt = self.instance.run(); - if let Some(exec_result) = self.runtime.handle_interrupt( - interrupt, - &self.module, - &mut self.instance, - self.api_version, - ) { + if let Some(exec_result) = + self.runtime.handle_interrupt(interrupt, &self.module, &mut self.instance) + { break exec_result } }; @@ -289,12 +277,18 @@ impl WasmBlob { self, mut runtime: Runtime, entry_point: ExportedFunction, - api_version: ApiVersion, ) -> Result, ExecError> { let mut config = polkavm::Config::default(); config.set_backend(Some(polkavm::BackendKind::Interpreter)); - let engine = - polkavm::Engine::new(&config).expect("interpreter is available on all plattforms; qed"); + config.set_cache_enabled(false); + #[cfg(feature = "std")] + if std::env::var_os("REVIVE_USE_COMPILER").is_some() { + config.set_backend(Some(polkavm::BackendKind::Compiler)); + } + let engine = polkavm::Engine::new(&config).expect( + "on-chain (no_std) use of interpreter is hard coded. + interpreter is available on all plattforms; qed", + ); let mut module_config = polkavm::ModuleConfig::new(); module_config.set_page_size(limits::PAGE_SIZE); @@ -306,6 +300,15 @@ impl WasmBlob { Error::::CodeRejected })?; + // This is checked at deploy time but we also want to reject pre-existing + // 32bit programs. + // TODO: Remove when we reset the test net. + // https://github.com/paritytech/contract-issues/issues/11 + if !module.is_64_bit() { + log::debug!(target: LOG_TARGET, "32bit programs are not supported."); + Err(Error::::CodeRejected)?; + } + let entry_program_counter = module .exports() .find(|export| export.symbol().as_bytes() == entry_point.identifier().as_bytes()) @@ -327,7 +330,7 @@ impl WasmBlob { instance.set_gas(gas_limit_polkavm); instance.prepare_call_untyped(entry_program_counter, &[]); - Ok(PreparedCall { module, instance, runtime, api_version }) + Ok(PreparedCall { module, instance, runtime }) } } @@ -348,13 +351,7 @@ where function: ExportedFunction, input_data: Vec, ) -> ExecResult { - let api_version = if ::UnsafeUnstableInterface::get() { - ApiVersion::UnsafeNewest - } else { - ApiVersion::Versioned(self.code_info.api_version) - }; - let prepared_call = - self.prepare_call(Runtime::new(ext, input_data), function, api_version)?; + let prepared_call = self.prepare_call(Runtime::new(ext, input_data), function)?; prepared_call.call() } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 95257bee1c6b..52f79f2eb55a 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -19,6 +19,7 @@ use crate::{ address::AddressMapper, + evm::runtime::GAS_PRICE, exec::{ExecError, ExecResult, Ext, Key}, gas::{ChargedAmount, Token}, limits, @@ -27,7 +28,7 @@ use crate::{ Config, Error, LOG_TARGET, SENTINEL, }; use alloc::{boxed::Box, vec, vec::Vec}; -use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; +use codec::{Decode, DecodeLimit, Encode}; use core::{fmt, marker::PhantomData, mem}; use frame_support::{ dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types, @@ -44,14 +45,6 @@ type CallOf = ::RuntimeCall; /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; -#[derive(Clone, Copy)] -pub enum ApiVersion { - /// Expose all APIs even unversioned ones. Only used for testing and benchmarking. - UnsafeNewest, - /// Only expose API's up to and including the specified version. - Versioned(u16), -} - /// Abstraction over the memory access within syscalls. /// /// The reason for this abstraction is that we run syscalls on the host machine when @@ -73,6 +66,13 @@ pub trait Memory { /// - designated area is not within the bounds of the sandbox memory. fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError>; + /// Zero the designated location in the sandbox memory. + /// + /// Returns `Err` if one of the following conditions occurs: + /// + /// - designated area is not within the bounds of the sandbox memory. + fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError>; + /// Read designated chunk from the sandbox memory. /// /// Returns `Err` if one of the following conditions occurs: @@ -126,34 +126,13 @@ pub trait Memory { /// /// # Note /// - /// There must be an extra benchmark for determining the influence of `len` with - /// regard to the overall weight. + /// Make sure to charge a proportional amount of weight if `len` is not fixed. fn read_as_unbounded(&self, ptr: u32, len: u32) -> Result { let buf = self.read(ptr, len)?; let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut buf.as_ref()) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; Ok(decoded) } - - /// Reads and decodes a type with a size fixed at compile time from contract memory. - /// - /// # Only use on fixed size types - /// - /// Don't use this for types where the encoded size is not fixed but merely bounded. Otherwise - /// this implementation will out of bound access the buffer declared by the guest. Some examples - /// of those bounded but not fixed types: Enums with data, `BoundedVec` or any compact encoded - /// integer. - /// - /// # Note - /// - /// The weight of reading a fixed value is included in the overall weight of any - /// contract callable function. - fn read_as(&self, ptr: u32) -> Result { - let buf = self.read(ptr, D::max_encoded_len() as u32)?; - let decoded = D::decode_with_depth_limit(MAX_DECODE_NESTING, &mut buf.as_ref()) - .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; - Ok(decoded) - } } /// Allows syscalls access to the PolkaVM instance they are executing in. @@ -164,8 +143,8 @@ pub trait Memory { pub trait PolkaVmInstance: Memory { fn gas(&self) -> polkavm::Gas; fn set_gas(&mut self, gas: polkavm::Gas); - fn read_input_regs(&self) -> (u32, u32, u32, u32, u32, u32); - fn write_output(&mut self, output: u32); + fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64); + fn write_output(&mut self, output: u64); } // Memory implementation used in benchmarking where guest memory is mapped into the host. @@ -191,6 +170,10 @@ impl Memory for [u8] { bound_checked.copy_from_slice(buf); Ok(()) } + + fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { + <[u8] as Memory>::write(self, ptr, &vec![0; len as usize]) + } } impl Memory for polkavm::RawInstance { @@ -203,6 +186,10 @@ impl Memory for polkavm::RawInstance { fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { self.write_memory(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) } + + fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { + self.zero_memory(ptr, len).map_err(|_| Error::::OutOfBounds.into()) + } } impl PolkaVmInstance for polkavm::RawInstance { @@ -214,7 +201,7 @@ impl PolkaVmInstance for polkavm::RawInstance { self.set_gas(gas) } - fn read_input_regs(&self) -> (u32, u32, u32, u32, u32, u32) { + fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64) { ( self.reg(polkavm::Reg::A0), self.reg(polkavm::Reg::A1), @@ -225,7 +212,7 @@ impl PolkaVmInstance for polkavm::RawInstance { ) } - fn write_output(&mut self, output: u32) { + fn write_output(&mut self, output: u64) { self.set_reg(polkavm::Reg::A0, output); } } @@ -296,8 +283,16 @@ pub enum RuntimeCosts { CopyFromContract(u32), /// Weight charged for copying data to the sandbox. CopyToContract(u32), + /// Weight of calling `seal_call_data_load``. + CallDataLoad, + /// Weight of calling `seal_call_data_copy`. + CallDataCopy(u32), /// Weight of calling `seal_caller`. Caller, + /// Weight of calling `seal_call_data_size`. + CallDataSize, + /// Weight of calling `seal_return_data_size`. + ReturnDataSize, /// Weight of calling `seal_origin`. Origin, /// Weight of calling `seal_is_contract`. @@ -314,6 +309,8 @@ pub enum RuntimeCosts { CallerIsRoot, /// Weight of calling `seal_address`. Address, + /// Weight of calling `seal_ref_time_left`. + RefTimeLeft, /// Weight of calling `seal_weight_left`. WeightLeft, /// Weight of calling `seal_balance`. @@ -328,8 +325,14 @@ pub enum RuntimeCosts { BlockNumber, /// Weight of calling `seal_block_hash`. BlockHash, + /// Weight of calling `seal_gas_price`. + GasPrice, + /// Weight of calling `seal_base_fee`. + BaseFee, /// Weight of calling `seal_now`. Now, + /// Weight of calling `seal_gas_limit`. + GasLimit, /// Weight of calling `seal_weight_to_fee`. WeightToFee, /// Weight of calling `seal_terminate`, passing the number of locked dependencies. @@ -358,8 +361,6 @@ pub enum RuntimeCosts { GetTransientStorage(u32), /// Weight of calling `seal_take_transient_storage` for the given size. TakeTransientStorage(u32), - /// Weight of calling `seal_transfer`. - Transfer, /// Base weight of calling `seal_call`. CallBase, /// Weight of calling `seal_delegate_call` for the given input size. @@ -458,8 +459,12 @@ impl Token for RuntimeCosts { use self::RuntimeCosts::*; match *self { HostFn => cost_args!(noop_host_fn, 1), - CopyToContract(len) => T::WeightInfo::seal_input(len), + CopyToContract(len) => T::WeightInfo::seal_copy_to_contract(len), CopyFromContract(len) => T::WeightInfo::seal_return(len), + CallDataSize => T::WeightInfo::seal_call_data_size(), + ReturnDataSize => T::WeightInfo::seal_return_data_size(), + CallDataLoad => T::WeightInfo::seal_call_data_load(), + CallDataCopy(len) => T::WeightInfo::seal_call_data_copy(len), Caller => T::WeightInfo::seal_caller(), Origin => T::WeightInfo::seal_origin(), IsContract => T::WeightInfo::seal_is_contract(), @@ -469,6 +474,7 @@ impl Token for RuntimeCosts { CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), CallerIsRoot => T::WeightInfo::seal_caller_is_root(), Address => T::WeightInfo::seal_address(), + RefTimeLeft => T::WeightInfo::seal_ref_time_left(), WeightLeft => T::WeightInfo::seal_weight_left(), Balance => T::WeightInfo::seal_balance(), BalanceOf => T::WeightInfo::seal_balance_of(), @@ -476,7 +482,10 @@ impl Token for RuntimeCosts { MinimumBalance => T::WeightInfo::seal_minimum_balance(), BlockNumber => T::WeightInfo::seal_block_number(), BlockHash => T::WeightInfo::seal_block_hash(), + GasPrice => T::WeightInfo::seal_gas_price(), + BaseFee => T::WeightInfo::seal_base_fee(), Now => T::WeightInfo::seal_now(), + GasLimit => T::WeightInfo::seal_gas_limit(), WeightToFee => T::WeightInfo::seal_weight_to_fee(), Terminate(locked_dependencies) => T::WeightInfo::seal_terminate(locked_dependencies), DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len), @@ -503,7 +512,6 @@ impl Token for RuntimeCosts { TakeTransientStorage(len) => { cost_storage!(write_transient, seal_take_transient_storage, len) }, - Transfer => T::WeightInfo::seal_transfer(), CallBase => T::WeightInfo::seal_call(0, 0), DelegateCallBase => T::WeightInfo::seal_delegate_call(), CallTransferSurcharge => cost_args!(seal_call, 1, 0), @@ -539,16 +547,17 @@ macro_rules! charge_gas { /// The kind of call that should be performed. enum CallType { /// Execute another instantiated contract - Call { callee_ptr: u32, value_ptr: u32, deposit_ptr: u32, weight: Weight }, - /// Execute deployed code in the context (storage, account ID, value) of the caller contract - DelegateCall { code_hash_ptr: u32 }, + Call { value_ptr: u32 }, + /// Execute another contract code in the context (storage, account ID, value) of the caller + /// contract + DelegateCall, } impl CallType { fn cost(&self) -> RuntimeCosts { match self { CallType::Call { .. } => RuntimeCosts::CallBase, - CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase, + CallType::DelegateCall => RuntimeCosts::DelegateCallBase, } } } @@ -574,7 +583,6 @@ impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { interrupt: Result, module: &polkavm::Module, instance: &mut M, - api_version: ApiVersion, ) -> Option { use polkavm::InterruptKind::*; @@ -594,7 +602,7 @@ impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { let Some(syscall_symbol) = module.imports().get(idx) else { return Some(Err(>::InvalidSyscall.into())); }; - match self.handle_ecall(instance, syscall_symbol.as_bytes(), api_version) { + match self.handle_ecall(instance, syscall_symbol.as_bytes()) { Ok(None) => None, Ok(Some(return_value)) => { instance.write_output(return_value); @@ -768,29 +776,24 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { Ok(()) } - /// Fallible conversion of `DispatchError` to `ReturnErrorCode`. - fn err_into_return_code(from: DispatchError) -> Result { - use ReturnErrorCode::*; - - let transfer_failed = Error::::TransferFailed.into(); - let no_code = Error::::CodeNotFound.into(); - let not_found = Error::::ContractNotFound.into(); - - match from { - x if x == transfer_failed => Ok(TransferFailed), - x if x == no_code => Ok(CodeNotFound), - x if x == not_found => Ok(NotCallable), - err => Err(err), - } - } - /// Fallible conversion of a `ExecError` to `ReturnErrorCode`. + /// + /// This is used when converting the error returned from a subcall in order to decide + /// whether to trap the caller or allow handling of the error. fn exec_error_into_return_code(from: ExecError) -> Result { use crate::exec::ErrorOrigin::Callee; + use ReturnErrorCode::*; + let transfer_failed = Error::::TransferFailed.into(); + let out_of_gas = Error::::OutOfGas.into(); + let out_of_deposit = Error::::StorageDepositLimitExhausted.into(); + + // errors in the callee do not trap the caller match (from.error, from.origin) { - (_, Callee) => Ok(ReturnErrorCode::CalleeTrapped), - (err, _) => Self::err_into_return_code(err), + (err, _) if err == transfer_failed => Ok(TransferFailed), + (err, Callee) if err == out_of_gas || err == out_of_deposit => Ok(OutOfResources), + (_, Callee) => Ok(CalleeTrapped), + (err, _) => Err(err), } } @@ -990,6 +993,9 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { memory: &mut M, flags: CallFlags, call_type: CallType, + callee_ptr: u32, + deposit_ptr: u32, + weight: Weight, input_data_ptr: u32, input_data_len: u32, output_ptr: u32, @@ -997,6 +1003,10 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { ) -> Result { self.charge_gas(call_type.cost())?; + let callee = memory.read_h160(callee_ptr)?; + let deposit_limit = + if deposit_ptr == SENTINEL { U256::zero() } else { memory.read_u256(deposit_ptr)? }; + let input_data = if flags.contains(CallFlags::CLONE_INPUT) { let input = self.input_data.as_ref().ok_or(Error::::InputForwarded)?; charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?; @@ -1009,13 +1019,7 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { }; let call_outcome = match call_type { - CallType::Call { callee_ptr, value_ptr, deposit_ptr, weight } => { - let callee = memory.read_h160(callee_ptr)?; - let deposit_limit = if deposit_ptr == SENTINEL { - U256::zero() - } else { - memory.read_u256(deposit_ptr)? - }; + CallType::Call { value_ptr } => { let read_only = flags.contains(CallFlags::READ_ONLY); let value = memory.read_u256(value_ptr)?; if value > 0u32.into() { @@ -1036,13 +1040,11 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { read_only, ) }, - CallType::DelegateCall { code_hash_ptr } => { + CallType::DelegateCall => { if flags.intersects(CallFlags::ALLOW_REENTRY | CallFlags::READ_ONLY) { return Err(Error::::InvalidCallFlags.into()); } - - let code_hash = memory.read_h256(code_hash_ptr)?; - self.ext.delegate_call(code_hash, input_data) + self.ext.delegate_call(weight, deposit_limit, callee, input_data) }, }; @@ -1156,14 +1158,18 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { #[define_env] pub mod env { /// Noop function used to benchmark the time it takes to execute an empty function. + /// + /// Marked as stable because it needs to be called from benchmarks even when the benchmarked + /// parachain has unstable functions disabled. #[cfg(feature = "runtime-benchmarks")] + #[stable] fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> { Ok(()) } /// Set the value at the given key in the contract storage. /// See [`pallet_revive_uapi::HostFn::set_storage_v2`] - #[api_version(0)] + #[stable] #[mutating] fn set_storage( &mut self, @@ -1177,23 +1183,9 @@ pub mod env { self.set_storage(memory, flags, key_ptr, key_len, value_ptr, value_len) } - /// Clear the value at the given key in the contract storage. - /// See [`pallet_revive_uapi::HostFn::clear_storage`] - #[api_version(0)] - #[mutating] - fn clear_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - self.clear_storage(memory, flags, key_ptr, key_len) - } - /// Retrieve the value under the given key from storage. /// See [`pallet_revive_uapi::HostFn::get_storage`] - #[api_version(0)] + #[stable] fn get_storage( &mut self, memory: &mut M, @@ -1206,61 +1198,9 @@ pub mod env { self.get_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr) } - /// Checks whether there is a value stored under the given key. - /// See [`pallet_revive_uapi::HostFn::contains_storage`] - #[api_version(0)] - fn contains_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - self.contains_storage(memory, flags, key_ptr, key_len) - } - - /// Retrieve and remove the value under the given key from storage. - /// See [`pallet_revive_uapi::HostFn::take_storage`] - #[api_version(0)] - #[mutating] - fn take_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - self.take_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr) - } - - /// Transfer some value to another account. - /// See [`pallet_revive_uapi::HostFn::transfer`]. - #[api_version(0)] - #[mutating] - fn transfer( - &mut self, - memory: &mut M, - address_ptr: u32, - value_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::Transfer)?; - let callee = memory.read_h160(address_ptr)?; - let value: U256 = memory.read_u256(value_ptr)?; - let result = self.ext.transfer(&callee, value); - match result { - Ok(()) => Ok(ReturnErrorCode::Success), - Err(err) => { - let code = Self::err_into_return_code(err)?; - Ok(code) - }, - } - } - /// Make a call to another contract. /// See [`pallet_revive_uapi::HostFn::call`]. - #[api_version(0)] + #[stable] fn call( &mut self, memory: &mut M, @@ -1278,12 +1218,10 @@ pub mod env { self.call( memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::Call { - callee_ptr, - value_ptr, - deposit_ptr, - weight: Weight::from_parts(ref_time_limit, proof_size_limit), - }, + CallType::Call { value_ptr }, + callee_ptr, + deposit_ptr, + Weight::from_parts(ref_time_limit, proof_size_limit), input_data_ptr, input_data_len, output_ptr, @@ -1293,12 +1231,15 @@ pub mod env { /// Execute code in the context (storage, caller, value) of the current contract. /// See [`pallet_revive_uapi::HostFn::delegate_call`]. - #[api_version(0)] + #[stable] fn delegate_call( &mut self, memory: &mut M, flags: u32, - code_hash_ptr: u32, + address_ptr: u32, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_ptr: u32, input_data_ptr: u32, input_data_len: u32, output_ptr: u32, @@ -1307,7 +1248,10 @@ pub mod env { self.call( memory, CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::DelegateCall { code_hash_ptr }, + CallType::DelegateCall, + address_ptr, + deposit_ptr, + Weight::from_parts(ref_time_limit, proof_size_limit), input_data_ptr, input_data_len, output_ptr, @@ -1317,7 +1261,7 @@ pub mod env { /// Instantiate a contract with the specified code hash. /// See [`pallet_revive_uapi::HostFn::instantiate`]. - #[api_version(0)] + #[stable] #[mutating] fn instantiate( &mut self, @@ -1349,32 +1293,83 @@ pub mod env { ) } - /// Remove the calling account and transfer remaining **free** balance. - /// See [`pallet_revive_uapi::HostFn::terminate`]. - #[api_version(0)] - #[mutating] - fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> { - self.terminate(memory, beneficiary_ptr) + /// Returns the total size of the contract call input data. + /// See [`pallet_revive_uapi::HostFn::call_data_size `]. + #[stable] + fn call_data_size(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::CallDataSize)?; + Ok(self + .input_data + .as_ref() + .map(|input| input.len().try_into().expect("usize fits into u64; qed")) + .unwrap_or_default()) } /// Stores the input passed by the caller into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::input`]. - #[api_version(0)] - fn input(&mut self, memory: &mut M, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { - if let Some(input) = self.input_data.take() { - self.write_sandbox_output(memory, out_ptr, out_len_ptr, &input, false, |len| { - Some(RuntimeCosts::CopyToContract(len)) - })?; - self.input_data = Some(input); - Ok(()) - } else { - Err(Error::::InputForwarded.into()) + /// See [`pallet_revive_uapi::HostFn::call_data_copy`]. + #[stable] + fn call_data_copy( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len: u32, + offset: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?; + + let Some(input) = self.input_data.as_ref() else { + return Err(Error::::InputForwarded.into()); + }; + + let start = offset as usize; + if start >= input.len() { + memory.zero(out_ptr, out_len)?; + return Ok(()); } + + let end = start.saturating_add(out_len as usize).min(input.len()); + memory.write(out_ptr, &input[start..end])?; + + let bytes_written = (end - start) as u32; + memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?; + + Ok(()) + } + + /// Stores the U256 value at given call input `offset` into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::call_data_load`]. + #[stable] + fn call_data_load( + &mut self, + memory: &mut M, + out_ptr: u32, + offset: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::CallDataLoad)?; + + let Some(input) = self.input_data.as_ref() else { + return Err(Error::::InputForwarded.into()); + }; + + let mut data = [0; 32]; + let start = offset as usize; + let data = if start >= input.len() { + data // Any index is valid to request; OOB offsets return zero. + } else { + let end = start.saturating_add(32).min(input.len()); + data[..end - start].copy_from_slice(&input[start..end]); + data.reverse(); + data // Solidity expects right-padded data + }; + + self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?; + + Ok(()) } /// Cease contract execution and save a data buffer as a result of the execution. /// See [`pallet_revive_uapi::HostFn::return_value`]. - #[api_version(0)] + #[stable] fn seal_return( &mut self, memory: &mut M, @@ -1388,7 +1383,7 @@ pub mod env { /// Stores the address of the caller into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::caller`]. - #[api_version(0)] + #[stable] fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::Caller)?; let caller = ::AddressMapper::to_address(self.ext.caller().account_id()?); @@ -1403,7 +1398,7 @@ pub mod env { /// Stores the address of the call stack origin into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::origin`]. - #[api_version(0)] + #[stable] fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::Origin)?; let origin = ::AddressMapper::to_address(self.ext.origin().account_id()?); @@ -1416,18 +1411,9 @@ pub mod env { )?) } - /// Checks whether a specified address belongs to a contract. - /// See [`pallet_revive_uapi::HostFn::is_contract`]. - #[api_version(0)] - fn is_contract(&mut self, memory: &mut M, account_ptr: u32) -> Result { - self.charge_gas(RuntimeCosts::IsContract)?; - let address = memory.read_h160(account_ptr)?; - Ok(self.ext.is_contract(&address) as u32) - } - /// Retrieve the code hash for a specified contract address. /// See [`pallet_revive_uapi::HostFn::code_hash`]. - #[api_version(0)] + #[stable] fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::CodeHash)?; let address = memory.read_h160(addr_ptr)?; @@ -1442,53 +1428,16 @@ pub mod env { /// Retrieve the code size for a given contract address. /// See [`pallet_revive_uapi::HostFn::code_size`]. - #[api_version(0)] - fn code_size(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> { + #[stable] + fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result { self.charge_gas(RuntimeCosts::CodeSize)?; let address = memory.read_h160(addr_ptr)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.code_size(&address).to_little_endian(), - false, - already_charged, - )?) - } - - /// Retrieve the code hash of the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::own_code_hash`]. - #[api_version(0)] - fn own_code_hash(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::OwnCodeHash)?; - let code_hash = *self.ext.own_code_hash(); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - code_hash.as_bytes(), - false, - already_charged, - )?) - } - - /// Checks whether the caller of the current contract is the origin of the whole call stack. - /// See [`pallet_revive_uapi::HostFn::caller_is_origin`]. - #[api_version(0)] - fn caller_is_origin(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsOrigin)?; - Ok(self.ext.caller_is_origin() as u32) - } - - /// Checks whether the caller of the current contract is root. - /// See [`pallet_revive_uapi::HostFn::caller_is_root`]. - #[api_version(0)] - fn caller_is_root(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsRoot)?; - Ok(self.ext.caller_is_root() as u32) + Ok(self.ext.code_size(&address)) } /// Stores the address of the current contract into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::address`]. - #[api_version(0)] + #[stable] fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::Address)?; let address = self.ext.address(); @@ -1503,7 +1452,7 @@ pub mod env { /// Stores the price for the specified amount of weight into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::weight_to_fee`]. - #[api_version(0)] + #[stable] fn weight_to_fee( &mut self, memory: &mut M, @@ -1522,30 +1471,9 @@ pub mod env { )?) } - /// Stores the amount of weight left into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::weight_left`]. - #[api_version(0)] - fn weight_left( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::WeightLeft)?; - let gas_left = &self.ext.gas_meter().gas_left().encode(); - Ok(self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - gas_left, - false, - already_charged, - )?) - } - /// Stores the immutable data into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. - #[api_version(0)] + #[stable] fn get_immutable_data( &mut self, memory: &mut M, @@ -1561,7 +1489,7 @@ pub mod env { /// Attaches the supplied immutable data to the currently executing contract. /// See [`pallet_revive_uapi::HostFn::set_immutable_data`]. - #[api_version(0)] + #[stable] fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> { if len > limits::IMMUTABLE_BYTES { return Err(Error::::OutOfBounds.into()); @@ -1575,7 +1503,7 @@ pub mod env { /// Stores the *free* balance of the current account into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::balance`]. - #[api_version(0)] + #[stable] fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::Balance)?; Ok(self.write_fixed_sandbox_output( @@ -1589,7 +1517,7 @@ pub mod env { /// Stores the *free* balance of the supplied address into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::balance`]. - #[api_version(0)] + #[stable] fn balance_of( &mut self, memory: &mut M, @@ -1609,7 +1537,7 @@ pub mod env { /// Returns the chain ID. /// See [`pallet_revive_uapi::HostFn::chain_id`]. - #[api_version(0)] + #[stable] fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { Ok(self.write_fixed_sandbox_output( memory, @@ -1620,9 +1548,17 @@ pub mod env { )?) } + /// Returns the block ref_time limit. + /// See [`pallet_revive_uapi::HostFn::gas_limit`]. + #[stable] + fn gas_limit(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::GasLimit)?; + Ok(::BlockWeights::get().max_block.ref_time()) + } + /// Stores the value transferred along with this call/instantiate into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::value_transferred`]. - #[api_version(0)] + #[stable] fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::ValueTransferred)?; Ok(self.write_fixed_sandbox_output( @@ -1634,29 +1570,37 @@ pub mod env { )?) } - /// Load the latest block timestamp into the supplied buffer - /// See [`pallet_revive_uapi::HostFn::now`]. - #[api_version(0)] - fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Now)?; + /// Returns the simulated ethereum `GASPRICE` value. + /// See [`pallet_revive_uapi::HostFn::gas_price`]. + #[stable] + fn gas_price(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::GasPrice)?; + Ok(GAS_PRICE.into()) + } + + /// Returns the simulated ethereum `BASEFEE` value. + /// See [`pallet_revive_uapi::HostFn::base_fee`]. + #[stable] + fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BaseFee)?; Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &self.ext.now().to_little_endian(), + &U256::zero().to_little_endian(), false, already_charged, )?) } - /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::minimum_balance`]. - #[api_version(0)] - fn minimum_balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::MinimumBalance)?; + /// Load the latest block timestamp into the supplied buffer + /// See [`pallet_revive_uapi::HostFn::now`]. + #[stable] + fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Now)?; Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &self.ext.minimum_balance().to_little_endian(), + &self.ext.now().to_little_endian(), false, already_charged, )?) @@ -1664,7 +1608,7 @@ pub mod env { /// Deposit a contract event with the data buffer and optional list of topics. /// See [pallet_revive_uapi::HostFn::deposit_event] - #[api_version(0)] + #[stable] #[mutating] fn deposit_event( &mut self, @@ -1704,7 +1648,7 @@ pub mod env { /// Stores the current block number of the current contract into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::block_number`]. - #[api_version(0)] + #[stable] fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::BlockNumber)?; Ok(self.write_fixed_sandbox_output( @@ -1718,7 +1662,7 @@ pub mod env { /// Stores the block hash at given block height into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::block_hash`]. - #[api_version(0)] + #[stable] fn block_hash( &mut self, memory: &mut M, @@ -1737,25 +1681,9 @@ pub mod env { )?) } - /// Computes the SHA2 256-bit hash on the given input buffer. - /// See [`pallet_revive_uapi::HostFn::hash_sha2_256`]. - #[api_version(0)] - fn hash_sha2_256( - &mut self, - memory: &mut M, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::HashSha256(input_len))?; - Ok(self.compute_hash_on_intermediate_buffer( - memory, sha2_256, input_ptr, input_len, output_ptr, - )?) - } - /// Computes the KECCAK 256-bit hash on the given input buffer. /// See [`pallet_revive_uapi::HostFn::hash_keccak_256`]. - #[api_version(0)] + #[stable] fn hash_keccak_256( &mut self, memory: &mut M, @@ -1769,36 +1697,53 @@ pub mod env { )?) } - /// Computes the BLAKE2 256-bit hash on the given input buffer. - /// See [`pallet_revive_uapi::HostFn::hash_blake2_256`]. - #[api_version(0)] - fn hash_blake2_256( - &mut self, - memory: &mut M, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::HashBlake256(input_len))?; - Ok(self.compute_hash_on_intermediate_buffer( - memory, blake2_256, input_ptr, input_len, output_ptr, - )?) + /// Stores the length of the data returned by the last call into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::return_data_size`]. + #[stable] + fn return_data_size(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::ReturnDataSize)?; + Ok(self + .ext + .last_frame_output() + .data + .len() + .try_into() + .expect("usize fits into u64; qed")) } - /// Computes the BLAKE2 128-bit hash on the given input buffer. - /// See [`pallet_revive_uapi::HostFn::hash_blake2_128`]. - #[api_version(0)] - fn hash_blake2_128( + /// Stores data returned by the last call, starting from `offset`, into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::return_data`]. + #[stable] + fn return_data_copy( &mut self, memory: &mut M, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::HashBlake128(input_len))?; - Ok(self.compute_hash_on_intermediate_buffer( - memory, blake2_128, input_ptr, input_len, output_ptr, - )?) + 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?) + } + + /// Returns the amount of ref_time left. + /// See [`pallet_revive_uapi::HostFn::ref_time_left`]. + #[stable] + fn ref_time_left(&mut self, memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::RefTimeLeft)?; + Ok(self.ext.gas_meter().gas_left().ref_time()) } /// Call into the chain extension provided by the chain if any. @@ -1831,28 +1776,6 @@ pub mod env { ret } - /// Emit a custom debug message. - /// See [`pallet_revive_uapi::HostFn::debug_message`]. - #[api_version(0)] - fn debug_message( - &mut self, - memory: &mut M, - str_ptr: u32, - str_len: u32, - ) -> Result { - let str_len = str_len.min(limits::DEBUG_BUFFER_BYTES); - self.charge_gas(RuntimeCosts::DebugMessage(str_len))?; - if self.ext.append_debug_buffer("") { - let data = memory.read(str_ptr, str_len)?; - if let Some(msg) = core::str::from_utf8(&data).ok() { - self.ext.append_debug_buffer(msg); - } - Ok(ReturnErrorCode::Success) - } else { - Ok(ReturnErrorCode::LoggingDisabled) - } - } - /// Call some dispatchable of the runtime. /// See [`frame_support::traits::call_runtime`]. #[mutating] @@ -1872,86 +1795,68 @@ pub mod env { ) } - /// Execute an XCM program locally, using the contract's address as the origin. - /// See [`pallet_revive_uapi::HostFn::execute_xcm`]. + /// Checks whether the caller of the current contract is the origin of the whole call stack. + /// See [`pallet_revive_uapi::HostFn::caller_is_origin`]. + fn caller_is_origin(&mut self, _memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::CallerIsOrigin)?; + Ok(self.ext.caller_is_origin() as u32) + } + + /// Checks whether the caller of the current contract is root. + /// See [`pallet_revive_uapi::HostFn::caller_is_root`]. + fn caller_is_root(&mut self, _memory: &mut M) -> Result { + self.charge_gas(RuntimeCosts::CallerIsRoot)?; + Ok(self.ext.caller_is_root() as u32) + } + + /// Clear the value at the given key in the contract storage. + /// See [`pallet_revive_uapi::HostFn::clear_storage`] #[mutating] - fn xcm_execute( + fn clear_storage( &mut self, memory: &mut M, - msg_ptr: u32, - msg_len: u32, - ) -> Result { - use frame_support::dispatch::DispatchInfo; - use xcm::VersionedXcm; - use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo}; - - self.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; - let message: VersionedXcm> = memory.read_as_unbounded(msg_ptr, msg_len)?; - - let execute_weight = - <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); - let weight = self.ext.gas_meter().gas_left().max(execute_weight); - let dispatch_info = DispatchInfo { call_weight: weight, ..Default::default() }; - - self.call_dispatchable::( - dispatch_info, - RuntimeCosts::CallXcmExecute, - |runtime| { - let origin = crate::RawOrigin::Signed(runtime.ext.account_id().clone()).into(); - let weight_used = <::Xcm>::execute( - origin, - Box::new(message), - weight.saturating_sub(execute_weight), - )?; + flags: u32, + key_ptr: u32, + key_len: u32, + ) -> Result { + self.clear_storage(memory, flags, key_ptr, key_len) + } - Ok(Some(weight_used.saturating_add(execute_weight)).into()) - }, - ) + /// Checks whether there is a value stored under the given key. + /// See [`pallet_revive_uapi::HostFn::contains_storage`] + fn contains_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + ) -> Result { + self.contains_storage(memory, flags, key_ptr, key_len) } - /// Send an XCM program from the contract to the specified destination. - /// See [`pallet_revive_uapi::HostFn::send_xcm`]. - #[mutating] - fn xcm_send( + /// Emit a custom debug message. + /// See [`pallet_revive_uapi::HostFn::debug_message`]. + fn debug_message( &mut self, memory: &mut M, - dest_ptr: u32, - dest_len: u32, - msg_ptr: u32, - msg_len: u32, - output_ptr: u32, + str_ptr: u32, + str_len: u32, ) -> Result { - use xcm::{VersionedLocation, VersionedXcm}; - use xcm_builder::{SendController, SendControllerWeightInfo}; - - self.charge_gas(RuntimeCosts::CopyFromContract(dest_len))?; - let dest: VersionedLocation = memory.read_as_unbounded(dest_ptr, dest_len)?; - - self.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; - let message: VersionedXcm<()> = memory.read_as_unbounded(msg_ptr, msg_len)?; - - let weight = <::Xcm as SendController<_>>::WeightInfo::send(); - self.charge_gas(RuntimeCosts::CallRuntime(weight))?; - let origin = crate::RawOrigin::Signed(self.ext.account_id().clone()).into(); - - match <::Xcm>::send(origin, dest.into(), message.into()) { - Ok(message_id) => { - memory.write(output_ptr, &message_id.encode())?; - Ok(ReturnErrorCode::Success) - }, - Err(e) => { - if self.ext.append_debug_buffer("") { - self.ext.append_debug_buffer("seal0::xcm_send failed with: "); - self.ext.append_debug_buffer(e.into()); - }; - Ok(ReturnErrorCode::XcmSendFailed) - }, + let str_len = str_len.min(limits::DEBUG_BUFFER_BYTES); + self.charge_gas(RuntimeCosts::DebugMessage(str_len))?; + if self.ext.append_debug_buffer("") { + let data = memory.read(str_ptr, str_len)?; + if let Some(msg) = core::str::from_utf8(&data).ok() { + self.ext.append_debug_buffer(msg); + } + Ok(ReturnErrorCode::Success) + } else { + Ok(ReturnErrorCode::LoggingDisabled) } } /// Recovers the ECDSA public key from the given message hash and signature. /// See [`pallet_revive_uapi::HostFn::ecdsa_recover`]. - #[api_version(0)] fn ecdsa_recover( &mut self, memory: &mut M, @@ -1980,59 +1885,8 @@ pub mod env { } } - /// Verify a sr25519 signature - /// See [`pallet_revive_uapi::HostFn::sr25519_verify`]. - #[api_version(0)] - fn sr25519_verify( - &mut self, - memory: &mut M, - signature_ptr: u32, - pub_key_ptr: u32, - message_len: u32, - message_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; - - let mut signature: [u8; 64] = [0; 64]; - memory.read_into_buf(signature_ptr, &mut signature)?; - - let mut pub_key: [u8; 32] = [0; 32]; - memory.read_into_buf(pub_key_ptr, &mut pub_key)?; - - let message: Vec = memory.read(message_ptr, message_len)?; - - if self.ext.sr25519_verify(&signature, &message, &pub_key) { - Ok(ReturnErrorCode::Success) - } else { - Ok(ReturnErrorCode::Sr25519VerifyFailed) - } - } - - /// Replace the contract code at the specified address with new code. - /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. - /// - /// Disabled until the internal implementation takes care of collecting - /// the immutable data of the new code hash. - #[mutating] - fn set_code_hash( - &mut self, - memory: &mut M, - code_hash_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::SetCodeHash)?; - let code_hash: H256 = memory.read_h256(code_hash_ptr)?; - match self.ext.set_code_hash(code_hash) { - Err(err) => { - let code = Self::err_into_return_code(err)?; - Ok(code) - }, - Ok(()) => Ok(ReturnErrorCode::Success), - } - } - /// Calculates Ethereum address from the ECDSA compressed public key and stores /// See [`pallet_revive_uapi::HostFn::ecdsa_to_eth_address`]. - #[api_version(0)] fn ecdsa_to_eth_address( &mut self, memory: &mut M, @@ -2052,9 +1906,61 @@ pub mod env { } } + /// Computes the BLAKE2 128-bit hash on the given input buffer. + /// See [`pallet_revive_uapi::HostFn::hash_blake2_128`]. + fn hash_blake2_128( + &mut self, + memory: &mut M, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::HashBlake128(input_len))?; + Ok(self.compute_hash_on_intermediate_buffer( + memory, blake2_128, input_ptr, input_len, output_ptr, + )?) + } + + /// Computes the BLAKE2 256-bit hash on the given input buffer. + /// See [`pallet_revive_uapi::HostFn::hash_blake2_256`]. + fn hash_blake2_256( + &mut self, + memory: &mut M, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::HashBlake256(input_len))?; + Ok(self.compute_hash_on_intermediate_buffer( + memory, blake2_256, input_ptr, input_len, output_ptr, + )?) + } + + /// Computes the SHA2 256-bit hash on the given input buffer. + /// See [`pallet_revive_uapi::HostFn::hash_sha2_256`]. + fn hash_sha2_256( + &mut self, + memory: &mut M, + input_ptr: u32, + input_len: u32, + output_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::HashSha256(input_len))?; + Ok(self.compute_hash_on_intermediate_buffer( + memory, sha2_256, input_ptr, input_len, output_ptr, + )?) + } + + /// Checks whether a specified address belongs to a contract. + /// See [`pallet_revive_uapi::HostFn::is_contract`]. + fn is_contract(&mut self, memory: &mut M, account_ptr: u32) -> Result { + self.charge_gas(RuntimeCosts::IsContract)?; + let address = memory.read_h160(account_ptr)?; + Ok(self.ext.is_contract(&address) as u32) + } + /// Adds a new delegate dependency to the contract. /// See [`pallet_revive_uapi::HostFn::lock_delegate_dependency`]. - #[api_version(0)] #[mutating] fn lock_delegate_dependency( &mut self, @@ -2067,9 +1973,75 @@ pub mod env { Ok(()) } + /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::minimum_balance`]. + fn minimum_balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::MinimumBalance)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.minimum_balance().to_little_endian(), + false, + already_charged, + )?) + } + + /// Retrieve the code hash of the currently executing contract. + /// See [`pallet_revive_uapi::HostFn::own_code_hash`]. + fn own_code_hash(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::OwnCodeHash)?; + let code_hash = *self.ext.own_code_hash(); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + code_hash.as_bytes(), + false, + already_charged, + )?) + } + + /// Replace the contract code at the specified address with new code. + /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. + /// + /// Disabled until the internal implementation takes care of collecting + /// the immutable data of the new code hash. + #[mutating] + fn set_code_hash(&mut self, memory: &mut M, code_hash_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::SetCodeHash)?; + let code_hash: H256 = memory.read_h256(code_hash_ptr)?; + self.ext.set_code_hash(code_hash)?; + Ok(()) + } + + /// Verify a sr25519 signature + /// See [`pallet_revive_uapi::HostFn::sr25519_verify`]. + fn sr25519_verify( + &mut self, + memory: &mut M, + signature_ptr: u32, + pub_key_ptr: u32, + message_len: u32, + message_ptr: u32, + ) -> Result { + self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; + + let mut signature: [u8; 64] = [0; 64]; + memory.read_into_buf(signature_ptr, &mut signature)?; + + let mut pub_key: [u8; 32] = [0; 32]; + memory.read_into_buf(pub_key_ptr, &mut pub_key)?; + + let message: Vec = memory.read(message_ptr, message_len)?; + + if self.ext.sr25519_verify(&signature, &message, &pub_key) { + Ok(ReturnErrorCode::Success) + } else { + Ok(ReturnErrorCode::Sr25519VerifyFailed) + } + } + /// Removes the delegate dependency from the contract. /// see [`pallet_revive_uapi::HostFn::unlock_delegate_dependency`]. - #[api_version(0)] #[mutating] fn unlock_delegate_dependency( &mut self, @@ -2082,43 +2054,122 @@ pub mod env { 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( + /// Retrieve and remove the value under the given key from storage. + /// See [`pallet_revive_uapi::HostFn::take_storage`] + #[mutating] + fn take_storage( + &mut self, + memory: &mut M, + flags: u32, + key_ptr: u32, + key_len: u32, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result { + self.take_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr) + } + + /// Remove the calling account and transfer remaining **free** balance. + /// See [`pallet_revive_uapi::HostFn::terminate`]. + #[mutating] + fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> { + self.terminate(memory, beneficiary_ptr) + } + + /// Stores the amount of weight left into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::weight_left`]. + fn weight_left( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::WeightLeft)?; + let gas_left = &self.ext.gas_meter().gas_left().encode(); + Ok(self.write_sandbox_output( memory, out_ptr, - &U256::from(self.ext.last_frame_output().data.len()).to_little_endian(), + out_len_ptr, + gas_left, false, - |len| Some(RuntimeCosts::CopyToContract(len)), + already_charged, )?) } - /// 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( + /// Execute an XCM program locally, using the contract's address as the origin. + /// See [`pallet_revive_uapi::HostFn::execute_xcm`]. + #[mutating] + fn xcm_execute( &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?) + msg_ptr: u32, + msg_len: u32, + ) -> Result { + use frame_support::dispatch::DispatchInfo; + use xcm::VersionedXcm; + use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo}; + + self.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; + let message: VersionedXcm> = memory.read_as_unbounded(msg_ptr, msg_len)?; + + let execute_weight = + <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); + let weight = self.ext.gas_meter().gas_left().max(execute_weight); + let dispatch_info = DispatchInfo { call_weight: weight, ..Default::default() }; + + self.call_dispatchable::( + dispatch_info, + RuntimeCosts::CallXcmExecute, + |runtime| { + let origin = crate::RawOrigin::Signed(runtime.ext.account_id().clone()).into(); + let weight_used = <::Xcm>::execute( + origin, + Box::new(message), + weight.saturating_sub(execute_weight), + )?; + + Ok(Some(weight_used.saturating_add(execute_weight)).into()) + }, + ) + } + + /// Send an XCM program from the contract to the specified destination. + /// See [`pallet_revive_uapi::HostFn::send_xcm`]. + #[mutating] + fn xcm_send( + &mut self, + memory: &mut M, + dest_ptr: u32, + dest_len: u32, + msg_ptr: u32, + msg_len: u32, + output_ptr: u32, + ) -> Result { + use xcm::{VersionedLocation, VersionedXcm}; + use xcm_builder::{SendController, SendControllerWeightInfo}; + + self.charge_gas(RuntimeCosts::CopyFromContract(dest_len))?; + let dest: VersionedLocation = memory.read_as_unbounded(dest_ptr, dest_len)?; + + self.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; + let message: VersionedXcm<()> = memory.read_as_unbounded(msg_ptr, msg_len)?; + + let weight = <::Xcm as SendController<_>>::WeightInfo::send(); + self.charge_gas(RuntimeCosts::CallRuntime(weight))?; + let origin = crate::RawOrigin::Signed(self.ext.account_id().clone()).into(); + + match <::Xcm>::send(origin, dest.into(), message.into()) { + Ok(message_id) => { + memory.write(output_ptr, &message_id.encode())?; + Ok(ReturnErrorCode::Success) + }, + Err(e) => { + if self.ext.append_debug_buffer("") { + self.ext.append_debug_buffer("seal0::xcm_send failed with: "); + self.ext.append_debug_buffer(e.into()); + }; + Ok(ReturnErrorCode::XcmSendFailed) + }, + } } } diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index d1b1a63b4db6..e35ba5ca0766 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -18,26 +18,28 @@ //! Autogenerated weights for `pallet_revive` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-10-30, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-12-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `19e0eeaa3bc2`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: // target/production/substrate-node // benchmark // pallet -// --steps=50 -// --repeat=20 // --extrinsic=* +// --chain=dev +// --pallet=pallet_revive +// --header=/__w/polkadot-sdk/polkadot-sdk/substrate/HEADER-APACHE2 +// --output=/__w/polkadot-sdk/polkadot-sdk/substrate/frame/revive/src/weights.rs // --wasm-execution=compiled +// --steps=50 +// --repeat=20 // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_revive -// --chain=dev -// --header=./substrate/HEADER-APACHE2 -// --output=./substrate/frame/revive/src/weights.rs -// --template=./substrate/.maintain/frame-weight-template.hbs +// --template=substrate/.maintain/frame-weight-template.hbs +// --no-storage-info +// --no-min-squares +// --no-median-slopes #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -72,17 +74,25 @@ pub trait WeightInfo { fn seal_caller_is_root() -> Weight; fn seal_address() -> Weight; fn seal_weight_left() -> Weight; + fn seal_ref_time_left() -> Weight; fn seal_balance() -> Weight; fn seal_balance_of() -> Weight; fn seal_get_immutable_data(n: u32, ) -> Weight; fn seal_set_immutable_data(n: u32, ) -> Weight; fn seal_value_transferred() -> Weight; fn seal_minimum_balance() -> Weight; + fn seal_return_data_size() -> Weight; + fn seal_call_data_size() -> Weight; + fn seal_gas_limit() -> Weight; + fn seal_gas_price() -> Weight; + fn seal_base_fee() -> Weight; fn seal_block_number() -> Weight; fn seal_block_hash() -> Weight; fn seal_now() -> Weight; fn seal_weight_to_fee() -> Weight; - fn seal_input(n: u32, ) -> Weight; + fn seal_copy_to_contract(n: u32, ) -> Weight; + fn seal_call_data_load() -> Weight; + fn seal_call_data_copy(n: u32, ) -> Weight; fn seal_return(n: u32, ) -> Weight; fn seal_terminate(n: u32, ) -> Weight; fn seal_deposit_event(t: u32, n: u32, ) -> Weight; @@ -106,7 +116,6 @@ pub trait WeightInfo { fn seal_get_transient_storage(n: u32, ) -> Weight; fn seal_contains_transient_storage(n: u32, ) -> Weight; fn seal_take_transient_storage(n: u32, ) -> Weight; - fn seal_transfer() -> Weight; fn seal_call(t: u32, i: u32, ) -> Weight; fn seal_delegate_call() -> Weight; fn seal_instantiate(i: u32, ) -> Weight; @@ -132,8 +141,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_649_000 picoseconds. - Weight::from_parts(2_726_000, 1594) + // Minimum execution time: 2_859_000 picoseconds. + Weight::from_parts(3_007_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -143,10 +152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `425 + k * (69 ±0)` // Estimated: `415 + k * (70 ±0)` - // Minimum execution time: 12_756_000 picoseconds. - Weight::from_parts(13_112_000, 415) - // Standard Error: 988 - .saturating_add(Weight::from_parts(1_131_927, 0).saturating_mul(k.into())) + // Minimum execution time: 15_640_000 picoseconds. + Weight::from_parts(1_609_026, 415) + // Standard Error: 1_359 + .saturating_add(Weight::from_parts(1_204_420, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -168,10 +177,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 262144]`. fn call_with_code_per_byte(_c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1465` - // Estimated: `7405` - // Minimum execution time: 86_553_000 picoseconds. - Weight::from_parts(89_689_079, 7405) + // Measured: `1463` + // Estimated: `7403` + // Minimum execution time: 89_437_000 picoseconds. + Weight::from_parts(94_285_182, 7403) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -191,14 +200,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. /// The range of component `i` is `[0, 262144]`. - fn instantiate_with_code(_c: u32, i: u32, ) -> Weight { + fn instantiate_with_code(c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `416` - // Estimated: `6333` - // Minimum execution time: 180_721_000 picoseconds. - Weight::from_parts(155_866_981, 6333) + // Measured: `364` + // Estimated: `6327` + // Minimum execution time: 187_904_000 picoseconds. + Weight::from_parts(153_252_081, 6327) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_514, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(49, 0).saturating_mul(c.into())) + // Standard Error: 11 + .saturating_add(Weight::from_parts(4_528, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -220,11 +231,11 @@ impl WeightInfo for SubstrateWeight { fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1296` - // Estimated: `4741` - // Minimum execution time: 151_590_000 picoseconds. - Weight::from_parts(128_110_988, 4741) + // Estimated: `4758` + // Minimum execution time: 154_656_000 picoseconds. + Weight::from_parts(139_308_398, 4758) // Standard Error: 16 - .saturating_add(Weight::from_parts(4_453, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_421, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -242,10 +253,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `1465` - // Estimated: `7405` - // Minimum execution time: 136_371_000 picoseconds. - Weight::from_parts(140_508_000, 7405) + // Measured: `1463` + // Estimated: `7403` + // Minimum execution time: 138_815_000 picoseconds. + Weight::from_parts(149_067_000, 7403) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -260,8 +271,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 51_255_000 picoseconds. - Weight::from_parts(52_668_809, 3574) + // Minimum execution time: 49_978_000 picoseconds. + Weight::from_parts(51_789_325, 3574) // Standard Error: 0 .saturating_add(Weight::from_parts(1, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) @@ -277,8 +288,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 41_664_000 picoseconds. - Weight::from_parts(42_981_000, 3750) + // Minimum execution time: 43_833_000 picoseconds. + Weight::from_parts(44_660_000, 3750) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -290,8 +301,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `529` // Estimated: `6469` - // Minimum execution time: 27_020_000 picoseconds. - Weight::from_parts(27_973_000, 6469) + // Minimum execution time: 26_717_000 picoseconds. + Weight::from_parts(28_566_000, 6469) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -303,8 +314,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 42_342_000 picoseconds. - Weight::from_parts(43_210_000, 3574) + // Minimum execution time: 39_401_000 picoseconds. + Weight::from_parts(40_542_000, 3574) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -316,8 +327,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `56` // Estimated: `3521` - // Minimum execution time: 31_881_000 picoseconds. - Weight::from_parts(32_340_000, 3521) + // Minimum execution time: 31_570_000 picoseconds. + Weight::from_parts(32_302_000, 3521) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -329,8 +340,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 11_087_000 picoseconds. - Weight::from_parts(11_416_000, 3610) + // Minimum execution time: 13_607_000 picoseconds. + Weight::from_parts(13_903_000, 3610) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -338,24 +349,24 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_403_000 picoseconds. - Weight::from_parts(7_751_101, 0) - // Standard Error: 99 - .saturating_add(Weight::from_parts(179_467, 0).saturating_mul(r.into())) + // Minimum execution time: 7_400_000 picoseconds. + Weight::from_parts(8_388_251, 0) + // Standard Error: 283 + .saturating_add(Weight::from_parts(165_630, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 272_000 picoseconds. - Weight::from_parts(306_000, 0) + // Minimum execution time: 275_000 picoseconds. + Weight::from_parts(305_000, 0) } fn seal_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 226_000 picoseconds. - Weight::from_parts(261_000, 0) + // Minimum execution time: 224_000 picoseconds. + Weight::from_parts(265_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) @@ -363,8 +374,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `306` // Estimated: `3771` - // Minimum execution time: 6_727_000 picoseconds. - Weight::from_parts(7_122_000, 3771) + // Minimum execution time: 10_004_000 picoseconds. + Weight::from_parts(10_336_000, 3771) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) @@ -373,16 +384,16 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 7_542_000 picoseconds. - Weight::from_parts(7_846_000, 3868) + // Minimum execution time: 11_054_000 picoseconds. + Weight::from_parts(11_651_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 243_000 picoseconds. - Weight::from_parts(275_000, 0) + // Minimum execution time: 252_000 picoseconds. + Weight::from_parts(305_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) @@ -392,44 +403,51 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `473` // Estimated: `3938` - // Minimum execution time: 11_948_000 picoseconds. - Weight::from_parts(12_406_000, 3938) + // Minimum execution time: 14_461_000 picoseconds. + Weight::from_parts(15_049_000, 3938) .saturating_add(T::DbWeight::get().reads(2_u64)) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 329_000 picoseconds. - Weight::from_parts(362_000, 0) + // Minimum execution time: 312_000 picoseconds. + Weight::from_parts(338_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 276_000 picoseconds. - Weight::from_parts(303_000, 0) + // Minimum execution time: 243_000 picoseconds. + Weight::from_parts(299_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 251_000 picoseconds. - Weight::from_parts(286_000, 0) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(271_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 611_000 picoseconds. - Weight::from_parts(669_000, 0) + // Minimum execution time: 683_000 picoseconds. + Weight::from_parts(732_000, 0) + } + fn seal_ref_time_left() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 226_000 picoseconds. + Weight::from_parts(273_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `103` + // Measured: `102` // Estimated: `0` - // Minimum execution time: 4_439_000 picoseconds. - Weight::from_parts(4_572_000, 0) + // Minimum execution time: 4_626_000 picoseconds. + Weight::from_parts(4_842_000, 0) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -439,8 +457,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `264` // Estimated: `3729` - // Minimum execution time: 9_336_000 picoseconds. - Weight::from_parts(9_622_000, 3729) + // Minimum execution time: 12_309_000 picoseconds. + Weight::from_parts(12_653_000, 3729) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -450,10 +468,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238 + n * (1 ±0)` // Estimated: `3703 + n * (1 ±0)` - // Minimum execution time: 5_660_000 picoseconds. - Weight::from_parts(6_291_437, 3703) - // Standard Error: 4 - .saturating_add(Weight::from_parts(741, 0).saturating_mul(n.into())) + // Minimum execution time: 5_838_000 picoseconds. + Weight::from_parts(9_570_778, 3703) + // Standard Error: 19 + .saturating_add(Weight::from_parts(721, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -464,32 +482,67 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_909_000 picoseconds. - Weight::from_parts(2_154_705, 0) + // Minimum execution time: 1_910_000 picoseconds. + Weight::from_parts(2_205_396, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(643, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(538, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 241_000 picoseconds. - Weight::from_parts(283_000, 0) + // Minimum execution time: 224_000 picoseconds. + Weight::from_parts(274_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 263_000 picoseconds. - Weight::from_parts(294_000, 0) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(279_000, 0) } - fn seal_block_number() -> Weight { + fn seal_return_data_size() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 229_000 picoseconds. + Weight::from_parts(267_000, 0) + } + fn seal_call_data_size() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 218_000 picoseconds. - Weight::from_parts(281_000, 0) + Weight::from_parts(267_000, 0) + } + fn seal_gas_limit() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 225_000 picoseconds. + Weight::from_parts(280_000, 0) + } + fn seal_gas_price() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 274_000 picoseconds. + Weight::from_parts(323_000, 0) + } + fn seal_base_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 239_000 picoseconds. + Weight::from_parts(290_000, 0) + } + fn seal_block_number() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 224_000 picoseconds. + Weight::from_parts(274_000, 0) } /// Storage: `System::BlockHash` (r:1 w:0) /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `Measured`) @@ -497,36 +550,50 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `30` // Estimated: `3495` - // Minimum execution time: 3_373_000 picoseconds. - Weight::from_parts(3_610_000, 3495) + // Minimum execution time: 3_430_000 picoseconds. + Weight::from_parts(3_692_000, 3495) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 247_000 picoseconds. - Weight::from_parts(299_000, 0) + // Minimum execution time: 241_000 picoseconds. + Weight::from_parts(290_000, 0) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) fn seal_weight_to_fee() -> Weight { // Proof Size summary in bytes: - // Measured: `67` - // Estimated: `1552` - // Minimum execution time: 5_523_000 picoseconds. - Weight::from_parts(5_757_000, 1552) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_355_000 picoseconds. + Weight::from_parts(1_493_000, 0) } /// The range of component `n` is `[0, 262140]`. - fn seal_input(n: u32, ) -> Weight { + fn seal_copy_to_contract(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 348_000 picoseconds. + Weight::from_parts(1_004_890, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(202, 0).saturating_mul(n.into())) + } + fn seal_call_data_load() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 222_000 picoseconds. + Weight::from_parts(256_000, 0) + } + /// The range of component `n` is `[0, 262144]`. + fn seal_call_data_copy(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 450_000 picoseconds. - Weight::from_parts(584_658, 0) + // Minimum execution time: 240_000 picoseconds. + Weight::from_parts(330_609, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(147, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(114, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262140]`. fn seal_return(n: u32, ) -> Weight { @@ -534,9 +601,9 @@ impl WeightInfo for SubstrateWeight { // Measured: `0` // Estimated: `0` // Minimum execution time: 232_000 picoseconds. - Weight::from_parts(611_960, 0) + Weight::from_parts(264_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(294, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(208, 0).saturating_mul(n.into())) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -551,12 +618,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 32]`. fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `321 + n * (88 ±0)` + // Measured: `322 + n * (88 ±0)` // Estimated: `3787 + n * (2563 ±0)` - // Minimum execution time: 19_158_000 picoseconds. - Weight::from_parts(20_900_189, 3787) - // Standard Error: 9_648 - .saturating_add(Weight::from_parts(4_239_910, 0).saturating_mul(n.into())) + // Minimum execution time: 21_920_000 picoseconds. + Weight::from_parts(21_725_868, 3787) + // Standard Error: 11_165 + .saturating_add(Weight::from_parts(4_317_986, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -564,56 +631,56 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 2563).saturating_mul(n.into())) } /// The range of component `t` is `[0, 4]`. - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_deposit_event(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_097_000 picoseconds. - Weight::from_parts(3_956_608, 0) - // Standard Error: 2_678 - .saturating_add(Weight::from_parts(178_555, 0).saturating_mul(t.into())) - // Standard Error: 23 - .saturating_add(Weight::from_parts(1_127, 0).saturating_mul(n.into())) + // Minimum execution time: 4_140_000 picoseconds. + Weight::from_parts(4_259_301, 0) + // Standard Error: 3_362 + .saturating_add(Weight::from_parts(194_546, 0).saturating_mul(t.into())) + // Standard Error: 34 + .saturating_add(Weight::from_parts(774, 0).saturating_mul(n.into())) } /// The range of component `i` is `[0, 262144]`. fn seal_debug_message(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 277_000 picoseconds. - Weight::from_parts(1_044_051, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(794, 0).saturating_mul(i.into())) + // Minimum execution time: 340_000 picoseconds. + Weight::from_parts(306_527, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(728, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn get_storage_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `744` - // Estimated: `744` - // Minimum execution time: 7_745_000 picoseconds. - Weight::from_parts(8_370_000, 744) + // Measured: `680` + // Estimated: `680` + // Minimum execution time: 10_747_000 picoseconds. + Weight::from_parts(11_276_000, 680) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn get_storage_full() -> Weight { // Proof Size summary in bytes: - // Measured: `10754` - // Estimated: `10754` - // Minimum execution time: 43_559_000 picoseconds. - Weight::from_parts(44_310_000, 10754) + // Measured: `10690` + // Estimated: `10690` + // Minimum execution time: 42_076_000 picoseconds. + Weight::from_parts(43_381_000, 10690) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_storage_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `744` - // Estimated: `744` - // Minimum execution time: 8_866_000 picoseconds. - Weight::from_parts(9_072_000, 744) + // Measured: `680` + // Estimated: `680` + // Minimum execution time: 11_703_000 picoseconds. + Weight::from_parts(12_308_000, 680) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -621,85 +688,85 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_storage_full() -> Weight { // Proof Size summary in bytes: - // Measured: `10754` - // Estimated: `10754` - // Minimum execution time: 44_481_000 picoseconds. - Weight::from_parts(45_157_000, 10754) + // Measured: `10690` + // Estimated: `10690` + // Minimum execution time: 43_460_000 picoseconds. + Weight::from_parts(45_165_000, 10690) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. - /// The range of component `o` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. + /// The range of component `o` is `[0, 448]`. fn seal_set_storage(n: u32, o: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 9_130_000 picoseconds. - Weight::from_parts(9_709_648, 247) - // Standard Error: 40 - .saturating_add(Weight::from_parts(435, 0).saturating_mul(n.into())) - // Standard Error: 40 - .saturating_add(Weight::from_parts(384, 0).saturating_mul(o.into())) + // Minimum execution time: 9_087_000 picoseconds. + Weight::from_parts(11_787_486, 247) + // Standard Error: 179 + .saturating_add(Weight::from_parts(976, 0).saturating_mul(n.into())) + // Standard Error: 179 + .saturating_add(Weight::from_parts(3_151, 0).saturating_mul(o.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_clear_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_753_000 picoseconds. - Weight::from_parts(9_558_399, 247) - // Standard Error: 56 - .saturating_add(Weight::from_parts(483, 0).saturating_mul(n.into())) + // Minimum execution time: 8_611_000 picoseconds. + Weight::from_parts(11_791_390, 247) + // Standard Error: 308 + .saturating_add(Weight::from_parts(3_943, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_get_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_328_000 picoseconds. - Weight::from_parts(9_120_157, 247) - // Standard Error: 58 - .saturating_add(Weight::from_parts(1_637, 0).saturating_mul(n.into())) + // Minimum execution time: 8_389_000 picoseconds. + Weight::from_parts(11_625_480, 247) + // Standard Error: 315 + .saturating_add(Weight::from_parts(4_487, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_contains_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 7_977_000 picoseconds. - Weight::from_parts(8_582_869, 247) - // Standard Error: 52 - .saturating_add(Weight::from_parts(854, 0).saturating_mul(n.into())) + // Minimum execution time: 7_947_000 picoseconds. + Weight::from_parts(10_970_587, 247) + // Standard Error: 310 + .saturating_add(Weight::from_parts(3_675, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_take_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_193_000 picoseconds. - Weight::from_parts(10_112_966, 247) - // Standard Error: 63 - .saturating_add(Weight::from_parts(1_320, 0).saturating_mul(n.into())) + // Minimum execution time: 9_071_000 picoseconds. + Weight::from_parts(12_525_027, 247) + // Standard Error: 328 + .saturating_add(Weight::from_parts(4_427, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -708,97 +775,89 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_398_000 picoseconds. - Weight::from_parts(1_490_000, 0) + // Minimum execution time: 1_487_000 picoseconds. + Weight::from_parts(1_611_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_762_000 picoseconds. - Weight::from_parts(1_926_000, 0) + // Minimum execution time: 1_852_000 picoseconds. + Weight::from_parts(1_982_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_413_000 picoseconds. - Weight::from_parts(1_494_000, 0) + // Minimum execution time: 1_467_000 picoseconds. + Weight::from_parts(1_529_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_606_000 picoseconds. - Weight::from_parts(1_659_000, 0) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(1_712_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_010_000 picoseconds. - Weight::from_parts(1_117_000, 0) + // Minimum execution time: 1_188_000 picoseconds. + Weight::from_parts(1_268_000, 0) } - /// The range of component `n` is `[0, 512]`. - /// The range of component `o` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. + /// The range of component `o` is `[0, 448]`. fn seal_set_transient_storage(n: u32, o: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_194_000 picoseconds. - Weight::from_parts(2_290_633, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(341, 0).saturating_mul(n.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(377, 0).saturating_mul(o.into())) + // Minimum execution time: 2_197_000 picoseconds. + Weight::from_parts(2_464_654, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(296, 0).saturating_mul(n.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(342, 0).saturating_mul(o.into())) } - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_896_000 picoseconds. - Weight::from_parts(2_254_323, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(439, 0).saturating_mul(n.into())) + // Minimum execution time: 2_005_000 picoseconds. + Weight::from_parts(2_381_053, 0) + // Standard Error: 23 + .saturating_add(Weight::from_parts(322, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_800_000 picoseconds. - Weight::from_parts(1_948_552, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(360, 0).saturating_mul(n.into())) + // Minimum execution time: 1_853_000 picoseconds. + Weight::from_parts(2_082_772, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(322, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_615_000 picoseconds. - Weight::from_parts(1_812_731, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(1_899_649, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(208, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 512]`. - fn seal_take_transient_storage(_n: u32, ) -> Weight { + /// The range of component `n` is `[0, 448]`. + fn seal_take_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_430_000 picoseconds. - Weight::from_parts(2_669_757, 0) - } - /// Storage: `Revive::AddressSuffix` (r:1 w:0) - /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) - fn seal_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `315` - // Estimated: `3780` - // Minimum execution time: 14_740_000 picoseconds. - Weight::from_parts(15_320_000, 3780) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 2_460_000 picoseconds. + Weight::from_parts(2_684_364, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(56, 0).saturating_mul(n.into())) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -808,31 +867,38 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 262144]`. fn seal_call(t: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1292 + t * (103 ±0)` - // Estimated: `4757 + t * (103 ±0)` - // Minimum execution time: 37_280_000 picoseconds. - Weight::from_parts(41_639_379, 4757) + // Measured: `1292 + t * (203 ±0)` + // Estimated: `4757 + t * (2480 ±0)` + // Minimum execution time: 40_031_000 picoseconds. + Weight::from_parts(41_527_691, 4757) + // Standard Error: 50_351 + .saturating_add(Weight::from_parts(1_112_950, 0).saturating_mul(t.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(2, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 103).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2480).saturating_mul(t.into())) } + /// Storage: `Revive::ContractInfoOf` (r:1 w:0) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) fn seal_delegate_call() -> Weight { // Proof Size summary in bytes: - // Measured: `1064` - // Estimated: `4529` - // Minimum execution time: 27_564_000 picoseconds. - Weight::from_parts(28_809_000, 4529) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `1237` + // Estimated: `4702` + // Minimum execution time: 35_759_000 picoseconds. + Weight::from_parts(37_086_000, 4702) + .saturating_add(T::DbWeight::get().reads(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -845,12 +911,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 262144]`. fn seal_instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1273` - // Estimated: `4732` - // Minimum execution time: 115_581_000 picoseconds. - Weight::from_parts(105_196_218, 4732) - // Standard Error: 11 - .saturating_add(Weight::from_parts(4_134, 0).saturating_mul(i.into())) + // Measured: `1271` + // Estimated: `4710` + // Minimum execution time: 116_485_000 picoseconds. + Weight::from_parts(108_907_717, 4710) + // Standard Error: 12 + .saturating_add(Weight::from_parts(4_125, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -859,64 +925,64 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 605_000 picoseconds. - Weight::from_parts(3_425_431, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_461, 0).saturating_mul(n.into())) + // Minimum execution time: 651_000 picoseconds. + Weight::from_parts(3_867_609, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_384, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_113_000 picoseconds. - Weight::from_parts(4_611_854, 0) + // Minimum execution time: 1_090_000 picoseconds. + Weight::from_parts(5_338_460, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_652, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_601, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 610_000 picoseconds. - Weight::from_parts(3_872_321, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_584, 0).saturating_mul(n.into())) + // Minimum execution time: 717_000 picoseconds. + Weight::from_parts(2_629_461, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_528, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 559_000 picoseconds. - Weight::from_parts(4_721_584, 0) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(4_807_814, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(1_570, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_509, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 261889]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 47_467_000 picoseconds. - Weight::from_parts(36_639_352, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(5_216, 0).saturating_mul(n.into())) + // Minimum execution time: 42_829_000 picoseconds. + Weight::from_parts(24_650_992, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(5_212, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 48_106_000 picoseconds. - Weight::from_parts(49_352_000, 0) + // Minimum execution time: 46_902_000 picoseconds. + Weight::from_parts(48_072_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_616_000 picoseconds. - Weight::from_parts(12_796_000, 0) + // Minimum execution time: 12_713_000 picoseconds. + Weight::from_parts(12_847_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -924,8 +990,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `300` // Estimated: `3765` - // Minimum execution time: 14_055_000 picoseconds. - Weight::from_parts(14_526_000, 3765) + // Minimum execution time: 17_657_000 picoseconds. + Weight::from_parts(18_419_000, 3765) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -933,10 +999,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn lock_delegate_dependency() -> Weight { // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `3802` - // Minimum execution time: 10_338_000 picoseconds. - Weight::from_parts(10_677_000, 3802) + // Measured: `338` + // Estimated: `3803` + // Minimum execution time: 13_650_000 picoseconds. + Weight::from_parts(14_209_000, 3803) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -944,10 +1010,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) fn unlock_delegate_dependency() -> Weight { // Proof Size summary in bytes: - // Measured: `337` + // Measured: `338` // Estimated: `3561` - // Minimum execution time: 8_740_000 picoseconds. - Weight::from_parts(9_329_000, 3561) + // Minimum execution time: 12_341_000 picoseconds. + Weight::from_parts(13_011_000, 3561) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -956,10 +1022,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_846_000 picoseconds. - Weight::from_parts(9_717_991, 0) - // Standard Error: 49 - .saturating_add(Weight::from_parts(72_062, 0).saturating_mul(r.into())) + // Minimum execution time: 8_899_000 picoseconds. + Weight::from_parts(10_489_171, 0) + // Standard Error: 104 + .saturating_add(Weight::from_parts(73_814, 0).saturating_mul(r.into())) } } @@ -971,8 +1037,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_649_000 picoseconds. - Weight::from_parts(2_726_000, 1594) + // Minimum execution time: 2_859_000 picoseconds. + Weight::from_parts(3_007_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -982,10 +1048,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `425 + k * (69 ±0)` // Estimated: `415 + k * (70 ±0)` - // Minimum execution time: 12_756_000 picoseconds. - Weight::from_parts(13_112_000, 415) - // Standard Error: 988 - .saturating_add(Weight::from_parts(1_131_927, 0).saturating_mul(k.into())) + // Minimum execution time: 15_640_000 picoseconds. + Weight::from_parts(1_609_026, 415) + // Standard Error: 1_359 + .saturating_add(Weight::from_parts(1_204_420, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1007,10 +1073,10 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 262144]`. fn call_with_code_per_byte(_c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1465` - // Estimated: `7405` - // Minimum execution time: 86_553_000 picoseconds. - Weight::from_parts(89_689_079, 7405) + // Measured: `1463` + // Estimated: `7403` + // Minimum execution time: 89_437_000 picoseconds. + Weight::from_parts(94_285_182, 7403) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1030,14 +1096,16 @@ impl WeightInfo for () { /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. /// The range of component `i` is `[0, 262144]`. - fn instantiate_with_code(_c: u32, i: u32, ) -> Weight { + fn instantiate_with_code(c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `416` - // Estimated: `6333` - // Minimum execution time: 180_721_000 picoseconds. - Weight::from_parts(155_866_981, 6333) + // Measured: `364` + // Estimated: `6327` + // Minimum execution time: 187_904_000 picoseconds. + Weight::from_parts(153_252_081, 6327) + // Standard Error: 11 + .saturating_add(Weight::from_parts(49, 0).saturating_mul(c.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_514, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_528, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1059,11 +1127,11 @@ impl WeightInfo for () { fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1296` - // Estimated: `4741` - // Minimum execution time: 151_590_000 picoseconds. - Weight::from_parts(128_110_988, 4741) + // Estimated: `4758` + // Minimum execution time: 154_656_000 picoseconds. + Weight::from_parts(139_308_398, 4758) // Standard Error: 16 - .saturating_add(Weight::from_parts(4_453, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_421, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1081,10 +1149,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `1465` - // Estimated: `7405` - // Minimum execution time: 136_371_000 picoseconds. - Weight::from_parts(140_508_000, 7405) + // Measured: `1463` + // Estimated: `7403` + // Minimum execution time: 138_815_000 picoseconds. + Weight::from_parts(149_067_000, 7403) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1099,8 +1167,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 51_255_000 picoseconds. - Weight::from_parts(52_668_809, 3574) + // Minimum execution time: 49_978_000 picoseconds. + Weight::from_parts(51_789_325, 3574) // Standard Error: 0 .saturating_add(Weight::from_parts(1, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) @@ -1116,8 +1184,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 41_664_000 picoseconds. - Weight::from_parts(42_981_000, 3750) + // Minimum execution time: 43_833_000 picoseconds. + Weight::from_parts(44_660_000, 3750) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1129,8 +1197,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `529` // Estimated: `6469` - // Minimum execution time: 27_020_000 picoseconds. - Weight::from_parts(27_973_000, 6469) + // Minimum execution time: 26_717_000 picoseconds. + Weight::from_parts(28_566_000, 6469) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1142,8 +1210,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 42_342_000 picoseconds. - Weight::from_parts(43_210_000, 3574) + // Minimum execution time: 39_401_000 picoseconds. + Weight::from_parts(40_542_000, 3574) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1155,8 +1223,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `56` // Estimated: `3521` - // Minimum execution time: 31_881_000 picoseconds. - Weight::from_parts(32_340_000, 3521) + // Minimum execution time: 31_570_000 picoseconds. + Weight::from_parts(32_302_000, 3521) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1168,8 +1236,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 11_087_000 picoseconds. - Weight::from_parts(11_416_000, 3610) + // Minimum execution time: 13_607_000 picoseconds. + Weight::from_parts(13_903_000, 3610) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -1177,24 +1245,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_403_000 picoseconds. - Weight::from_parts(7_751_101, 0) - // Standard Error: 99 - .saturating_add(Weight::from_parts(179_467, 0).saturating_mul(r.into())) + // Minimum execution time: 7_400_000 picoseconds. + Weight::from_parts(8_388_251, 0) + // Standard Error: 283 + .saturating_add(Weight::from_parts(165_630, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 272_000 picoseconds. - Weight::from_parts(306_000, 0) + // Minimum execution time: 275_000 picoseconds. + Weight::from_parts(305_000, 0) } fn seal_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 226_000 picoseconds. - Weight::from_parts(261_000, 0) + // Minimum execution time: 224_000 picoseconds. + Weight::from_parts(265_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) @@ -1202,8 +1270,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `306` // Estimated: `3771` - // Minimum execution time: 6_727_000 picoseconds. - Weight::from_parts(7_122_000, 3771) + // Minimum execution time: 10_004_000 picoseconds. + Weight::from_parts(10_336_000, 3771) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) @@ -1212,16 +1280,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 7_542_000 picoseconds. - Weight::from_parts(7_846_000, 3868) + // Minimum execution time: 11_054_000 picoseconds. + Weight::from_parts(11_651_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 243_000 picoseconds. - Weight::from_parts(275_000, 0) + // Minimum execution time: 252_000 picoseconds. + Weight::from_parts(305_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) @@ -1231,44 +1299,51 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `473` // Estimated: `3938` - // Minimum execution time: 11_948_000 picoseconds. - Weight::from_parts(12_406_000, 3938) + // Minimum execution time: 14_461_000 picoseconds. + Weight::from_parts(15_049_000, 3938) .saturating_add(RocksDbWeight::get().reads(2_u64)) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 329_000 picoseconds. - Weight::from_parts(362_000, 0) + // Minimum execution time: 312_000 picoseconds. + Weight::from_parts(338_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 276_000 picoseconds. - Weight::from_parts(303_000, 0) + // Minimum execution time: 243_000 picoseconds. + Weight::from_parts(299_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 251_000 picoseconds. - Weight::from_parts(286_000, 0) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(271_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 611_000 picoseconds. - Weight::from_parts(669_000, 0) + // Minimum execution time: 683_000 picoseconds. + Weight::from_parts(732_000, 0) + } + fn seal_ref_time_left() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 226_000 picoseconds. + Weight::from_parts(273_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `103` + // Measured: `102` // Estimated: `0` - // Minimum execution time: 4_439_000 picoseconds. - Weight::from_parts(4_572_000, 0) + // Minimum execution time: 4_626_000 picoseconds. + Weight::from_parts(4_842_000, 0) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -1278,8 +1353,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `264` // Estimated: `3729` - // Minimum execution time: 9_336_000 picoseconds. - Weight::from_parts(9_622_000, 3729) + // Minimum execution time: 12_309_000 picoseconds. + Weight::from_parts(12_653_000, 3729) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -1289,10 +1364,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238 + n * (1 ±0)` // Estimated: `3703 + n * (1 ±0)` - // Minimum execution time: 5_660_000 picoseconds. - Weight::from_parts(6_291_437, 3703) - // Standard Error: 4 - .saturating_add(Weight::from_parts(741, 0).saturating_mul(n.into())) + // Minimum execution time: 5_838_000 picoseconds. + Weight::from_parts(9_570_778, 3703) + // Standard Error: 19 + .saturating_add(Weight::from_parts(721, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1303,32 +1378,67 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_909_000 picoseconds. - Weight::from_parts(2_154_705, 0) + // Minimum execution time: 1_910_000 picoseconds. + Weight::from_parts(2_205_396, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(643, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(538, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 241_000 picoseconds. - Weight::from_parts(283_000, 0) + // Minimum execution time: 224_000 picoseconds. + Weight::from_parts(274_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 263_000 picoseconds. - Weight::from_parts(294_000, 0) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(279_000, 0) } - fn seal_block_number() -> Weight { + fn seal_return_data_size() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 229_000 picoseconds. + Weight::from_parts(267_000, 0) + } + fn seal_call_data_size() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 218_000 picoseconds. - Weight::from_parts(281_000, 0) + Weight::from_parts(267_000, 0) + } + fn seal_gas_limit() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 225_000 picoseconds. + Weight::from_parts(280_000, 0) + } + fn seal_gas_price() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 274_000 picoseconds. + Weight::from_parts(323_000, 0) + } + fn seal_base_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 239_000 picoseconds. + Weight::from_parts(290_000, 0) + } + fn seal_block_number() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 224_000 picoseconds. + Weight::from_parts(274_000, 0) } /// Storage: `System::BlockHash` (r:1 w:0) /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `Measured`) @@ -1336,36 +1446,50 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `30` // Estimated: `3495` - // Minimum execution time: 3_373_000 picoseconds. - Weight::from_parts(3_610_000, 3495) + // Minimum execution time: 3_430_000 picoseconds. + Weight::from_parts(3_692_000, 3495) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 247_000 picoseconds. - Weight::from_parts(299_000, 0) + // Minimum execution time: 241_000 picoseconds. + Weight::from_parts(290_000, 0) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) fn seal_weight_to_fee() -> Weight { // Proof Size summary in bytes: - // Measured: `67` - // Estimated: `1552` - // Minimum execution time: 5_523_000 picoseconds. - Weight::from_parts(5_757_000, 1552) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_355_000 picoseconds. + Weight::from_parts(1_493_000, 0) } /// The range of component `n` is `[0, 262140]`. - fn seal_input(n: u32, ) -> Weight { + fn seal_copy_to_contract(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 348_000 picoseconds. + Weight::from_parts(1_004_890, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(202, 0).saturating_mul(n.into())) + } + fn seal_call_data_load() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 222_000 picoseconds. + Weight::from_parts(256_000, 0) + } + /// The range of component `n` is `[0, 262144]`. + fn seal_call_data_copy(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 450_000 picoseconds. - Weight::from_parts(584_658, 0) + // Minimum execution time: 240_000 picoseconds. + Weight::from_parts(330_609, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(147, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(114, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262140]`. fn seal_return(n: u32, ) -> Weight { @@ -1373,9 +1497,9 @@ impl WeightInfo for () { // Measured: `0` // Estimated: `0` // Minimum execution time: 232_000 picoseconds. - Weight::from_parts(611_960, 0) + Weight::from_parts(264_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(294, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(208, 0).saturating_mul(n.into())) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -1390,12 +1514,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 32]`. fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `321 + n * (88 ±0)` + // Measured: `322 + n * (88 ±0)` // Estimated: `3787 + n * (2563 ±0)` - // Minimum execution time: 19_158_000 picoseconds. - Weight::from_parts(20_900_189, 3787) - // Standard Error: 9_648 - .saturating_add(Weight::from_parts(4_239_910, 0).saturating_mul(n.into())) + // Minimum execution time: 21_920_000 picoseconds. + Weight::from_parts(21_725_868, 3787) + // Standard Error: 11_165 + .saturating_add(Weight::from_parts(4_317_986, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1403,56 +1527,56 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2563).saturating_mul(n.into())) } /// The range of component `t` is `[0, 4]`. - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_deposit_event(t: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_097_000 picoseconds. - Weight::from_parts(3_956_608, 0) - // Standard Error: 2_678 - .saturating_add(Weight::from_parts(178_555, 0).saturating_mul(t.into())) - // Standard Error: 23 - .saturating_add(Weight::from_parts(1_127, 0).saturating_mul(n.into())) + // Minimum execution time: 4_140_000 picoseconds. + Weight::from_parts(4_259_301, 0) + // Standard Error: 3_362 + .saturating_add(Weight::from_parts(194_546, 0).saturating_mul(t.into())) + // Standard Error: 34 + .saturating_add(Weight::from_parts(774, 0).saturating_mul(n.into())) } /// The range of component `i` is `[0, 262144]`. fn seal_debug_message(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 277_000 picoseconds. - Weight::from_parts(1_044_051, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(794, 0).saturating_mul(i.into())) + // Minimum execution time: 340_000 picoseconds. + Weight::from_parts(306_527, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(728, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn get_storage_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `744` - // Estimated: `744` - // Minimum execution time: 7_745_000 picoseconds. - Weight::from_parts(8_370_000, 744) + // Measured: `680` + // Estimated: `680` + // Minimum execution time: 10_747_000 picoseconds. + Weight::from_parts(11_276_000, 680) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn get_storage_full() -> Weight { // Proof Size summary in bytes: - // Measured: `10754` - // Estimated: `10754` - // Minimum execution time: 43_559_000 picoseconds. - Weight::from_parts(44_310_000, 10754) + // Measured: `10690` + // Estimated: `10690` + // Minimum execution time: 42_076_000 picoseconds. + Weight::from_parts(43_381_000, 10690) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_storage_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `744` - // Estimated: `744` - // Minimum execution time: 8_866_000 picoseconds. - Weight::from_parts(9_072_000, 744) + // Measured: `680` + // Estimated: `680` + // Minimum execution time: 11_703_000 picoseconds. + Weight::from_parts(12_308_000, 680) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1460,85 +1584,85 @@ impl WeightInfo for () { /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_storage_full() -> Weight { // Proof Size summary in bytes: - // Measured: `10754` - // Estimated: `10754` - // Minimum execution time: 44_481_000 picoseconds. - Weight::from_parts(45_157_000, 10754) + // Measured: `10690` + // Estimated: `10690` + // Minimum execution time: 43_460_000 picoseconds. + Weight::from_parts(45_165_000, 10690) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. - /// The range of component `o` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. + /// The range of component `o` is `[0, 448]`. fn seal_set_storage(n: u32, o: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 9_130_000 picoseconds. - Weight::from_parts(9_709_648, 247) - // Standard Error: 40 - .saturating_add(Weight::from_parts(435, 0).saturating_mul(n.into())) - // Standard Error: 40 - .saturating_add(Weight::from_parts(384, 0).saturating_mul(o.into())) + // Minimum execution time: 9_087_000 picoseconds. + Weight::from_parts(11_787_486, 247) + // Standard Error: 179 + .saturating_add(Weight::from_parts(976, 0).saturating_mul(n.into())) + // Standard Error: 179 + .saturating_add(Weight::from_parts(3_151, 0).saturating_mul(o.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_clear_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_753_000 picoseconds. - Weight::from_parts(9_558_399, 247) - // Standard Error: 56 - .saturating_add(Weight::from_parts(483, 0).saturating_mul(n.into())) + // Minimum execution time: 8_611_000 picoseconds. + Weight::from_parts(11_791_390, 247) + // Standard Error: 308 + .saturating_add(Weight::from_parts(3_943, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_get_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_328_000 picoseconds. - Weight::from_parts(9_120_157, 247) - // Standard Error: 58 - .saturating_add(Weight::from_parts(1_637, 0).saturating_mul(n.into())) + // Minimum execution time: 8_389_000 picoseconds. + Weight::from_parts(11_625_480, 247) + // Standard Error: 315 + .saturating_add(Weight::from_parts(4_487, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_contains_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 7_977_000 picoseconds. - Weight::from_parts(8_582_869, 247) - // Standard Error: 52 - .saturating_add(Weight::from_parts(854, 0).saturating_mul(n.into())) + // Minimum execution time: 7_947_000 picoseconds. + Weight::from_parts(10_970_587, 247) + // Standard Error: 310 + .saturating_add(Weight::from_parts(3_675, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_take_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_193_000 picoseconds. - Weight::from_parts(10_112_966, 247) - // Standard Error: 63 - .saturating_add(Weight::from_parts(1_320, 0).saturating_mul(n.into())) + // Minimum execution time: 9_071_000 picoseconds. + Weight::from_parts(12_525_027, 247) + // Standard Error: 328 + .saturating_add(Weight::from_parts(4_427, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1547,97 +1671,89 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_398_000 picoseconds. - Weight::from_parts(1_490_000, 0) + // Minimum execution time: 1_487_000 picoseconds. + Weight::from_parts(1_611_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_762_000 picoseconds. - Weight::from_parts(1_926_000, 0) + // Minimum execution time: 1_852_000 picoseconds. + Weight::from_parts(1_982_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_413_000 picoseconds. - Weight::from_parts(1_494_000, 0) + // Minimum execution time: 1_467_000 picoseconds. + Weight::from_parts(1_529_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_606_000 picoseconds. - Weight::from_parts(1_659_000, 0) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(1_712_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_010_000 picoseconds. - Weight::from_parts(1_117_000, 0) + // Minimum execution time: 1_188_000 picoseconds. + Weight::from_parts(1_268_000, 0) } - /// The range of component `n` is `[0, 512]`. - /// The range of component `o` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. + /// The range of component `o` is `[0, 448]`. fn seal_set_transient_storage(n: u32, o: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_194_000 picoseconds. - Weight::from_parts(2_290_633, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(341, 0).saturating_mul(n.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(377, 0).saturating_mul(o.into())) + // Minimum execution time: 2_197_000 picoseconds. + Weight::from_parts(2_464_654, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(296, 0).saturating_mul(n.into())) + // Standard Error: 17 + .saturating_add(Weight::from_parts(342, 0).saturating_mul(o.into())) } - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_896_000 picoseconds. - Weight::from_parts(2_254_323, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(439, 0).saturating_mul(n.into())) + // Minimum execution time: 2_005_000 picoseconds. + Weight::from_parts(2_381_053, 0) + // Standard Error: 23 + .saturating_add(Weight::from_parts(322, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_800_000 picoseconds. - Weight::from_parts(1_948_552, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(360, 0).saturating_mul(n.into())) + // Minimum execution time: 1_853_000 picoseconds. + Weight::from_parts(2_082_772, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(322, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 512]`. + /// The range of component `n` is `[0, 448]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_615_000 picoseconds. - Weight::from_parts(1_812_731, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(177, 0).saturating_mul(n.into())) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(1_899_649, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(208, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 512]`. - fn seal_take_transient_storage(_n: u32, ) -> Weight { + /// The range of component `n` is `[0, 448]`. + fn seal_take_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_430_000 picoseconds. - Weight::from_parts(2_669_757, 0) - } - /// Storage: `Revive::AddressSuffix` (r:1 w:0) - /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) - fn seal_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `315` - // Estimated: `3780` - // Minimum execution time: 14_740_000 picoseconds. - Weight::from_parts(15_320_000, 3780) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 2_460_000 picoseconds. + Weight::from_parts(2_684_364, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(56, 0).saturating_mul(n.into())) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -1647,31 +1763,38 @@ impl WeightInfo for () { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 262144]`. fn seal_call(t: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1292 + t * (103 ±0)` - // Estimated: `4757 + t * (103 ±0)` - // Minimum execution time: 37_280_000 picoseconds. - Weight::from_parts(41_639_379, 4757) + // Measured: `1292 + t * (203 ±0)` + // Estimated: `4757 + t * (2480 ±0)` + // Minimum execution time: 40_031_000 picoseconds. + Weight::from_parts(41_527_691, 4757) + // Standard Error: 50_351 + .saturating_add(Weight::from_parts(1_112_950, 0).saturating_mul(t.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(2, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 103).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2480).saturating_mul(t.into())) } + /// Storage: `Revive::ContractInfoOf` (r:1 w:0) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) fn seal_delegate_call() -> Weight { // Proof Size summary in bytes: - // Measured: `1064` - // Estimated: `4529` - // Minimum execution time: 27_564_000 picoseconds. - Weight::from_parts(28_809_000, 4529) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `1237` + // Estimated: `4702` + // Minimum execution time: 35_759_000 picoseconds. + Weight::from_parts(37_086_000, 4702) + .saturating_add(RocksDbWeight::get().reads(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1684,12 +1807,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn seal_instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1273` - // Estimated: `4732` - // Minimum execution time: 115_581_000 picoseconds. - Weight::from_parts(105_196_218, 4732) - // Standard Error: 11 - .saturating_add(Weight::from_parts(4_134, 0).saturating_mul(i.into())) + // Measured: `1271` + // Estimated: `4710` + // Minimum execution time: 116_485_000 picoseconds. + Weight::from_parts(108_907_717, 4710) + // Standard Error: 12 + .saturating_add(Weight::from_parts(4_125, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1698,64 +1821,64 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 605_000 picoseconds. - Weight::from_parts(3_425_431, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_461, 0).saturating_mul(n.into())) + // Minimum execution time: 651_000 picoseconds. + Weight::from_parts(3_867_609, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_384, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_113_000 picoseconds. - Weight::from_parts(4_611_854, 0) + // Minimum execution time: 1_090_000 picoseconds. + Weight::from_parts(5_338_460, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_652, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_601, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 610_000 picoseconds. - Weight::from_parts(3_872_321, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_584, 0).saturating_mul(n.into())) + // Minimum execution time: 717_000 picoseconds. + Weight::from_parts(2_629_461, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_528, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 559_000 picoseconds. - Weight::from_parts(4_721_584, 0) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(4_807_814, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(1_570, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_509, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 261889]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 47_467_000 picoseconds. - Weight::from_parts(36_639_352, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(5_216, 0).saturating_mul(n.into())) + // Minimum execution time: 42_829_000 picoseconds. + Weight::from_parts(24_650_992, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(5_212, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 48_106_000 picoseconds. - Weight::from_parts(49_352_000, 0) + // Minimum execution time: 46_902_000 picoseconds. + Weight::from_parts(48_072_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_616_000 picoseconds. - Weight::from_parts(12_796_000, 0) + // Minimum execution time: 12_713_000 picoseconds. + Weight::from_parts(12_847_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1763,8 +1886,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `300` // Estimated: `3765` - // Minimum execution time: 14_055_000 picoseconds. - Weight::from_parts(14_526_000, 3765) + // Minimum execution time: 17_657_000 picoseconds. + Weight::from_parts(18_419_000, 3765) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1772,10 +1895,10 @@ impl WeightInfo for () { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn lock_delegate_dependency() -> Weight { // Proof Size summary in bytes: - // Measured: `337` - // Estimated: `3802` - // Minimum execution time: 10_338_000 picoseconds. - Weight::from_parts(10_677_000, 3802) + // Measured: `338` + // Estimated: `3803` + // Minimum execution time: 13_650_000 picoseconds. + Weight::from_parts(14_209_000, 3803) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1783,10 +1906,10 @@ impl WeightInfo for () { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `MaxEncodedLen`) fn unlock_delegate_dependency() -> Weight { // Proof Size summary in bytes: - // Measured: `337` + // Measured: `338` // Estimated: `3561` - // Minimum execution time: 8_740_000 picoseconds. - Weight::from_parts(9_329_000, 3561) + // Minimum execution time: 12_341_000 picoseconds. + Weight::from_parts(13_011_000, 3561) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1795,9 +1918,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_846_000 picoseconds. - Weight::from_parts(9_717_991, 0) - // Standard Error: 49 - .saturating_add(Weight::from_parts(72_062, 0).saturating_mul(r.into())) + // Minimum execution time: 8_899_000 picoseconds. + Weight::from_parts(10_489_171, 0) + // Standard Error: 104 + .saturating_add(Weight::from_parts(73_814, 0).saturating_mul(r.into())) } } diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 0c7461a35d69..7241d667fcdc 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -12,20 +12,23 @@ description = "Exposes all the host functions that a contract can import." workspace = true [dependencies] -paste = { workspace = true } bitflags = { workspace = true } -scale-info = { features = ["derive"], optional = true, workspace = true } codec = { features = [ "derive", "max-encoded-len", ], optional = true, workspace = true } +pallet-revive-proc-macro = { workspace = true } +paste = { workspace = true } +scale-info = { features = ["derive"], optional = true, workspace = true } -[target.'cfg(target_arch = "riscv32")'.dependencies] -polkavm-derive = { version = "0.14.0" } +[target.'cfg(target_arch = "riscv64")'.dependencies] +polkavm-derive = { version = "0.18.0" } [package.metadata.docs.rs] -default-target = ["wasm32-unknown-unknown"] +features = ["unstable-hostfn"] +targets = ["riscv64imac-unknown-none-elf"] [features] default = ["scale"] scale = ["dep:codec", "scale-info"] +unstable-hostfn = [] diff --git a/substrate/frame/revive/uapi/src/flags.rs b/substrate/frame/revive/uapi/src/flags.rs index 763a89d6c030..6a0f47c38c2c 100644 --- a/substrate/frame/revive/uapi/src/flags.rs +++ b/substrate/frame/revive/uapi/src/flags.rs @@ -38,7 +38,7 @@ bitflags! { /// /// A forwarding call will consume the current contracts input. Any attempt to /// access the input after this call returns will lead to [`Error::InputForwarded`]. - /// It does not matter if this is due to calling `seal_input` or trying another + /// It does not matter if this is due to calling `call_data_copy` or trying another /// forwarding call. Consider using [`Self::CLONE_INPUT`] in order to preserve /// the input. const FORWARD_INPUT = 0b0000_0001; diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index cf4cdeee0f28..eced4843b552 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -12,26 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. use crate::{CallFlags, Result, ReturnFlags, StorageFlags}; -use paste::paste; - -#[cfg(target_arch = "riscv32")] -mod riscv32; - -macro_rules! hash_fn { - ( $name:ident, $bytes:literal ) => { - paste! { - #[doc = "Computes the " $name " " $bytes "-bit hash on the given input buffer."] - #[doc = "\n# Notes\n"] - #[doc = "- The `input` and `output` buffer may overlap."] - #[doc = "- The output buffer is expected to hold at least " $bytes " bits."] - #[doc = "- It is the callers responsibility to provide an output buffer that is large enough to hold the expected amount of bytes returned by the hash function."] - #[doc = "\n# Parameters\n"] - #[doc = "- `input`: The input data buffer."] - #[doc = "- `output`: The output buffer to write the hash result to."] - fn [](input: &[u8], output: &mut [u8; $bytes]); - } - }; -} +use pallet_revive_proc_macro::unstable_hostfn; + +#[cfg(target_arch = "riscv64")] +mod riscv64; /// Implements [`HostFn`] when compiled on supported architectures (RISC-V). pub enum HostFnImpl {} @@ -45,17 +29,6 @@ pub trait HostFn: private::Sealed { /// - `output`: A reference to the output data buffer to write the address. fn address(output: &mut [u8; 20]); - /// Lock a new delegate dependency to the contract. - /// - /// Traps if the maximum number of delegate_dependencies is reached or if - /// the delegate dependency already exists. - /// - /// # Parameters - /// - /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps - /// otherwise. - fn lock_delegate_dependency(code_hash: &[u8; 32]); - /// Get the contract immutable data. /// /// Traps if: @@ -98,20 +71,16 @@ pub trait HostFn: private::Sealed { /// Returns the [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID. fn chain_id(output: &mut [u8; 32]); - /// Stores the current block number of the current contract into the supplied buffer. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the block number. - fn block_number(output: &mut [u8; 32]); + /// Returns the price per ref_time, akin to the EVM + /// [GASPRICE](https://www.evm.codes/?fork=cancun#3a) opcode. + fn gas_price() -> u64; - /// Stores the block hash of the given block number into the supplied buffer. - /// - /// # Parameters - /// - /// - `block_number`: A reference to the block number buffer. - /// - `output`: A reference to the output data buffer to write the block number. - fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]); + /// Returns the base fee, akin to the EVM + /// [BASEFEE](https://www.evm.codes/?fork=cancun#48) opcode. + fn base_fee(output: &mut [u8; 32]); + + /// Returns the call data size. + fn call_data_size() -> u64; /// Call (possibly transferring some amount of funds) into the specified account. /// @@ -138,7 +107,7 @@ pub trait HostFn: private::Sealed { /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] - /// - [NotCallable][`crate::ReturnErrorCode::NotCallable] + /// - [OutOfResources][`crate::ReturnErrorCode::OutOfResources] fn call( flags: CallFlags, callee: &[u8; 20], @@ -150,6 +119,302 @@ pub trait HostFn: private::Sealed { output: Option<&mut &mut [u8]>, ) -> Result; + /// Stores the address of the caller into the supplied buffer. + /// + /// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the + /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then + /// the address of the contract will be returned. + /// + /// If there is no address associated with the caller (e.g. because the caller is root) then + /// it traps with `BadOrigin`. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the caller address. + fn caller(output: &mut [u8; 20]); + + /// Stores the origin address (initator of the call stack) into the supplied buffer. + /// + /// If there is no address associated with the origin (e.g. because the origin is root) then + /// it traps with `BadOrigin`. This can only happen through on-chain governance actions or + /// customized runtimes. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the origin's address. + fn origin(output: &mut [u8; 20]); + + /// Retrieve the code hash for a specified contract address. + /// + /// # Parameters + /// + /// - `addr`: The address of the contract. + /// - `output`: A reference to the output data buffer to write the code hash. + /// + /// # Note + /// + /// If `addr` is not a contract but the account exists then the hash of empty data + /// `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` is written, + /// otherwise `zero`. + fn code_hash(addr: &[u8; 20], output: &mut [u8; 32]); + + /// Returns the code size for a specified contract address. + /// + /// # Parameters + /// + /// - `addr`: The address of the contract. + /// + /// # Note + /// + /// If `addr` is not a contract the `output` will be zero. + fn code_size(addr: &[u8; 20]) -> u64; + + /// Execute code in the context (storage, caller, value) of the current contract. + /// + /// Reentrancy protection is always disabled since the callee is allowed + /// to modify the callers storage. This makes going through a reentrancy attack + /// unnecessary for the callee when it wants to exploit the caller. + /// + /// # Parameters + /// + /// - `flags`: See [`CallFlags`] for a documentation of the supported flags. + /// - `address`: The address of the code to be executed. Should be decodable as an + /// `T::AccountId`. Traps otherwise. + /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. + /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. + /// - `deposit_limit`: The storage deposit limit for delegate call. Passing `None` means setting + /// no specific limit for the call, which implies storage usage up to the limit of the parent + /// call. + /// - `input`: The input data buffer used to call the contract. + /// - `output`: A reference to the output data buffer to write the call output buffer. If `None` + /// is provided then the output buffer is not copied. + /// + /// # Errors + /// + /// An error means that the call wasn't successful and no output buffer is returned unless + /// stated otherwise. + /// + /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. + /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] + /// - [OutOfResources][`crate::ReturnErrorCode::OutOfResources] + fn delegate_call( + flags: CallFlags, + address: &[u8; 20], + ref_time_limit: u64, + proof_size_limit: u64, + deposit_limit: Option<&[u8; 32]>, + input_data: &[u8], + output: Option<&mut &mut [u8]>, + ) -> Result; + + /// Deposit a contract event with the data buffer and optional list of topics. There is a limit + /// on the maximum number of topics specified by `event_topics`. + /// + /// There should not be any duplicates in `topics`. + /// + /// # Parameters + /// + /// - `topics`: The topics list. It can't contain duplicates. + fn deposit_event(topics: &[[u8; 32]], data: &[u8]); + + /// Retrieve the value under the given key from storage. + /// + /// The key length must not exceed the maximum defined by the contracts module parameter. + /// + /// # Parameters + /// - `key`: The storage key. + /// - `output`: A reference to the output data buffer to write the storage entry. + /// + /// # Errors + /// + /// [KeyNotFound][`crate::ReturnErrorCode::KeyNotFound] + fn get_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result; + + /// Computes the keccak_256 32-bit hash on the given input buffer. + /// + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 32 bits. + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the hash function. + /// + /// # Parameters + /// + /// - `input`: The input data buffer. + /// - `output`: The output buffer to write the hash result to. + fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]); + + /// Stores the input data passed by the caller into the supplied `output` buffer, + /// starting from the given input data `offset`. + /// + /// The `output` buffer is guaranteed to always be fully populated: + /// - If the call data (starting from the given `offset`) is larger than the `output` buffer, + /// only what fits into the `output` buffer is written. + /// - If the `output` buffer size exceeds the call data size (starting from `offset`), remaining + /// bytes in the `output` buffer are zeroed out. + /// - If the provided call data `offset` is out-of-bounds, the whole `output` buffer is zeroed + /// out. + /// + /// # Note + /// + /// This function traps if: + /// - the input was previously forwarded by a [`call()`][`Self::call()`]. + /// - the `output` buffer is located in an PolkaVM invalid memory range. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the call data. + /// - `offset`: The offset index into the call data from where to start copying. + fn call_data_copy(output: &mut [u8], offset: u32); + + /// Stores the U256 value at given `offset` from the input passed by the caller + /// into the supplied buffer. + /// + /// # Note + /// - If `offset` is out of bounds, a value of zero will be returned. + /// - If `offset` is in bounds but there is not enough call data, the available data + /// is right-padded in order to fill a whole U256 value. + /// - The data written to `output` is a little endian U256 integer value. + /// + /// # Parameters + /// + /// - `output`: A reference to the fixed output data buffer to write the value. + /// - `offset`: The offset (index) into the call data. + fn call_data_load(output: &mut [u8; 32], offset: u32); + + /// Instantiate a contract with the specified code hash. + /// + /// This function creates an account and executes the constructor defined in the code specified + /// by the code hash. + /// + /// # Parameters + /// + /// - `code_hash`: The hash of the code to be instantiated. + /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. + /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. + /// - `deposit`: The storage deposit limit for instantiation. Passing `None` means setting no + /// specific limit for the call, which implies storage usage up to the limit of the parent + /// call. + /// - `value`: The value to transfer into the contract. + /// - `input`: The input data buffer. + /// - `address`: A reference to the address buffer to write the address of the contract. If + /// `None` is provided then the output buffer is not copied. + /// - `output`: A reference to the return value buffer to write the constructor output buffer. + /// If `None` is provided then the output buffer is not copied. + /// - `salt`: The salt bytes to use for this instantiation. + /// + /// # Errors + /// + /// Please consult the [ReturnErrorCode][`crate::ReturnErrorCode`] enum declaration for more + /// information on those errors. Here we only note things specific to this function. + /// + /// An error means that the account wasn't created and no address or output buffer + /// is returned unless stated otherwise. + /// + /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. + /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] + /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] + /// - [OutOfResources][`crate::ReturnErrorCode::OutOfResources] + fn instantiate( + code_hash: &[u8; 32], + ref_time_limit: u64, + proof_size_limit: u64, + deposit: Option<&[u8; 32]>, + value: &[u8; 32], + input: &[u8], + address: Option<&mut [u8; 20]>, + output: Option<&mut &mut [u8]>, + salt: Option<&[u8; 32]>, + ) -> Result; + + /// Load the latest block timestamp into the supplied buffer + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the timestamp. + fn now(output: &mut [u8; 32]); + + /// Returns the block ref_time limit. + fn gas_limit() -> u64; + + /// Cease contract execution and save a data buffer as a result of the execution. + /// + /// This function never returns as it stops execution of the caller. + /// This is the only way to return a data buffer to the caller. Returning from + /// execution without calling this function is equivalent to calling: + /// ```nocompile + /// return_value(ReturnFlags::empty(), &[]) + /// ``` + /// + /// Using an unnamed non empty `ReturnFlags` triggers a trap. + /// + /// # Parameters + /// + /// - `flags`: Flag used to signal special return conditions to the supervisor. See + /// [`ReturnFlags`] for a documentation of the supported flags. + /// - `return_value`: The return value buffer. + fn return_value(flags: ReturnFlags, return_value: &[u8]) -> !; + + /// Set the value at the given key in the contract storage. + /// + /// The key and value lengths must not exceed the maximums defined by the contracts module + /// parameters. + /// + /// # Parameters + /// + /// - `key`: The storage key. + /// - `encoded_value`: The storage value. + /// + /// # Return + /// + /// Returns the size of the pre-existing value at the specified key if any. + fn set_storage(flags: StorageFlags, key: &[u8], value: &[u8]) -> Option; + + /// Stores the value transferred along with this call/instantiate into the supplied buffer. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the transferred value. + fn value_transferred(output: &mut [u8; 32]); + + /// Stores the price for the specified amount of gas into the supplied buffer. + /// + /// # Parameters + /// + /// - `ref_time_limit`: The *ref_time* Weight limit to query the price for. + /// - `proof_size_limit`: The *proof_size* Weight limit to query the price for. + /// - `output`: A reference to the output data buffer to write the price. + fn weight_to_fee(ref_time_limit: u64, proof_size_limit: u64, output: &mut [u8; 32]); + + /// Returns the size of the returned data of the last contract call or instantiation. + fn return_data_size() -> u64; + + /// 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); + + /// Returns the amount of ref_time left. + fn ref_time_left() -> u64; + + /// Stores the current block number of the current contract into the supplied buffer. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the block number. + #[unstable_hostfn] + fn block_number(output: &mut [u8; 32]); + + /// Stores the block hash of the given block number into the supplied buffer. + /// + /// # Parameters + /// + /// - `block_number`: A reference to the block number buffer. + /// - `output`: A reference to the output data buffer to write the block number. + #[unstable_hostfn] + fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]); + /// Call into the chain extension provided by the chain if any. /// /// Handling of the input values is up to the specific chain extension and so is the @@ -172,6 +437,7 @@ pub trait HostFn: private::Sealed { /// # Return /// /// The chain extension returned value, if executed successfully. + #[unstable_hostfn] fn call_chain_extension(func_id: u32, input: &[u8], output: Option<&mut &mut [u8]>) -> u32; /// Call some dispatchable of the runtime. @@ -198,33 +464,9 @@ pub trait HostFn: private::Sealed { /// - Provide functionality **exclusively** to contracts. /// - Provide custom weights. /// - Avoid the need to keep the `Call` data structure stable. + #[unstable_hostfn] fn call_runtime(call: &[u8]) -> Result; - /// Stores the address of the caller into the supplied buffer. - /// - /// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the - /// extrinsic will be returned. Otherwise, if this call is initiated by another contract then - /// the address of the contract will be returned. - /// - /// If there is no address associated with the caller (e.g. because the caller is root) then - /// it traps with `BadOrigin`. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the caller address. - fn caller(output: &mut [u8; 20]); - - /// Stores the origin address (initator of the call stack) into the supplied buffer. - /// - /// If there is no address associated with the origin (e.g. because the origin is root) then - /// it traps with `BadOrigin`. This can only happen through on-chain governance actions or - /// customized runtimes. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the origin's address. - fn origin(output: &mut [u8; 20]); - /// Checks whether the caller of the current contract is the origin of the whole call stack. /// /// Prefer this over [`is_contract()`][`Self::is_contract`] when checking whether your contract @@ -235,6 +477,7 @@ pub trait HostFn: private::Sealed { /// /// A return value of `true` indicates that this contract is being called by a plain account /// and `false` indicates that the caller is another contract. + #[unstable_hostfn] fn caller_is_origin() -> bool; /// Checks whether the caller of the current contract is root. @@ -244,6 +487,7 @@ pub trait HostFn: private::Sealed { /// /// A return value of `true` indicates that this contract is being called by a root origin, /// and `false` indicates that the caller is a signed origin. + #[unstable_hostfn] fn caller_is_root() -> u32; /// Clear the value at the given key in the contract storage. @@ -255,34 +499,9 @@ pub trait HostFn: private::Sealed { /// # Return /// /// Returns the size of the pre-existing value at the specified key if any. + #[unstable_hostfn] fn clear_storage(flags: StorageFlags, key: &[u8]) -> Option; - /// Retrieve the code hash for a specified contract address. - /// - /// # Parameters - /// - /// - `addr`: The address of the contract. - /// - `output`: A reference to the output data buffer to write the code hash. - /// - /// # Note - /// - /// If `addr` is not a contract but the account exists then the hash of empty data - /// `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` is written, - /// otherwise `zero`. - fn code_hash(addr: &[u8; 20], output: &mut [u8; 32]); - - /// Retrieve the code size for a specified contract address. - /// - /// # Parameters - /// - /// - `addr`: The address of the contract. - /// - `output`: A reference to the output data buffer to write the code size. - /// - /// # Note - /// - /// If `addr` is not a contract the `output` will be zero. - fn code_size(addr: &[u8; 20], output: &mut [u8; 32]); - /// Checks whether there is a value stored under the given key. /// /// The key length must not exceed the maximum defined by the contracts module parameter. @@ -293,6 +512,7 @@ pub trait HostFn: private::Sealed { /// # Return /// /// Returns the size of the pre-existing value at the specified key if any. + #[unstable_hostfn] fn contains_storage(flags: StorageFlags, key: &[u8]) -> Option; /// Emit a custom debug message. @@ -312,47 +532,9 @@ pub trait HostFn: private::Sealed { /// not being executed as an RPC. For example, they could allow users to disable logging /// through compile time flags (cargo features) for on-chain deployment. Additionally, the /// return value of this function can be cached in order to prevent further calls at runtime. + #[unstable_hostfn] fn debug_message(str: &[u8]) -> Result; - /// Execute code in the context (storage, caller, value) of the current contract. - /// - /// Reentrancy protection is always disabled since the callee is allowed - /// to modify the callers storage. This makes going through a reentrancy attack - /// unnecessary for the callee when it wants to exploit the caller. - /// - /// # Parameters - /// - /// - `flags`: See [`CallFlags`] for a documentation of the supported flags. - /// - `code_hash`: The hash of the code to be executed. - /// - `input`: The input data buffer used to call the contract. - /// - `output`: A reference to the output data buffer to write the call output buffer. If `None` - /// is provided then the output buffer is not copied. - /// - /// # Errors - /// - /// An error means that the call wasn't successful and no output buffer is returned unless - /// stated otherwise. - /// - /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. - /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] - /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] - fn delegate_call( - flags: CallFlags, - code_hash: &[u8; 32], - input_data: &[u8], - output: Option<&mut &mut [u8]>, - ) -> Result; - - /// Deposit a contract event with the data buffer and optional list of topics. There is a limit - /// on the maximum number of topics specified by `event_topics`. - /// - /// There should not be any duplicates in `topics`. - /// - /// # Parameters - /// - /// - `topics`: The topics list. It can't contain duplicates. - fn deposit_event(topics: &[[u8; 32]], data: &[u8]); - /// Recovers the ECDSA public key from the given message hash and signature. /// /// Writes the public key into the given output buffer. @@ -367,6 +549,7 @@ pub trait HostFn: private::Sealed { /// # Errors /// /// - [EcdsaRecoveryFailed][`crate::ReturnErrorCode::EcdsaRecoveryFailed] + #[unstable_hostfn] fn ecdsa_recover( signature: &[u8; 65], message_hash: &[u8; 32], @@ -384,93 +567,49 @@ pub trait HostFn: private::Sealed { /// # Errors /// /// - [EcdsaRecoveryFailed][`crate::ReturnErrorCode::EcdsaRecoveryFailed] + #[unstable_hostfn] fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result; - /// Stores the amount of weight left into the supplied buffer. - /// The data is encoded as Weight. - /// - /// If the available space in `output` is less than the size of the value a trap is triggered. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the weight left. - fn weight_left(output: &mut &mut [u8]); - - /// Retrieve the value under the given key from storage. + /// Computes the sha2_256 32-bit hash on the given input buffer. /// - /// The key length must not exceed the maximum defined by the contracts module parameter. + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 32 bits. + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the hash function. /// /// # Parameters - /// - `key`: The storage key. - /// - `output`: A reference to the output data buffer to write the storage entry. /// - /// # Errors - /// - /// [KeyNotFound][`crate::ReturnErrorCode::KeyNotFound] - fn get_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result; - - hash_fn!(sha2_256, 32); - hash_fn!(keccak_256, 32); - hash_fn!(blake2_256, 32); - hash_fn!(blake2_128, 16); + /// - `input`: The input data buffer. + /// - `output`: The output buffer to write the hash result to. + #[unstable_hostfn] + fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]); - /// Stores the input passed by the caller into the supplied buffer. - /// - /// # Note + /// Computes the blake2_256 32-bit hash on the given input buffer. /// - /// This function traps if: - /// - the input is larger than the available space. - /// - the input was previously forwarded by a [`call()`][`Self::call()`]. + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 32 bits. + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the hash function. /// /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the input data. - fn input(output: &mut &mut [u8]); + /// */ + /// - `input`: The input data buffer. + /// - `output`: The output buffer to write the hash result to. + #[unstable_hostfn] + fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]); - /// Instantiate a contract with the specified code hash. - /// - /// This function creates an account and executes the constructor defined in the code specified - /// by the code hash. + /// Computes the blake2_128 16-bit hash on the given input buffer. /// + /// - The `input` and `output` buffer may overlap. + /// - The output buffer is expected to hold at least 16 bits. + /// - It is the callers responsibility to provide an output buffer that is large enough to hold + /// the expected amount of bytes returned by the hash function. /// # Parameters /// - /// - `code_hash`: The hash of the code to be instantiated. - /// - `ref_time_limit`: how much *ref_time* Weight to devote to the execution. - /// - `proof_size_limit`: how much *proof_size* Weight to devote to the execution. - /// - `deposit`: The storage deposit limit for instantiation. Passing `None` means setting no - /// specific limit for the call, which implies storage usage up to the limit of the parent - /// call. - /// - `value`: The value to transfer into the contract. /// - `input`: The input data buffer. - /// - `address`: A reference to the address buffer to write the address of the contract. If - /// `None` is provided then the output buffer is not copied. - /// - `output`: A reference to the return value buffer to write the constructor output buffer. - /// If `None` is provided then the output buffer is not copied. - /// - `salt`: The salt bytes to use for this instantiation. - /// - /// # Errors - /// - /// Please consult the [ReturnErrorCode][`crate::ReturnErrorCode`] enum declaration for more - /// information on those errors. Here we only note things specific to this function. - /// - /// An error means that the account wasn't created and no address or output buffer - /// is returned unless stated otherwise. - /// - /// - [CalleeReverted][`crate::ReturnErrorCode::CalleeReverted]: Output buffer is returned. - /// - [CalleeTrapped][`crate::ReturnErrorCode::CalleeTrapped] - /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] - /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] - fn instantiate( - code_hash: &[u8; 32], - ref_time_limit: u64, - proof_size_limit: u64, - deposit: Option<&[u8; 32]>, - value: &[u8; 32], - input: &[u8], - address: Option<&mut [u8; 20]>, - output: Option<&mut &mut [u8]>, - salt: Option<&[u8; 32]>, - ) -> Result; + /// - `output`: The output buffer to write the hash result to. + #[unstable_hostfn] + fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]); /// Checks whether a specified address belongs to a contract. /// @@ -481,13 +620,27 @@ pub trait HostFn: private::Sealed { /// # Return /// /// Returns `true` if the address belongs to a contract. + #[unstable_hostfn] fn is_contract(address: &[u8; 20]) -> bool; + /// Lock a new delegate dependency to the contract. + /// + /// Traps if the maximum number of delegate_dependencies is reached or if + /// the delegate dependency already exists. + /// + /// # Parameters + /// + /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps + /// otherwise. + #[unstable_hostfn] + fn lock_delegate_dependency(code_hash: &[u8; 32]); + /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. /// /// # Parameters /// /// - `output`: A reference to the output data buffer to write the minimum balance. + #[unstable_hostfn] fn minimum_balance(output: &mut [u8; 32]); /// Retrieve the code hash of the currently executing contract. @@ -495,43 +648,9 @@ pub trait HostFn: private::Sealed { /// # Parameters /// /// - `output`: A reference to the output data buffer to write the code hash. + #[unstable_hostfn] fn own_code_hash(output: &mut [u8; 32]); - /// Load the latest block timestamp into the supplied buffer - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the timestamp. - fn now(output: &mut [u8; 32]); - - /// Removes the delegate dependency from the contract. - /// - /// Traps if the delegate dependency does not exist. - /// - /// # Parameters - /// - /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps - /// otherwise. - fn unlock_delegate_dependency(code_hash: &[u8; 32]); - - /// Cease contract execution and save a data buffer as a result of the execution. - /// - /// This function never returns as it stops execution of the caller. - /// This is the only way to return a data buffer to the caller. Returning from - /// execution without calling this function is equivalent to calling: - /// ```nocompile - /// return_value(ReturnFlags::empty(), &[]) - /// ``` - /// - /// Using an unnamed non empty `ReturnFlags` triggers a trap. - /// - /// # Parameters - /// - /// - `flags`: Flag used to signal special return conditions to the supervisor. See - /// [`ReturnFlags`] for a documentation of the supported flags. - /// - `return_value`: The return value buffer. - fn return_value(flags: ReturnFlags, return_value: &[u8]) -> !; - /// Replace the contract code at the specified address with new code. /// /// # Note @@ -557,25 +676,11 @@ pub trait HostFn: private::Sealed { /// - `code_hash`: The hash of the new code. Should be decodable as an `T::Hash`. Traps /// otherwise. /// - /// # Errors - /// - /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] - fn set_code_hash(code_hash: &[u8; 32]) -> Result; - - /// Set the value at the given key in the contract storage. - /// - /// The key and value lengths must not exceed the maximums defined by the contracts module - /// parameters. - /// - /// # Parameters - /// - /// - `key`: The storage key. - /// - `encoded_value`: The storage value. - /// - /// # Return + /// # Panics /// - /// Returns the size of the pre-existing value at the specified key if any. - fn set_storage(flags: StorageFlags, key: &[u8], value: &[u8]) -> Option; + /// Panics if there is no code on-chain with the specified hash. + #[unstable_hostfn] + fn set_code_hash(code_hash: &[u8; 32]); /// Verify a sr25519 signature /// @@ -587,6 +692,7 @@ pub trait HostFn: private::Sealed { /// # Errors /// /// - [Sr25519VerifyFailed][`crate::ReturnErrorCode::Sr25519VerifyFailed] + #[unstable_hostfn] fn sr25519_verify(signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> Result; /// Retrieve and remove the value under the given key from storage. @@ -598,20 +704,9 @@ pub trait HostFn: private::Sealed { /// # Errors /// /// [KeyNotFound][`crate::ReturnErrorCode::KeyNotFound] + #[unstable_hostfn] fn take_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result; - /// Transfer some amount of funds into the specified account. - /// - /// # Parameters - /// - /// - `address`: The address of the account to transfer funds to. - /// - `value`: The U256 value to transfer. - /// - /// # Errors - /// - /// - [TransferFailed][`crate::ReturnErrorCode::TransferFailed] - fn transfer(address: &[u8; 20], value: &[u8; 32]) -> Result; - /// Remove the calling account and transfer remaining **free** balance. /// /// This function never returns. Either the termination was successful and the @@ -627,23 +722,30 @@ pub trait HostFn: private::Sealed { /// - The contract is live i.e is already on the call stack. /// - Failed to send the balance to the beneficiary. /// - The deletion queue is full. + #[unstable_hostfn] fn terminate(beneficiary: &[u8; 20]) -> !; - /// Stores the value transferred along with this call/instantiate into the supplied buffer. + /// Removes the delegate dependency from the contract. + /// + /// Traps if the delegate dependency does not exist. /// /// # Parameters /// - /// - `output`: A reference to the output data buffer to write the transferred value. - fn value_transferred(output: &mut [u8; 32]); + /// - `code_hash`: The code hash of the dependency. Should be decodable as an `T::Hash`. Traps + /// otherwise. + #[unstable_hostfn] + fn unlock_delegate_dependency(code_hash: &[u8; 32]); - /// Stores the price for the specified amount of gas into the supplied buffer. + /// Stores the amount of weight left into the supplied buffer. + /// The data is encoded as Weight. + /// + /// If the available space in `output` is less than the size of the value a trap is triggered. /// /// # Parameters /// - /// - `ref_time_limit`: The *ref_time* Weight limit to query the price for. - /// - `proof_size_limit`: The *proof_size* Weight limit to query the price for. - /// - `output`: A reference to the output data buffer to write the price. - fn weight_to_fee(ref_time_limit: u64, proof_size_limit: u64, output: &mut [u8; 32]); + /// - `output`: A reference to the output data buffer to write the weight left. + #[unstable_hostfn] + fn weight_left(output: &mut &mut [u8]); /// Execute an XCM program locally, using the contract's address as the origin. /// This is equivalent to dispatching `pallet_xcm::execute` through call_runtime, except that @@ -659,6 +761,7 @@ pub trait HostFn: private::Sealed { /// /// Returns `Error::Success` when the XCM execution attempt is successful. When the XCM /// execution fails, `ReturnCode::XcmExecutionFailed` is returned + #[unstable_hostfn] fn xcm_execute(msg: &[u8]) -> Result; /// Send an XCM program from the contract to the specified destination. @@ -676,21 +779,8 @@ pub trait HostFn: private::Sealed { /// /// Returns `ReturnCode::Success` when the message was successfully sent. When the XCM /// execution fails, `ReturnErrorCode::XcmSendFailed` is returned. + #[unstable_hostfn] 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/riscv64.rs similarity index 72% rename from substrate/frame/revive/uapi/src/host/riscv32.rs rename to substrate/frame/revive/uapi/src/host/riscv64.rs index fc55bfbde186..6fdda86892d5 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv64.rs @@ -18,6 +18,7 @@ use crate::{ host::{CallFlags, HostFn, HostFnImpl, Result, StorageFlags}, ReturnFlags, }; +use pallet_revive_proc_macro::unstable_hostfn; mod sys { use crate::ReturnCode; @@ -26,10 +27,10 @@ mod sys { mod abi {} impl abi::FromHost for ReturnCode { - type Regs = (u32,); + type Regs = (u64,); fn from_host((a0,): Self::Regs) -> Self { - ReturnCode(a0) + ReturnCode(a0 as _) } } @@ -58,31 +59,25 @@ mod sys { out_ptr: *mut u8, out_len_ptr: *mut u32, ) -> ReturnCode; - pub fn transfer(address_ptr: *const u8, value_ptr: *const u8) -> ReturnCode; pub fn call(ptr: *const u8) -> ReturnCode; - pub fn delegate_call( - flags: u32, - code_hash_ptr: *const u8, - input_data_ptr: *const u8, - input_data_len: u32, - out_ptr: *mut u8, - out_len_ptr: *mut u32, - ) -> ReturnCode; + pub fn delegate_call(ptr: *const u8) -> ReturnCode; pub fn instantiate(ptr: *const u8) -> ReturnCode; pub fn terminate(beneficiary_ptr: *const u8); - pub fn input(out_ptr: *mut u8, out_len_ptr: *mut u32); + pub fn call_data_copy(out_ptr: *mut u8, out_len: u32, offset: u32); + pub fn call_data_load(out_ptr: *mut u8, offset: u32); pub fn seal_return(flags: u32, data_ptr: *const u8, data_len: u32); pub fn caller(out_ptr: *mut u8); pub fn origin(out_ptr: *mut u8); pub fn is_contract(account_ptr: *const u8) -> ReturnCode; pub fn code_hash(address_ptr: *const u8, out_ptr: *mut u8); - pub fn code_size(address_ptr: *const u8, out_ptr: *mut u8); + pub fn code_size(address_ptr: *const u8) -> u64; pub fn own_code_hash(out_ptr: *mut u8); pub fn caller_is_origin() -> ReturnCode; pub fn caller_is_root() -> ReturnCode; pub fn address(out_ptr: *mut u8); pub fn weight_to_fee(ref_time: u64, proof_size: u64, out_ptr: *mut u8); pub fn weight_left(out_ptr: *mut u8, out_len_ptr: *mut u32); + pub fn ref_time_left() -> u64; pub fn get_immutable_data(out_ptr: *mut u8, out_len_ptr: *mut u32); pub fn set_immutable_data(ptr: *const u8, len: u32); pub fn balance(out_ptr: *mut u8); @@ -90,6 +85,7 @@ mod sys { pub fn chain_id(out_ptr: *mut u8); pub fn value_transferred(out_ptr: *mut u8); pub fn now(out_ptr: *mut u8); + pub fn gas_limit() -> u64; pub fn minimum_balance(out_ptr: *mut u8); pub fn deposit_event( topics_ptr: *const [u8; 32], @@ -97,6 +93,9 @@ mod sys { data_ptr: *const u8, data_len: u32, ); + pub fn gas_price() -> u64; + pub fn base_fee(out_ptr: *mut u8); + pub fn call_data_size() -> u64; pub fn block_number(out_ptr: *mut u8); pub fn block_hash(block_number_ptr: *const u8, out_ptr: *mut u8); pub fn hash_sha2_256(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8); @@ -123,7 +122,7 @@ mod sys { message_len: u32, message_ptr: *const u8, ) -> ReturnCode; - pub fn set_code_hash(code_hash_ptr: *const u8) -> ReturnCode; + pub fn set_code_hash(code_hash_ptr: *const u8); pub fn ecdsa_to_eth_address(key_ptr: *const u8, out_ptr: *mut u8) -> ReturnCode; pub fn instantiation_nonce() -> u64; pub fn lock_delegate_dependency(code_hash_ptr: *const u8); @@ -136,43 +135,11 @@ mod sys { msg_len: u32, out_ptr: *mut u8, ) -> ReturnCode; - pub fn return_data_size(out_ptr: *mut u8); + pub fn return_data_size() -> u64; pub fn return_data_copy(out_ptr: *mut u8, out_len_ptr: *mut u32, offset: u32); } } -/// A macro to implement all Host functions with a signature of `fn(&mut [u8; n])`. -macro_rules! impl_wrapper_for { - (@impl_fn $name:ident, $n: literal) => { - fn $name(output: &mut [u8; $n]) { - unsafe { sys::$name(output.as_mut_ptr()) } - } - }; - - () => {}; - - ([u8; $n: literal] => $($name:ident),*; $($tail:tt)*) => { - $(impl_wrapper_for!(@impl_fn $name, $n);)* - impl_wrapper_for!($($tail)*); - }; -} - -macro_rules! impl_hash_fn { - ( $name:ident, $bytes_result:literal ) => { - paste::item! { - fn [](input: &[u8], output: &mut [u8; $bytes_result]) { - unsafe { - sys::[]( - input.as_ptr(), - input.len() as u32, - output.as_mut_ptr(), - ) - } - } - } - }; -} - #[inline(always)] fn extract_from_slice(output: &mut &mut [u8], new_len: usize) { debug_assert!(new_len <= output.len()); @@ -215,33 +182,33 @@ impl HostFn for HostFnImpl { let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit); let salt_ptr = ptr_or_sentinel(&salt); - #[repr(packed)] + #[repr(C)] #[allow(dead_code)] struct Args { - code_hash: *const u8, + code_hash: u32, ref_time_limit: u64, proof_size_limit: u64, - deposit_limit: *const u8, - value: *const u8, - input: *const u8, + deposit_limit: u32, + value: u32, + input: u32, input_len: u32, - address: *const u8, - output: *mut u8, - output_len: *mut u32, - salt: *const u8, + address: u32, + output: u32, + output_len: u32, + salt: u32, } let args = Args { - code_hash: code_hash.as_ptr(), + code_hash: code_hash.as_ptr() as _, ref_time_limit, proof_size_limit, - deposit_limit: deposit_limit_ptr, - value: value.as_ptr(), - input: input.as_ptr(), + deposit_limit: deposit_limit_ptr as _, + value: value.as_ptr() as _, + input: input.as_ptr() as _, input_len: input.len() as _, - address, - output: output_ptr, - output_len: &mut output_len as *mut _, - salt: salt_ptr, + address: address as _, + output: output_ptr as _, + output_len: &mut output_len as *mut _ as _, + salt: salt_ptr as _, }; let ret_code = { unsafe { sys::instantiate(&args as *const Args as *const _) } }; @@ -265,31 +232,31 @@ impl HostFn for HostFnImpl { ) -> Result { let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit); - #[repr(packed)] + #[repr(C)] #[allow(dead_code)] struct Args { flags: u32, - callee: *const u8, + callee: u32, ref_time_limit: u64, proof_size_limit: u64, - deposit_limit: *const u8, - value: *const u8, - input: *const u8, + deposit_limit: u32, + value: u32, + input: u32, input_len: u32, - output: *mut u8, - output_len: *mut u32, + output: u32, + output_len: u32, } let args = Args { flags: flags.bits(), - callee: callee.as_ptr(), + callee: callee.as_ptr() as _, ref_time_limit, proof_size_limit, - deposit_limit: deposit_limit_ptr, - value: value.as_ptr(), - input: input.as_ptr(), + deposit_limit: deposit_limit_ptr as _, + value: value.as_ptr() as _, + input: input.as_ptr() as _, input_len: input.len() as _, - output: output_ptr, - output_len: &mut output_len as *mut _, + output: output_ptr as _, + output_len: &mut output_len as *mut _ as _, }; let ret_code = { unsafe { sys::call(&args as *const Args as *const _) } }; @@ -301,30 +268,44 @@ impl HostFn for HostFnImpl { ret_code.into() } - fn caller_is_root() -> u32 { - unsafe { sys::caller_is_root() }.into_u32() - } - fn delegate_call( flags: CallFlags, - code_hash: &[u8; 32], + address: &[u8; 20], + ref_time_limit: u64, + proof_size_limit: u64, + deposit_limit: Option<&[u8; 32]>, input: &[u8], mut output: Option<&mut &mut [u8]>, ) -> Result { let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); - let ret_code = { - unsafe { - sys::delegate_call( - flags.bits(), - code_hash.as_ptr(), - input.as_ptr(), - input.len() as u32, - output_ptr, - &mut output_len, - ) - } + let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit); + #[repr(C)] + #[allow(dead_code)] + struct Args { + flags: u32, + address: u32, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_limit: u32, + input: u32, + input_len: u32, + output: u32, + output_len: u32, + } + let args = Args { + flags: flags.bits(), + address: address.as_ptr() as _, + ref_time_limit, + proof_size_limit, + deposit_limit: deposit_limit_ptr as _, + input: input.as_ptr() as _, + input_len: input.len() as _, + output: output_ptr as _, + output_len: &mut output_len as *mut _ as _, }; + let ret_code = { unsafe { sys::delegate_call(&args as *const Args as *const _) } }; + if let Some(ref mut output) = output { extract_from_slice(output, output_len as usize); } @@ -332,11 +313,6 @@ impl HostFn for HostFnImpl { ret_code.into() } - fn transfer(address: &[u8; 20], value: &[u8; 32]) -> Result { - let ret_code = unsafe { sys::transfer(address.as_ptr(), value.as_ptr()) }; - ret_code.into() - } - fn deposit_event(topics: &[[u8; 32]], data: &[u8]) { unsafe { sys::deposit_event( @@ -361,17 +337,6 @@ impl HostFn for HostFnImpl { ret_code.into() } - fn clear_storage(flags: StorageFlags, key: &[u8]) -> Option { - let ret_code = unsafe { sys::clear_storage(flags.bits(), key.as_ptr(), key.len() as u32) }; - ret_code.into() - } - - fn contains_storage(flags: StorageFlags, key: &[u8]) -> Option { - let ret_code = - unsafe { sys::contains_storage(flags.bits(), key.as_ptr(), key.len() as u32) }; - ret_code.into() - } - fn get_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result { let mut output_len = output.len() as u32; let ret_code = { @@ -389,33 +354,115 @@ impl HostFn for HostFnImpl { ret_code.into() } - fn take_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result { + fn call_data_load(out_ptr: &mut [u8; 32], offset: u32) { + unsafe { sys::call_data_load(out_ptr.as_mut_ptr(), offset) }; + } + + fn gas_limit() -> u64 { + unsafe { sys::gas_limit() } + } + + fn call_data_size() -> u64 { + unsafe { sys::call_data_size() } + } + + fn return_value(flags: ReturnFlags, return_value: &[u8]) -> ! { + unsafe { sys::seal_return(flags.bits(), return_value.as_ptr(), return_value.len() as u32) } + panic!("seal_return does not return"); + } + + fn gas_price() -> u64 { + unsafe { sys::gas_price() } + } + + fn base_fee(output: &mut [u8; 32]) { + unsafe { sys::base_fee(output.as_mut_ptr()) } + } + + fn balance(output: &mut [u8; 32]) { + unsafe { sys::balance(output.as_mut_ptr()) } + } + + fn value_transferred(output: &mut [u8; 32]) { + unsafe { sys::value_transferred(output.as_mut_ptr()) } + } + + fn now(output: &mut [u8; 32]) { + unsafe { sys::now(output.as_mut_ptr()) } + } + + fn chain_id(output: &mut [u8; 32]) { + unsafe { sys::chain_id(output.as_mut_ptr()) } + } + + fn address(output: &mut [u8; 20]) { + unsafe { sys::address(output.as_mut_ptr()) } + } + + fn caller(output: &mut [u8; 20]) { + unsafe { sys::caller(output.as_mut_ptr()) } + } + + fn origin(output: &mut [u8; 20]) { + unsafe { sys::origin(output.as_mut_ptr()) } + } + + fn block_number(output: &mut [u8; 32]) { + unsafe { sys::block_number(output.as_mut_ptr()) } + } + + fn weight_to_fee(ref_time_limit: u64, proof_size_limit: u64, output: &mut [u8; 32]) { + unsafe { sys::weight_to_fee(ref_time_limit, proof_size_limit, output.as_mut_ptr()) }; + } + + fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) { + unsafe { sys::hash_keccak_256(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) } + } + + fn get_immutable_data(output: &mut &mut [u8]) { let mut output_len = output.len() as u32; - let ret_code = { - unsafe { - sys::take_storage( - flags.bits(), - key.as_ptr(), - key.len() as u32, - output.as_mut_ptr(), - &mut output_len, - ) - } - }; + unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) }; extract_from_slice(output, output_len as usize); - ret_code.into() } - fn debug_message(str: &[u8]) -> Result { - let ret_code = unsafe { sys::debug_message(str.as_ptr(), str.len() as u32) }; - ret_code.into() + fn set_immutable_data(data: &[u8]) { + unsafe { sys::set_immutable_data(data.as_ptr(), data.len() as u32) } } - fn terminate(beneficiary: &[u8; 20]) -> ! { - unsafe { sys::terminate(beneficiary.as_ptr()) } - panic!("terminate does not return"); + fn balance_of(address: &[u8; 20], output: &mut [u8; 32]) { + unsafe { sys::balance_of(address.as_ptr(), output.as_mut_ptr()) }; + } + + fn code_hash(address: &[u8; 20], output: &mut [u8; 32]) { + unsafe { sys::code_hash(address.as_ptr(), output.as_mut_ptr()) } + } + + fn code_size(address: &[u8; 20]) -> u64 { + unsafe { sys::code_size(address.as_ptr()) } + } + + fn return_data_size() -> u64 { + unsafe { sys::return_data_size() } + } + + 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); + } + + fn ref_time_left() -> u64 { + unsafe { sys::ref_time_left() } } + #[unstable_hostfn] + fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) { + unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) }; + } + + #[unstable_hostfn] fn call_chain_extension(func_id: u32, input: &[u8], mut output: Option<&mut &mut [u8]>) -> u32 { let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); let ret_code = { @@ -436,44 +483,48 @@ impl HostFn for HostFnImpl { ret_code.into_u32() } - fn input(output: &mut &mut [u8]) { - let mut output_len = output.len() as u32; - { - unsafe { sys::input(output.as_mut_ptr(), &mut output_len) }; - } - extract_from_slice(output, output_len as usize); - } - - fn return_value(flags: ReturnFlags, return_value: &[u8]) -> ! { - unsafe { sys::seal_return(flags.bits(), return_value.as_ptr(), return_value.len() as u32) } - panic!("seal_return does not return"); + fn call_data_copy(output: &mut [u8], offset: u32) { + let len = output.len() as u32; + unsafe { sys::call_data_copy(output.as_mut_ptr(), len, offset) }; } + #[unstable_hostfn] fn call_runtime(call: &[u8]) -> Result { let ret_code = unsafe { sys::call_runtime(call.as_ptr(), call.len() as u32) }; ret_code.into() } - impl_wrapper_for! { - [u8; 32] => block_number, balance, value_transferred, now, minimum_balance, chain_id; - [u8; 20] => address, caller, origin; + #[unstable_hostfn] + fn caller_is_origin() -> bool { + let ret_val = unsafe { sys::caller_is_origin() }; + ret_val.into_bool() } - fn weight_left(output: &mut &mut [u8]) { - let mut output_len = output.len() as u32; - unsafe { sys::weight_left(output.as_mut_ptr(), &mut output_len) } - extract_from_slice(output, output_len as usize) + #[unstable_hostfn] + fn caller_is_root() -> u32 { + unsafe { sys::caller_is_root() }.into_u32() } - fn weight_to_fee(ref_time_limit: u64, proof_size_limit: u64, output: &mut [u8; 32]) { - unsafe { sys::weight_to_fee(ref_time_limit, proof_size_limit, output.as_mut_ptr()) }; + #[unstable_hostfn] + fn clear_storage(flags: StorageFlags, key: &[u8]) -> Option { + let ret_code = unsafe { sys::clear_storage(flags.bits(), key.as_ptr(), key.len() as u32) }; + ret_code.into() + } + + #[unstable_hostfn] + fn contains_storage(flags: StorageFlags, key: &[u8]) -> Option { + let ret_code = + unsafe { sys::contains_storage(flags.bits(), key.as_ptr(), key.len() as u32) }; + ret_code.into() } - impl_hash_fn!(sha2_256, 32); - impl_hash_fn!(keccak_256, 32); - impl_hash_fn!(blake2_256, 32); - impl_hash_fn!(blake2_128, 16); + #[unstable_hostfn] + fn debug_message(str: &[u8]) -> Result { + let ret_code = unsafe { sys::debug_message(str.as_ptr(), str.len() as u32) }; + ret_code.into() + } + #[unstable_hostfn] fn ecdsa_recover( signature: &[u8; 65], message_hash: &[u8; 32], @@ -485,77 +536,109 @@ impl HostFn for HostFnImpl { ret_code.into() } + #[unstable_hostfn] fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result { let ret_code = unsafe { sys::ecdsa_to_eth_address(pubkey.as_ptr(), output.as_mut_ptr()) }; ret_code.into() } - fn sr25519_verify(signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> Result { - let ret_code = unsafe { - sys::sr25519_verify( - signature.as_ptr(), - pub_key.as_ptr(), - message.len() as u32, - message.as_ptr(), - ) - }; - ret_code.into() + #[unstable_hostfn] + fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) { + unsafe { sys::hash_sha2_256(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) } } - fn is_contract(address: &[u8; 20]) -> bool { - let ret_val = unsafe { sys::is_contract(address.as_ptr()) }; - ret_val.into_bool() + #[unstable_hostfn] + fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) { + unsafe { sys::hash_blake2_256(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) } } - fn get_immutable_data(output: &mut &mut [u8]) { - let mut output_len = output.len() as u32; - unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) }; - extract_from_slice(output, output_len as usize); + #[unstable_hostfn] + fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) { + unsafe { sys::hash_blake2_128(input.as_ptr(), input.len() as u32, output.as_mut_ptr()) } } - fn set_immutable_data(data: &[u8]) { - unsafe { sys::set_immutable_data(data.as_ptr(), data.len() as u32) } + #[unstable_hostfn] + fn is_contract(address: &[u8; 20]) -> bool { + let ret_val = unsafe { sys::is_contract(address.as_ptr()) }; + ret_val.into_bool() } - fn balance_of(address: &[u8; 20], output: &mut [u8; 32]) { - unsafe { sys::balance_of(address.as_ptr(), output.as_mut_ptr()) }; + #[unstable_hostfn] + fn lock_delegate_dependency(code_hash: &[u8; 32]) { + unsafe { sys::lock_delegate_dependency(code_hash.as_ptr()) } } - fn caller_is_origin() -> bool { - let ret_val = unsafe { sys::caller_is_origin() }; - ret_val.into_bool() + #[unstable_hostfn] + fn minimum_balance(output: &mut [u8; 32]) { + unsafe { sys::minimum_balance(output.as_mut_ptr()) } } - fn set_code_hash(code_hash: &[u8; 32]) -> Result { - let ret_val = unsafe { sys::set_code_hash(code_hash.as_ptr()) }; - ret_val.into() + #[unstable_hostfn] + fn own_code_hash(output: &mut [u8; 32]) { + unsafe { sys::own_code_hash(output.as_mut_ptr()) } } - fn code_hash(address: &[u8; 20], output: &mut [u8; 32]) { - unsafe { sys::code_hash(address.as_ptr(), output.as_mut_ptr()) } + #[unstable_hostfn] + fn set_code_hash(code_hash: &[u8; 32]) { + unsafe { sys::set_code_hash(code_hash.as_ptr()) } } - fn code_size(address: &[u8; 20], output: &mut [u8; 32]) { - unsafe { sys::code_size(address.as_ptr(), output.as_mut_ptr()) } + #[unstable_hostfn] + fn sr25519_verify(signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> Result { + let ret_code = unsafe { + sys::sr25519_verify( + signature.as_ptr(), + pub_key.as_ptr(), + message.len() as u32, + message.as_ptr(), + ) + }; + ret_code.into() } - fn own_code_hash(output: &mut [u8; 32]) { - unsafe { sys::own_code_hash(output.as_mut_ptr()) } + #[unstable_hostfn] + fn take_storage(flags: StorageFlags, key: &[u8], output: &mut &mut [u8]) -> Result { + let mut output_len = output.len() as u32; + let ret_code = { + unsafe { + sys::take_storage( + flags.bits(), + key.as_ptr(), + key.len() as u32, + output.as_mut_ptr(), + &mut output_len, + ) + } + }; + extract_from_slice(output, output_len as usize); + ret_code.into() } - fn lock_delegate_dependency(code_hash: &[u8; 32]) { - unsafe { sys::lock_delegate_dependency(code_hash.as_ptr()) } + #[unstable_hostfn] + fn terminate(beneficiary: &[u8; 20]) -> ! { + unsafe { sys::terminate(beneficiary.as_ptr()) } + panic!("terminate does not return"); } + #[unstable_hostfn] fn unlock_delegate_dependency(code_hash: &[u8; 32]) { unsafe { sys::unlock_delegate_dependency(code_hash.as_ptr()) } } + #[unstable_hostfn] + fn weight_left(output: &mut &mut [u8]) { + let mut output_len = output.len() as u32; + unsafe { sys::weight_left(output.as_mut_ptr(), &mut output_len) } + extract_from_slice(output, output_len as usize) + } + + #[unstable_hostfn] fn xcm_execute(msg: &[u8]) -> Result { let ret_code = unsafe { sys::xcm_execute(msg.as_ptr(), msg.len() as _) }; ret_code.into() } + #[unstable_hostfn] fn xcm_send(dest: &[u8], msg: &[u8], output: &mut [u8; 32]) -> Result { let ret_code = unsafe { sys::xcm_send( @@ -568,20 +651,4 @@ 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); - } - - fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) { - unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) }; - } } diff --git a/substrate/frame/revive/uapi/src/lib.rs b/substrate/frame/revive/uapi/src/lib.rs index e660ce36ef75..ef1798b4bf61 100644 --- a/substrate/frame/revive/uapi/src/lib.rs +++ b/substrate/frame/revive/uapi/src/lib.rs @@ -17,6 +17,7 @@ //! Refer to substrate FRAME contract module for more documentation. #![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] mod flags; pub use flags::*; @@ -65,6 +66,12 @@ impl From for u32 { } } +impl From for u64 { + fn from(error: ReturnErrorCode) -> Self { + u32::from(error).into() + } +} + define_error_codes! { /// The called function trapped and has its state changes reverted. /// In this case no output buffer is returned. @@ -79,23 +86,21 @@ define_error_codes! { /// Transfer failed for other not further specified reason. Most probably /// reserved or locked balance of the sender that was preventing the transfer. TransferFailed = 4, - /// No code could be found at the supplied code hash. - CodeNotFound = 5, - /// The account that was called is no contract. - NotCallable = 6, /// The call to `debug_message` had no effect because debug message /// recording was disabled. - LoggingDisabled = 7, + LoggingDisabled = 5, /// The call dispatched by `call_runtime` was executed but returned an error. - CallRuntimeFailed = 8, + CallRuntimeFailed = 6, /// ECDSA public key recovery failed. Most probably wrong recovery id or signature. - EcdsaRecoveryFailed = 9, + EcdsaRecoveryFailed = 7, /// sr25519 signature verification failed. - Sr25519VerifyFailed = 10, + Sr25519VerifyFailed = 8, /// The `xcm_execute` call failed. - XcmExecutionFailed = 11, + XcmExecutionFailed = 9, /// The `xcm_send` call failed. - XcmSendFailed = 12, + XcmSendFailed = 10, + /// The subcall ran out of weight or storage deposit. + OutOfResources = 11, } /// The raw return code returned by the host side. diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index f80fed11b971..dedde9956b6f 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -29,8 +29,8 @@ sp-staking = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true } diff --git a/substrate/frame/root-offences/src/lib.rs b/substrate/frame/root-offences/src/lib.rs index 6531080b8d10..fd6ffc55e40c 100644 --- a/substrate/frame/root-offences/src/lib.rs +++ b/substrate/frame/root-offences/src/lib.rs @@ -106,7 +106,7 @@ pub mod pallet { fn get_offence_details( offenders: Vec<(T::AccountId, Perbill)>, ) -> Result>, DispatchError> { - let now = Staking::::active_era() + let now = pallet_staking::ActiveEra::::get() .map(|e| e.index) .ok_or(Error::::FailedToGetActiveEra)?; diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index af073d7672cf..a27fb36f64a6 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -296,5 +296,5 @@ pub(crate) fn run_to_block(n: BlockNumber) { } pub(crate) fn active_era() -> EraIndex { - Staking::active_era().unwrap().index + pallet_staking::ActiveEra::::get().unwrap().index } diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index ee3ce8011009..fd0f4da2e80c 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index e7f165ae67d8..3f1f6bc1f1d6 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -20,20 +20,20 @@ docify = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +pallet-balances = { optional = true, workspace = true } +pallet-proxy = { optional = true, workspace = true } +pallet-utility = { optional = true, workspace = true } scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true } sp-runtime = { workspace = true } -pallet-balances = { optional = true, workspace = true } -pallet-utility = { optional = true, workspace = true } -pallet-proxy = { optional = true, workspace = true } [dev-dependencies] -sp-core = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } +frame-support = { features = ["experimental"], workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } pallet-proxy = { workspace = true, default-features = true } -frame-support = { features = ["experimental"], workspace = true, default-features = true } +pallet-utility = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/safe-mode/src/mock.rs b/substrate/frame/safe-mode/src/mock.rs index ec1ad8249514..aaf3456272fa 100644 --- a/substrate/frame/safe-mode/src/mock.rs +++ b/substrate/frame/safe-mode/src/mock.rs @@ -138,6 +138,7 @@ impl pallet_proxy::Config for Test { type MaxPending = ConstU32<2>; type AnnouncementDepositBase = ConstU64<1>; type AnnouncementDepositFactor = ConstU64<1>; + type BlockNumberProvider = frame_system::Pallet; } /// The calls that can always bypass safe-mode. diff --git a/substrate/frame/safe-mode/src/weights.rs b/substrate/frame/safe-mode/src/weights.rs index c2ce2cfab9b9..631853b19462 100644 --- a/substrate/frame/safe-mode/src/weights.rs +++ b/substrate/frame/safe-mode/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_safe_mode` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -72,8 +72,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 2_152_000 picoseconds. - Weight::from_parts(2_283_000, 1489) + // Minimum execution time: 2_982_000 picoseconds. + Weight::from_parts(3_104_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) @@ -82,23 +82,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 6_657_000 picoseconds. - Weight::from_parts(6_955_000, 1489) + // Minimum execution time: 7_338_000 picoseconds. + Weight::from_parts(7_813_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn enter() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `3658` - // Minimum execution time: 49_366_000 picoseconds. - Weight::from_parts(50_506_000, 3658) + // Estimated: `3820` + // Minimum execution time: 48_807_000 picoseconds. + Weight::from_parts(49_731_000, 3820) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -108,23 +108,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 7_843_000 picoseconds. - Weight::from_parts(8_205_000, 1489) + // Minimum execution time: 8_207_000 picoseconds. + Weight::from_parts(8_645_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn extend() -> Weight { // Proof Size summary in bytes: // Measured: `169` - // Estimated: `3658` - // Minimum execution time: 50_487_000 picoseconds. - Weight::from_parts(52_101_000, 3658) + // Estimated: `3820` + // Minimum execution time: 53_540_000 picoseconds. + Weight::from_parts(54_315_000, 3820) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -134,8 +134,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_517_000 picoseconds. - Weight::from_parts(8_894_000, 1489) + // Minimum execution time: 9_494_000 picoseconds. + Weight::from_parts(9_751_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -145,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_451_000 picoseconds. - Weight::from_parts(8_745_000, 1489) + // Minimum execution time: 8_970_000 picoseconds. + Weight::from_parts(9_318_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -155,39 +155,39 @@ impl WeightInfo for SubstrateWeight { /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 42_504_000 picoseconds. - Weight::from_parts(45_493_000, 3658) + // Estimated: `3820` + // Minimum execution time: 46_187_000 picoseconds. + Weight::from_parts(47_068_000, 3820) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn force_release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 40_864_000 picoseconds. - Weight::from_parts(41_626_000, 3658) + // Estimated: `3820` + // Minimum execution time: 44_809_000 picoseconds. + Weight::from_parts(45_501_000, 3820) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn force_slash_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 31_943_000 picoseconds. - Weight::from_parts(33_033_000, 3658) + // Estimated: `3820` + // Minimum execution time: 36_977_000 picoseconds. + Weight::from_parts(37_694_000, 3820) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -201,8 +201,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 2_152_000 picoseconds. - Weight::from_parts(2_283_000, 1489) + // Minimum execution time: 2_982_000 picoseconds. + Weight::from_parts(3_104_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) @@ -211,23 +211,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 6_657_000 picoseconds. - Weight::from_parts(6_955_000, 1489) + // Minimum execution time: 7_338_000 picoseconds. + Weight::from_parts(7_813_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn enter() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `3658` - // Minimum execution time: 49_366_000 picoseconds. - Weight::from_parts(50_506_000, 3658) + // Estimated: `3820` + // Minimum execution time: 48_807_000 picoseconds. + Weight::from_parts(49_731_000, 3820) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -237,23 +237,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 7_843_000 picoseconds. - Weight::from_parts(8_205_000, 1489) + // Minimum execution time: 8_207_000 picoseconds. + Weight::from_parts(8_645_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn extend() -> Weight { // Proof Size summary in bytes: // Measured: `169` - // Estimated: `3658` - // Minimum execution time: 50_487_000 picoseconds. - Weight::from_parts(52_101_000, 3658) + // Estimated: `3820` + // Minimum execution time: 53_540_000 picoseconds. + Weight::from_parts(54_315_000, 3820) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -263,8 +263,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_517_000 picoseconds. - Weight::from_parts(8_894_000, 1489) + // Minimum execution time: 9_494_000 picoseconds. + Weight::from_parts(9_751_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -274,8 +274,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_451_000 picoseconds. - Weight::from_parts(8_745_000, 1489) + // Minimum execution time: 8_970_000 picoseconds. + Weight::from_parts(9_318_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -284,39 +284,39 @@ impl WeightInfo for () { /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 42_504_000 picoseconds. - Weight::from_parts(45_493_000, 3658) + // Estimated: `3820` + // Minimum execution time: 46_187_000 picoseconds. + Weight::from_parts(47_068_000, 3820) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn force_release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 40_864_000 picoseconds. - Weight::from_parts(41_626_000, 3658) + // Estimated: `3820` + // Minimum execution time: 44_809_000 picoseconds. + Weight::from_parts(45_501_000, 3820) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn force_slash_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 31_943_000 picoseconds. - Weight::from_parts(33_033_000, 3658) + // Estimated: `3820` + // Minimum execution time: 36_977_000 picoseconds. + Weight::from_parts(37_694_000, 3820) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 9e4cf06288dd..b3ed95bf1de5 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +pallet-ranked-collective = { optional = true, workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } -pallet-ranked-collective = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/frame/salary/src/tests/integration.rs b/substrate/frame/salary/src/tests/integration.rs index 69f218943ade..0c1fb8bbdcba 100644 --- a/substrate/frame/salary/src/tests/integration.rs +++ b/substrate/frame/salary/src/tests/integration.rs @@ -17,22 +17,21 @@ //! The crate's tests. +use crate as pallet_salary; +use crate::*; use frame_support::{ assert_noop, assert_ok, derive_impl, hypothetically, pallet_prelude::Weight, parameter_types, - traits::{ConstU64, EitherOf, MapSuccess, PollStatus, Polling}, + traits::{ConstU64, EitherOf, MapSuccess, NoOpPoll}, }; -use pallet_ranked_collective::{EnsureRanked, Geometric, TallyOf, Votes}; +use pallet_ranked_collective::{EnsureRanked, Geometric}; use sp_core::{ConstU16, Get}; use sp_runtime::{ traits::{Convert, ReduceBy, ReplaceWithDefault}, - BuildStorage, DispatchError, + BuildStorage, }; -use crate as pallet_salary; -use crate::*; - type Rank = u16; type Block = frame_system::mocking::MockBlock; @@ -55,45 +54,6 @@ impl frame_system::Config for Test { type Block = Block; } -pub struct TestPolls; -impl Polling> for TestPolls { - type Index = u8; - type Votes = Votes; - type Moment = u64; - type Class = Rank; - - fn classes() -> Vec { - unimplemented!() - } - fn as_ongoing(_index: u8) -> Option<(TallyOf, Self::Class)> { - unimplemented!() - } - fn access_poll( - _index: Self::Index, - _f: impl FnOnce(PollStatus<&mut TallyOf, Self::Moment, Self::Class>) -> R, - ) -> R { - unimplemented!() - } - fn try_access_poll( - _index: Self::Index, - _f: impl FnOnce( - PollStatus<&mut TallyOf, Self::Moment, Self::Class>, - ) -> Result, - ) -> Result { - unimplemented!() - } - - #[cfg(feature = "runtime-benchmarks")] - fn create_ongoing(_class: Self::Class) -> Result { - unimplemented!() - } - - #[cfg(feature = "runtime-benchmarks")] - fn end_ongoing(_index: Self::Index, _approved: bool) -> Result<(), ()> { - unimplemented!() - } -} - pub struct MinRankOfClass(PhantomData); impl> Convert for MinRankOfClass { fn convert(a: u16) -> Rank { @@ -176,7 +136,7 @@ impl pallet_ranked_collective::Config for Test { // Members can exchange up to the rank of 2 below them. MapSuccess, ReduceBy>>, >; - type Polls = TestPolls; + type Polls = NoOpPoll; type MinRankOfClass = MinRankOfClass; type MemberSwappedHandler = Salary; type VoteWeight = Geometric; diff --git a/substrate/frame/salary/src/weights.rs b/substrate/frame/salary/src/weights.rs index d4e6331919b6..f1cdaaa225a4 100644 --- a/substrate/frame/salary/src/weights.rs +++ b/substrate/frame/salary/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_salary` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -69,8 +69,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 7_382_000 picoseconds. - Weight::from_parts(7_793_000, 1541) + // Minimum execution time: 7_583_000 picoseconds. + Weight::from_parts(8_073_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -80,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 8_744_000 picoseconds. - Weight::from_parts(9_216_000, 1541) + // Minimum execution time: 9_648_000 picoseconds. + Weight::from_parts(10_016_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -95,8 +95,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3543` - // Minimum execution time: 16_728_000 picoseconds. - Weight::from_parts(17_387_000, 3543) + // Minimum execution time: 22_534_000 picoseconds. + Weight::from_parts(23_265_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,8 +110,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 19_744_000 picoseconds. - Weight::from_parts(20_225_000, 3543) + // Minimum execution time: 25_764_000 picoseconds. + Weight::from_parts(26_531_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -125,8 +125,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 56_084_000 picoseconds. - Weight::from_parts(58_484_000, 3543) + // Minimum execution time: 62_575_000 picoseconds. + Weight::from_parts(63_945_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -140,10 +140,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `462` + // Measured: `514` // Estimated: `3593` - // Minimum execution time: 57_341_000 picoseconds. - Weight::from_parts(59_882_000, 3593) + // Minimum execution time: 64_043_000 picoseconds. + Weight::from_parts(65_938_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -155,8 +155,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3543` - // Minimum execution time: 10_788_000 picoseconds. - Weight::from_parts(11_109_000, 3543) + // Minimum execution time: 12_303_000 picoseconds. + Weight::from_parts(12_797_000, 3543) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -170,8 +170,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 7_382_000 picoseconds. - Weight::from_parts(7_793_000, 1541) + // Minimum execution time: 7_583_000 picoseconds. + Weight::from_parts(8_073_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -181,8 +181,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 8_744_000 picoseconds. - Weight::from_parts(9_216_000, 1541) + // Minimum execution time: 9_648_000 picoseconds. + Weight::from_parts(10_016_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -196,8 +196,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3543` - // Minimum execution time: 16_728_000 picoseconds. - Weight::from_parts(17_387_000, 3543) + // Minimum execution time: 22_534_000 picoseconds. + Weight::from_parts(23_265_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -211,8 +211,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 19_744_000 picoseconds. - Weight::from_parts(20_225_000, 3543) + // Minimum execution time: 25_764_000 picoseconds. + Weight::from_parts(26_531_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -226,8 +226,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 56_084_000 picoseconds. - Weight::from_parts(58_484_000, 3543) + // Minimum execution time: 62_575_000 picoseconds. + Weight::from_parts(63_945_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -241,10 +241,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout_other() -> Weight { // Proof Size summary in bytes: - // Measured: `462` + // Measured: `514` // Estimated: `3593` - // Minimum execution time: 57_341_000 picoseconds. - Weight::from_parts(59_882_000, 3593) + // Minimum execution time: 64_043_000 picoseconds. + Weight::from_parts(65_938_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -256,8 +256,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3543` - // Minimum execution time: 10_788_000 picoseconds. - Weight::from_parts(11_109_000, 3543) + // Minimum execution time: 12_303_000 picoseconds. + Weight::from_parts(12_797_000, 3543) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index 7eb2bda96ffc..dd091b6f8ed7 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-consensus-sassafras = { features = ["serde"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 1432ada91335..0506470e72c3 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -14,15 +14,15 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } +docify = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-weights = { workspace = true } -docify = { workspace = true } [dev-dependencies] pallet-preimage = { workspace = true, default-features = true } diff --git a/substrate/frame/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs index d0a14fc73d64..ff40e8ef8abf 100644 --- a/substrate/frame/scheduler/src/benchmarking.rs +++ b/substrate/frame/scheduler/src/benchmarking.rs @@ -17,25 +17,23 @@ //! Scheduler pallet benchmarking. -use super::*; use alloc::vec; -use frame_benchmarking::v1::{account, benchmarks, BenchmarkError}; +use frame_benchmarking::v2::*; use frame_support::{ ensure, traits::{schedule::Priority, BoundedInline}, weights::WeightMeter, }; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use frame_system::{EventRecord, RawOrigin}; -use crate::Pallet as Scheduler; -use frame_system::{Call as SystemCall, EventRecord}; +use crate::*; -const SEED: u32 = 0; +type SystemCall = frame_system::Call; +type SystemOrigin = ::RuntimeOrigin; +const SEED: u32 = 0; const BLOCK_NUMBER: u32 = 2; -type SystemOrigin = ::RuntimeOrigin; - fn assert_last_event(generic_event: ::RuntimeEvent) { let events = frame_system::Pallet::::events(); let system_event: ::RuntimeEvent = generic_event.into(); @@ -61,7 +59,7 @@ fn fill_schedule( let call = make_call::(None); let period = Some(((i + 100).into(), 100)); let name = u32_to_name(i); - Scheduler::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; + Pallet::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; } ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); Ok(()) @@ -134,107 +132,160 @@ fn make_origin(signed: bool) -> ::PalletsOrigin { } } -benchmarks! { +#[benchmarks] +mod benchmarks { + use super::*; + // `service_agendas` when no work is done. - service_agendas_base { - let now = BlockNumberFor::::from(BLOCK_NUMBER); + #[benchmark] + fn service_agendas_base() { + let now = BLOCK_NUMBER.into(); IncompleteSince::::put(now - One::one()); - }: { - Scheduler::::service_agendas(&mut WeightMeter::new(), now, 0); - } verify { + + #[block] + { + Pallet::::service_agendas(&mut WeightMeter::new(), now, 0); + } + assert_eq!(IncompleteSince::::get(), Some(now - One::one())); } // `service_agenda` when no work is done. - service_agenda_base { + #[benchmark] + fn service_agenda_base( + s: Linear<0, { T::MaxScheduledPerBlock::get() }>, + ) -> Result<(), BenchmarkError> { let now = BLOCK_NUMBER.into(); - let s in 0 .. T::MaxScheduledPerBlock::get(); fill_schedule::(now, s)?; let mut executed = 0; - }: { - Scheduler::::service_agenda(&mut WeightMeter::new(), &mut executed, now, now, 0); - } verify { + + #[block] + { + Pallet::::service_agenda(&mut WeightMeter::new(), &mut executed, now, now, 0); + } + assert_eq!(executed, 0); + + Ok(()) } // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not // dispatched (e.g. due to being overweight). - service_task_base { + #[benchmark] + fn service_task_base() { let now = BLOCK_NUMBER.into(); let task = make_task::(false, false, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { - //assert_eq!(result, Ok(())); + let _result; + + #[block] + { + _result = Pallet::::service_task(&mut counter, now, now, 0, true, task); + } + + // assert!(_result.is_ok()); } // `service_task` when the task is a non-periodic, non-named, fetched call (with a known // preimage length) and which is not dispatched (e.g. due to being overweight). - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { // Use measured PoV size for the Preimages since we pass in a length witness. Preimage::PreimageFor: Measured - }] - service_task_fetched { - let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32); + })] + fn service_task_fetched( + s: Linear<{ BoundedInline::bound() as u32 }, { T::Preimages::MAX_LENGTH as u32 }>, + ) { let now = BLOCK_NUMBER.into(); let task = make_task::(false, false, false, Some(s), 0); // prevent any tasks from actually being executed as we only want the surrounding weight. let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { + let _result; + + #[block] + { + _result = Pallet::::service_task(&mut counter, now, now, 0, true, task); + } + + // assert!(result.is_ok()); } // `service_task` when the task is a non-periodic, named, non-fetched call which is not // dispatched (e.g. due to being overweight). - service_task_named { + #[benchmark] + fn service_task_named() { let now = BLOCK_NUMBER.into(); let task = make_task::(false, true, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { + let _result; + + #[block] + { + _result = Pallet::::service_task(&mut counter, now, now, 0, true, task); + } + + // assert!(result.is_ok()); } // `service_task` when the task is a periodic, non-named, non-fetched call which is not // dispatched (e.g. due to being overweight). - service_task_periodic { + #[benchmark] + fn service_task_periodic() { let now = BLOCK_NUMBER.into(); let task = make_task::(true, false, false, None, 0); // prevent any tasks from actually being executed as we only want the surrounding weight. let mut counter = WeightMeter::with_limit(Weight::zero()); - }: { - let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); - } verify { + let _result; + + #[block] + { + _result = Pallet::::service_task(&mut counter, now, now, 0, true, task); + } + + // assert!(result.is_ok()); } // `execute_dispatch` when the origin is `Signed`, not counting the dispatchable's weight. - execute_dispatch_signed { + #[benchmark] + fn execute_dispatch_signed() -> Result<(), BenchmarkError> { let mut counter = WeightMeter::new(); let origin = make_origin::(true); - let call = T::Preimages::realize(&make_call::(None)).unwrap().0; - }: { - assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); - } - verify { + let call = T::Preimages::realize(&make_call::(None))?.0; + let result; + + #[block] + { + result = Pallet::::execute_dispatch(&mut counter, origin, call); + } + + assert!(result.is_ok()); + + Ok(()) } // `execute_dispatch` when the origin is not `Signed`, not counting the dispatchable's weight. - execute_dispatch_unsigned { + #[benchmark] + fn execute_dispatch_unsigned() -> Result<(), BenchmarkError> { let mut counter = WeightMeter::new(); let origin = make_origin::(false); - let call = T::Preimages::realize(&make_call::(None)).unwrap().0; - }: { - assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); - } - verify { + let call = T::Preimages::realize(&make_call::(None))?.0; + let result; + + #[block] + { + result = Pallet::::execute_dispatch(&mut counter, origin, call); + } + + assert!(result.is_ok()); + + Ok(()) } - schedule { - let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); + #[benchmark] + fn schedule( + s: Linear<0, { T::MaxScheduledPerBlock::get() - 1 }>, + ) -> Result<(), BenchmarkError> { let when = BLOCK_NUMBER.into(); let periodic = Some((BlockNumberFor::::one(), 100)); let priority = 0; @@ -242,24 +293,27 @@ benchmarks! { let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); fill_schedule::(when, s)?; - }: _(RawOrigin::Root, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); + + #[extrinsic_call] + _(RawOrigin::Root, when, periodic, priority, call); + + ensure!(Agenda::::get(when).len() == s as usize + 1, "didn't add to schedule"); + + Ok(()) } - cancel { - let s in 1 .. T::MaxScheduledPerBlock::get(); + #[benchmark] + fn cancel(s: Linear<1, { T::MaxScheduledPerBlock::get() }>) -> Result<(), BenchmarkError> { let when = BLOCK_NUMBER.into(); fill_schedule::(when, s)?; assert_eq!(Agenda::::get(when).len(), s as usize); let schedule_origin = T::ScheduleOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - }: _>(schedule_origin, when, 0) - verify { + + #[extrinsic_call] + _(schedule_origin as SystemOrigin, when, 0); + ensure!( s == 1 || Lookup::::get(u32_to_name(0)).is_none(), "didn't remove from lookup if more than 1 task scheduled for `when`" @@ -273,10 +327,14 @@ benchmarks! { s > 1 || Agenda::::get(when).len() == 0, "remove from schedule if only 1 task scheduled for `when`" ); + + Ok(()) } - schedule_named { - let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); + #[benchmark] + fn schedule_named( + s: Linear<0, { T::MaxScheduledPerBlock::get() - 1 }>, + ) -> Result<(), BenchmarkError> { let id = u32_to_name(s); let when = BLOCK_NUMBER.into(); let periodic = Some((BlockNumberFor::::one(), 100)); @@ -285,21 +343,26 @@ benchmarks! { let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); fill_schedule::(when, s)?; - }: _(RawOrigin::Root, id, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); + + #[extrinsic_call] + _(RawOrigin::Root, id, when, periodic, priority, call); + + ensure!(Agenda::::get(when).len() == s as usize + 1, "didn't add to schedule"); + + Ok(()) } - cancel_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); + #[benchmark] + fn cancel_named( + s: Linear<1, { T::MaxScheduledPerBlock::get() }>, + ) -> Result<(), BenchmarkError> { let when = BLOCK_NUMBER.into(); fill_schedule::(when, s)?; - }: _(RawOrigin::Root, u32_to_name(0)) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, u32_to_name(0)); + ensure!( s == 1 || Lookup::::get(u32_to_name(0)).is_none(), "didn't remove from lookup if more than 1 task scheduled for `when`" @@ -313,33 +376,49 @@ benchmarks! { s > 1 || Agenda::::get(when).len() == 0, "remove from schedule if only 1 task scheduled for `when`" ); + + Ok(()) } - schedule_retry { - let s in 1 .. T::MaxScheduledPerBlock::get(); + #[benchmark] + fn schedule_retry( + s: Linear<1, { T::MaxScheduledPerBlock::get() }>, + ) -> Result<(), BenchmarkError> { let when = BLOCK_NUMBER.into(); fill_schedule::(when, s)?; let name = u32_to_name(s - 1); let address = Lookup::::get(name).unwrap(); - let period: BlockNumberFor = 1u32.into(); - let root: ::PalletsOrigin = frame_system::RawOrigin::Root.into(); + let period: BlockNumberFor = 1_u32.into(); let retry_config = RetryConfig { total_retries: 10, remaining: 10, period }; Retries::::insert(address, retry_config); let (mut when, index) = address; let task = Agenda::::get(when)[index as usize].clone().unwrap(); let mut weight_counter = WeightMeter::with_limit(T::MaximumWeight::get()); - }: { - Scheduler::::schedule_retry(&mut weight_counter, when, when, index, &task, retry_config); - } verify { + + #[block] + { + Pallet::::schedule_retry( + &mut weight_counter, + when, + when, + index, + &task, + retry_config, + ); + } + when = when + BlockNumberFor::::one(); assert_eq!( Retries::::get((when, 0)), Some(RetryConfig { total_retries: 10, remaining: 9, period }) ); + + Ok(()) } - set_retry { + #[benchmark] + fn set_retry() -> Result<(), BenchmarkError> { let s = T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); @@ -348,8 +427,10 @@ benchmarks! { let address = Lookup::::get(name).unwrap(); let (when, index) = address; let period = BlockNumberFor::::one(); - }: _(RawOrigin::Root, (when, index), 10, period) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, (when, index), 10, period); + assert_eq!( Retries::::get((when, index)), Some(RetryConfig { total_retries: 10, remaining: 10, period }) @@ -357,9 +438,12 @@ benchmarks! { assert_last_event::( Event::RetrySet { task: address, id: None, period, retries: 10 }.into(), ); + + Ok(()) } - set_retry_named { + #[benchmark] + fn set_retry_named() -> Result<(), BenchmarkError> { let s = T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); @@ -368,8 +452,10 @@ benchmarks! { let address = Lookup::::get(name).unwrap(); let (when, index) = address; let period = BlockNumberFor::::one(); - }: _(RawOrigin::Root, name, 10, period) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, name, 10, period); + assert_eq!( Retries::::get((when, index)), Some(RetryConfig { total_retries: 10, remaining: 10, period }) @@ -377,9 +463,12 @@ benchmarks! { assert_last_event::( Event::RetrySet { task: address, id: Some(name), period, retries: 10 }.into(), ); + + Ok(()) } - cancel_retry { + #[benchmark] + fn cancel_retry() -> Result<(), BenchmarkError> { let s = T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); @@ -388,16 +477,19 @@ benchmarks! { let address = Lookup::::get(name).unwrap(); let (when, index) = address; let period = BlockNumberFor::::one(); - assert!(Scheduler::::set_retry(RawOrigin::Root.into(), (when, index), 10, period).is_ok()); - }: _(RawOrigin::Root, (when, index)) - verify { + assert!(Pallet::::set_retry(RawOrigin::Root.into(), (when, index), 10, period).is_ok()); + + #[extrinsic_call] + _(RawOrigin::Root, (when, index)); + assert!(!Retries::::contains_key((when, index))); - assert_last_event::( - Event::RetryCancelled { task: address, id: None }.into(), - ); + assert_last_event::(Event::RetryCancelled { task: address, id: None }.into()); + + Ok(()) } - cancel_retry_named { + #[benchmark] + fn cancel_retry_named() -> Result<(), BenchmarkError> { let s = T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); @@ -406,14 +498,20 @@ benchmarks! { let address = Lookup::::get(name).unwrap(); let (when, index) = address; let period = BlockNumberFor::::one(); - assert!(Scheduler::::set_retry_named(RawOrigin::Root.into(), name, 10, period).is_ok()); - }: _(RawOrigin::Root, name) - verify { + assert!(Pallet::::set_retry_named(RawOrigin::Root.into(), name, 10, period).is_ok()); + + #[extrinsic_call] + _(RawOrigin::Root, name); + assert!(!Retries::::contains_key((when, index))); - assert_last_event::( - Event::RetryCancelled { task: address, id: Some(name) }.into(), - ); + assert_last_event::(Event::RetryCancelled { task: address, id: Some(name) }.into()); + + Ok(()) } - impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite! { + Pallet, + mock::new_test_ext(), + mock::Test + } } diff --git a/substrate/frame/scheduler/src/weights.rs b/substrate/frame/scheduler/src/weights.rs index 62d2fe78049d..dc34ae556e70 100644 --- a/substrate/frame/scheduler/src/weights.rs +++ b/substrate/frame/scheduler/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_scheduler` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -79,8 +79,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_099_000 picoseconds. - Weight::from_parts(3_298_000, 1489) + // Minimum execution time: 3_735_000 picoseconds. + Weight::from_parts(3_928_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -91,10 +91,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_558_000 picoseconds. - Weight::from_parts(5_984_191, 110487) - // Standard Error: 564 - .saturating_add(Weight::from_parts(334_983, 0).saturating_mul(s.into())) + // Minimum execution time: 3_944_000 picoseconds. + Weight::from_parts(4_034_000, 110487) + // Standard Error: 1_119 + .saturating_add(Weight::from_parts(468_891, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -102,11 +102,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_389_000 picoseconds. - Weight::from_parts(3_609_000, 0) + // Minimum execution time: 3_235_000 picoseconds. + Weight::from_parts(3_423_000, 0) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) @@ -114,15 +114,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246 + s * (1 ±0)` - // Estimated: `3711 + s * (1 ±0)` - // Minimum execution time: 18_292_000 picoseconds. - Weight::from_parts(18_574_000, 3711) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_189, 0).saturating_mul(s.into())) + // Measured: `141 + s * (1 ±0)` + // Estimated: `4197809` + // Minimum execution time: 18_976_000 picoseconds. + Weight::from_parts(19_220_000, 4197809) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_871, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) } /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -130,16 +129,16 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_216_000 picoseconds. - Weight::from_parts(5_439_000, 0) + // Minimum execution time: 4_858_000 picoseconds. + Weight::from_parts(5_041_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_383_000 picoseconds. - Weight::from_parts(3_661_000, 0) + // Minimum execution time: 3_249_000 picoseconds. + Weight::from_parts(3_377_000, 0) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -149,16 +148,16 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 6_692_000 picoseconds. - Weight::from_parts(7_069_000, 3997) + // Minimum execution time: 8_482_000 picoseconds. + Weight::from_parts(9_252_000, 3997) .saturating_add(T::DbWeight::get().reads(2_u64)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_165_000 picoseconds. - Weight::from_parts(2_332_000, 0) + // Minimum execution time: 2_391_000 picoseconds. + Weight::from_parts(2_591_000, 0) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) @@ -167,10 +166,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 10_209_000 picoseconds. - Weight::from_parts(11_235_511, 110487) - // Standard Error: 906 - .saturating_add(Weight::from_parts(375_445, 0).saturating_mul(s.into())) + // Minimum execution time: 10_698_000 picoseconds. + Weight::from_parts(7_346_814, 110487) + // Standard Error: 2_513 + .saturating_add(Weight::from_parts(535_729, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -185,10 +184,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 15_906_000 picoseconds. - Weight::from_parts(13_697_344, 110487) - // Standard Error: 949 - .saturating_add(Weight::from_parts(564_461, 0).saturating_mul(s.into())) + // Minimum execution time: 16_371_000 picoseconds. + Weight::from_parts(9_559_789, 110487) + // Standard Error: 2_542 + .saturating_add(Weight::from_parts(723_961, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -201,10 +200,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 13_618_000 picoseconds. - Weight::from_parts(17_489_572, 110487) - // Standard Error: 766 - .saturating_add(Weight::from_parts(377_559, 0).saturating_mul(s.into())) + // Minimum execution time: 13_995_000 picoseconds. + Weight::from_parts(16_677_389, 110487) + // Standard Error: 2_606 + .saturating_add(Weight::from_parts(555_434, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -219,10 +218,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 17_954_000 picoseconds. - Weight::from_parts(18_459_344, 110487) - // Standard Error: 835 - .saturating_add(Weight::from_parts(585_557, 0).saturating_mul(s.into())) + // Minimum execution time: 18_962_000 picoseconds. + Weight::from_parts(17_610_180, 110487) + // Standard Error: 2_556 + .saturating_add(Weight::from_parts(743_494, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -235,10 +234,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `118` // Estimated: `110487` - // Minimum execution time: 9_446_000 picoseconds. - Weight::from_parts(10_797_672, 110487) - // Standard Error: 184 - .saturating_add(Weight::from_parts(13_971, 0).saturating_mul(s.into())) + // Minimum execution time: 10_303_000 picoseconds. + Weight::from_parts(12_180_080, 110487) + // Standard Error: 286 + .saturating_add(Weight::from_parts(16_437, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -250,8 +249,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `90705` // Estimated: `110487` - // Minimum execution time: 137_044_000 picoseconds. - Weight::from_parts(142_855_000, 110487) + // Minimum execution time: 156_198_000 picoseconds. + Weight::from_parts(167_250_000, 110487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -265,8 +264,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `91747` // Estimated: `110487` - // Minimum execution time: 144_333_000 picoseconds. - Weight::from_parts(149_251_000, 110487) + // Minimum execution time: 169_418_000 picoseconds. + Weight::from_parts(176_781_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -278,8 +277,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `90717` // Estimated: `110487` - // Minimum execution time: 132_387_000 picoseconds. - Weight::from_parts(139_222_000, 110487) + // Minimum execution time: 154_106_000 picoseconds. + Weight::from_parts(166_893_000, 110487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -293,8 +292,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `91759` // Estimated: `110487` - // Minimum execution time: 141_082_000 picoseconds. - Weight::from_parts(146_117_000, 110487) + // Minimum execution time: 167_121_000 picoseconds. + Weight::from_parts(175_510_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -308,8 +307,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_099_000 picoseconds. - Weight::from_parts(3_298_000, 1489) + // Minimum execution time: 3_735_000 picoseconds. + Weight::from_parts(3_928_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -320,10 +319,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_558_000 picoseconds. - Weight::from_parts(5_984_191, 110487) - // Standard Error: 564 - .saturating_add(Weight::from_parts(334_983, 0).saturating_mul(s.into())) + // Minimum execution time: 3_944_000 picoseconds. + Weight::from_parts(4_034_000, 110487) + // Standard Error: 1_119 + .saturating_add(Weight::from_parts(468_891, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -331,11 +330,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_389_000 picoseconds. - Weight::from_parts(3_609_000, 0) + // Minimum execution time: 3_235_000 picoseconds. + Weight::from_parts(3_423_000, 0) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) @@ -343,15 +342,14 @@ impl WeightInfo for () { /// The range of component `s` is `[128, 4194304]`. fn service_task_fetched(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246 + s * (1 ±0)` - // Estimated: `3711 + s * (1 ±0)` - // Minimum execution time: 18_292_000 picoseconds. - Weight::from_parts(18_574_000, 3711) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_189, 0).saturating_mul(s.into())) + // Measured: `141 + s * (1 ±0)` + // Estimated: `4197809` + // Minimum execution time: 18_976_000 picoseconds. + Weight::from_parts(19_220_000, 4197809) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_871, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) } /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -359,16 +357,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_216_000 picoseconds. - Weight::from_parts(5_439_000, 0) + // Minimum execution time: 4_858_000 picoseconds. + Weight::from_parts(5_041_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_383_000 picoseconds. - Weight::from_parts(3_661_000, 0) + // Minimum execution time: 3_249_000 picoseconds. + Weight::from_parts(3_377_000, 0) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -378,16 +376,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 6_692_000 picoseconds. - Weight::from_parts(7_069_000, 3997) + // Minimum execution time: 8_482_000 picoseconds. + Weight::from_parts(9_252_000, 3997) .saturating_add(RocksDbWeight::get().reads(2_u64)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_165_000 picoseconds. - Weight::from_parts(2_332_000, 0) + // Minimum execution time: 2_391_000 picoseconds. + Weight::from_parts(2_591_000, 0) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) @@ -396,10 +394,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 10_209_000 picoseconds. - Weight::from_parts(11_235_511, 110487) - // Standard Error: 906 - .saturating_add(Weight::from_parts(375_445, 0).saturating_mul(s.into())) + // Minimum execution time: 10_698_000 picoseconds. + Weight::from_parts(7_346_814, 110487) + // Standard Error: 2_513 + .saturating_add(Weight::from_parts(535_729, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -414,10 +412,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 15_906_000 picoseconds. - Weight::from_parts(13_697_344, 110487) - // Standard Error: 949 - .saturating_add(Weight::from_parts(564_461, 0).saturating_mul(s.into())) + // Minimum execution time: 16_371_000 picoseconds. + Weight::from_parts(9_559_789, 110487) + // Standard Error: 2_542 + .saturating_add(Weight::from_parts(723_961, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -430,10 +428,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 13_618_000 picoseconds. - Weight::from_parts(17_489_572, 110487) - // Standard Error: 766 - .saturating_add(Weight::from_parts(377_559, 0).saturating_mul(s.into())) + // Minimum execution time: 13_995_000 picoseconds. + Weight::from_parts(16_677_389, 110487) + // Standard Error: 2_606 + .saturating_add(Weight::from_parts(555_434, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -448,10 +446,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 17_954_000 picoseconds. - Weight::from_parts(18_459_344, 110487) - // Standard Error: 835 - .saturating_add(Weight::from_parts(585_557, 0).saturating_mul(s.into())) + // Minimum execution time: 18_962_000 picoseconds. + Weight::from_parts(17_610_180, 110487) + // Standard Error: 2_556 + .saturating_add(Weight::from_parts(743_494, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -464,10 +462,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `118` // Estimated: `110487` - // Minimum execution time: 9_446_000 picoseconds. - Weight::from_parts(10_797_672, 110487) - // Standard Error: 184 - .saturating_add(Weight::from_parts(13_971, 0).saturating_mul(s.into())) + // Minimum execution time: 10_303_000 picoseconds. + Weight::from_parts(12_180_080, 110487) + // Standard Error: 286 + .saturating_add(Weight::from_parts(16_437, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -479,8 +477,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `90705` // Estimated: `110487` - // Minimum execution time: 137_044_000 picoseconds. - Weight::from_parts(142_855_000, 110487) + // Minimum execution time: 156_198_000 picoseconds. + Weight::from_parts(167_250_000, 110487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -494,8 +492,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `91747` // Estimated: `110487` - // Minimum execution time: 144_333_000 picoseconds. - Weight::from_parts(149_251_000, 110487) + // Minimum execution time: 169_418_000 picoseconds. + Weight::from_parts(176_781_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -507,8 +505,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `90717` // Estimated: `110487` - // Minimum execution time: 132_387_000 picoseconds. - Weight::from_parts(139_222_000, 110487) + // Minimum execution time: 154_106_000 picoseconds. + Weight::from_parts(166_893_000, 110487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -522,8 +520,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `91759` // Estimated: `110487` - // Minimum execution time: 141_082_000 picoseconds. - Weight::from_parts(146_117_000, 110487) + // Minimum execution time: 167_121_000 picoseconds. + Weight::from_parts(175_510_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index d945ef42a47b..227868fa2a4f 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index b82112681e67..737678bea8a3 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -17,19 +17,19 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -impl-trait-for-tuples = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +impl-trait-for-tuples = { workspace = true } +log = { workspace = true } pallet-timestamp = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } sp-io = { workspace = true } sp-runtime = { features = ["serde"], workspace = true } sp-session = { workspace = true } sp-staking = { features = ["serde"], workspace = true } -sp-trie = { optional = true, workspace = true } sp-state-machine = { workspace = true } +sp-trie = { optional = true, workspace = true } [features] default = ["historical", "std"] diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index 264bc10a33f6..72e4b3deabfd 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -17,22 +17,22 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -rand = { features = ["std_rng"], workspace = true } frame-benchmarking = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-session = { workspace = true } pallet-staking = { workspace = true } +rand = { features = ["std_rng"], workspace = true } sp-runtime = { workspace = true } sp-session = { workspace = true } [dev-dependencies] codec = { features = ["derive"], workspace = true, default-features = true } -scale-info = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-staking-reward-curve = { workspace = true, default-features = true } pallet-timestamp = { workspace = true, default-features = true } +scale-info = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } diff --git a/substrate/frame/session/benchmarking/src/inner.rs b/substrate/frame/session/benchmarking/src/inner.rs index 9ba47b34ed7a..9789b6bb593d 100644 --- a/substrate/frame/session/benchmarking/src/inner.rs +++ b/substrate/frame/session/benchmarking/src/inner.rs @@ -22,7 +22,7 @@ use alloc::{vec, vec::Vec}; use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput}; use codec::Decode; -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v2::*; use frame_support::traits::{Get, KeyOwnerProofSystem, OnInitialize}; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::{historical::Pallet as Historical, Pallet as Session, *}; @@ -45,8 +45,12 @@ impl OnInitialize> for Pallet { } } -benchmarks! { - set_keys { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn set_keys() -> Result<(), BenchmarkError> { let n = MaxNominationsOf::::get(); let (v_stash, _) = create_validator_with_nominators::( n, @@ -58,13 +62,19 @@ benchmarks! { let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); - let proof: Vec = vec![0,1,2,3]; + let proof: Vec = vec![0, 1, 2, 3]; // Whitelist controller account from further DB operations. let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); - }: _(RawOrigin::Signed(v_controller), keys, proof) - purge_keys { + #[extrinsic_call] + _(RawOrigin::Signed(v_controller), keys, proof); + + Ok(()) + } + + #[benchmark] + fn purge_keys() -> Result<(), BenchmarkError> { let n = MaxNominationsOf::::get(); let (v_stash, _) = create_validator_with_nominators::( n, @@ -75,30 +85,33 @@ benchmarks! { )?; let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); - let proof: Vec = vec![0,1,2,3]; + let proof: Vec = vec![0, 1, 2, 3]; Session::::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?; // Whitelist controller account from further DB operations. let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); - }: _(RawOrigin::Signed(v_controller)) - #[extra] - check_membership_proof_current_session { - let n in 2 .. MAX_VALIDATORS as u32; + #[extrinsic_call] + _(RawOrigin::Signed(v_controller)); + Ok(()) + } + + #[benchmark(extra)] + fn check_membership_proof_current_session(n: Linear<2, MAX_VALIDATORS>) { let (key, key_owner_proof1) = check_membership_proof_setup::(n); let key_owner_proof2 = key_owner_proof1.clone(); - }: { - Historical::::check_proof(key, key_owner_proof1); - } - verify { + + #[block] + { + Historical::::check_proof(key, key_owner_proof1); + } + assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); } - #[extra] - check_membership_proof_historical_session { - let n in 2 .. MAX_VALIDATORS as u32; - + #[benchmark(extra)] + fn check_membership_proof_historical_session(n: Linear<2, MAX_VALIDATORS>) { let (key, key_owner_proof1) = check_membership_proof_setup::(n); // skip to the next session so that the session is historical @@ -106,14 +119,21 @@ benchmarks! { Session::::rotate_session(); let key_owner_proof2 = key_owner_proof1.clone(); - }: { - Historical::::check_proof(key, key_owner_proof1); - } - verify { + + #[block] + { + Historical::::check_proof(key, key_owner_proof1); + } + assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); } - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false); + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext(), + crate::mock::Test, + extra = false + ); } /// Sets up the benchmark for checking a membership proof. It creates the given diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 2aec58cceded..346cd04c0fa9 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; -use sp_runtime::{traits::IdentityLookup, BuildStorage}; +use sp_runtime::{traits::IdentityLookup, BuildStorage, KeyTypeId}; type AccountId = u64; type Nonce = u32; @@ -42,6 +42,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, Staking: pallet_staking, Session: pallet_session, + Historical: pallet_session::historical } ); @@ -79,7 +80,8 @@ sp_runtime::impl_opaque_keys! { pub struct TestSessionHandler; impl pallet_session::SessionHandler for TestSessionHandler { - const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[]; + // corresponds to the opaque key id above + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[KeyTypeId([100u8, 117u8, 109u8, 121u8])]; fn on_genesis_session(_validators: &[(AccountId, Ks)]) {} diff --git a/substrate/frame/session/src/lib.rs b/substrate/frame/session/src/lib.rs index 325758d54dd8..e8b4a355f49a 100644 --- a/substrate/frame/session/src/lib.rs +++ b/substrate/frame/session/src/lib.rs @@ -127,8 +127,8 @@ use frame_support::{ dispatch::DispatchResult, ensure, traits::{ - EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, OneSessionHandler, - ValidatorRegistration, ValidatorSet, + Defensive, EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get, + OneSessionHandler, ValidatorRegistration, ValidatorSet, }, weights::Weight, Parameter, @@ -735,6 +735,23 @@ impl Pallet { }) } + /// Re-enable the validator of index `i`, returns `false` if the validator was already enabled. + pub fn enable_index(i: u32) -> bool { + if i >= Validators::::decode_len().defensive_unwrap_or(0) as u32 { + return false + } + + // If the validator is not disabled, return false. + DisabledValidators::::mutate(|disabled| { + if let Ok(index) = disabled.binary_search(&i) { + disabled.remove(index); + true + } else { + false + } + }) + } + /// Disable the validator identified by `c`. (If using with the staking pallet, /// this would be their *stash* account.) /// diff --git a/substrate/frame/session/src/weights.rs b/substrate/frame/session/src/weights.rs index 2908a7563f07..a52db0645701 100644 --- a/substrate/frame/session/src/weights.rs +++ b/substrate/frame/session/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -66,10 +66,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1919` - // Estimated: `17759` - // Minimum execution time: 58_466_000 picoseconds. - Weight::from_parts(59_558_000, 17759) + // Measured: `1952` + // Estimated: `17792` + // Minimum execution time: 68_425_000 picoseconds. + Weight::from_parts(69_632_000, 17792) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -81,10 +81,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1817` - // Estimated: `5282` - // Minimum execution time: 41_730_000 picoseconds. - Weight::from_parts(42_476_000, 5282) + // Measured: `1850` + // Estimated: `5315` + // Minimum execution time: 49_086_000 picoseconds. + Weight::from_parts(50_131_000, 5315) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -100,10 +100,10 @@ impl WeightInfo for () { /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1919` - // Estimated: `17759` - // Minimum execution time: 58_466_000 picoseconds. - Weight::from_parts(59_558_000, 17759) + // Measured: `1952` + // Estimated: `17792` + // Minimum execution time: 68_425_000 picoseconds. + Weight::from_parts(69_632_000, 17792) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -115,10 +115,10 @@ impl WeightInfo for () { /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1817` - // Estimated: `5282` - // Minimum execution time: 41_730_000 picoseconds. - Weight::from_parts(42_476_000, 5282) + // Measured: `1850` + // Estimated: `5315` + // Minimum execution time: 49_086_000 picoseconds. + Weight::from_parts(50_131_000, 5315) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 555dee68ba01..d5860518fdda 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -16,17 +16,17 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { features = ["derive"], workspace = true } log = { workspace = true } rand_chacha = { workspace = true } scale-info = { features = ["derive"], workspace = true } -codec = { features = ["derive"], workspace = true } -sp-io = { workspace = true } -sp-arithmetic = { workspace = true } -sp-runtime = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-arithmetic = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] frame-support-test = { workspace = true } diff --git a/substrate/frame/society/src/benchmarking.rs b/substrate/frame/society/src/benchmarking.rs index 8c3d2bf32ce7..dc8e3cab775f 100644 --- a/substrate/frame/society/src/benchmarking.rs +++ b/substrate/frame/society/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; use alloc::vec; @@ -111,42 +111,57 @@ fn increment_round, I: 'static>() { RoundCount::::put(round_count); } -benchmarks_instance_pallet! { - bid { - let founder = setup_society::()?; +#[instance_benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn bid() -> Result<(), BenchmarkError> { + setup_society::()?; let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - }: _(RawOrigin::Signed(caller.clone()), 10u32.into()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), 10u32.into()); + let first_bid: Bid> = Bid { who: caller.clone(), kind: BidKind::Deposit(mock_balance_deposit::()), value: 10u32.into(), }; assert_eq!(Bids::::get(), vec![first_bid]); + Ok(()) } - unbid { - let founder = setup_society::()?; + #[benchmark] + fn unbid() -> Result<(), BenchmarkError> { + setup_society::()?; let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let mut bids = Bids::::get(); Society::::insert_bid(&mut bids, &caller, 10u32.into(), make_bid::(&caller)); Bids::::put(bids); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + assert_eq!(Bids::::get(), vec![]); + Ok(()) } - vouch { - let founder = setup_society::()?; + #[benchmark] + fn vouch() -> Result<(), BenchmarkError> { + setup_society::()?; let caller: T::AccountId = whitelisted_caller(); let vouched: T::AccountId = account("vouched", 0, 0); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let _ = Society::::insert_member(&caller, 1u32.into()); - let vouched_lookup: ::Source = T::Lookup::unlookup(vouched.clone()); - }: _(RawOrigin::Signed(caller.clone()), vouched_lookup, 0u32.into(), 0u32.into()) - verify { + let vouched_lookup: ::Source = + T::Lookup::unlookup(vouched.clone()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), vouched_lookup, 0u32.into(), 0u32.into()); + let bids = Bids::::get(); let vouched_bid: Bid> = Bid { who: vouched.clone(), @@ -154,207 +169,328 @@ benchmarks_instance_pallet! { value: 0u32.into(), }; assert_eq!(bids, vec![vouched_bid]); + Ok(()) } - unvouch { - let founder = setup_society::()?; + #[benchmark] + fn unvouch() -> Result<(), BenchmarkError> { + setup_society::()?; let caller: T::AccountId = whitelisted_caller(); - let vouched: T::AccountId = account("vouched", 0, 0); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let mut bids = Bids::::get(); - Society::::insert_bid(&mut bids, &caller, 10u32.into(), BidKind::Vouch(caller.clone(), 0u32.into())); + Society::::insert_bid( + &mut bids, + &caller, + 10u32.into(), + BidKind::Vouch(caller.clone(), 0u32.into()), + ); Bids::::put(bids); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + assert_eq!(Bids::::get(), vec![]); + Ok(()) } - vote { - let founder = setup_society::()?; + #[benchmark] + fn vote() -> Result<(), BenchmarkError> { + setup_society::()?; let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let _ = Society::::insert_member(&caller, 1u32.into()); let candidate = add_candidate::("candidate", Default::default(), false); - let candidate_lookup: ::Source = T::Lookup::unlookup(candidate.clone()); - }: _(RawOrigin::Signed(caller.clone()), candidate_lookup, true) - verify { + let candidate_lookup: ::Source = + T::Lookup::unlookup(candidate.clone()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), candidate_lookup, true); + let maybe_vote: Vote = >::get(candidate.clone(), caller).unwrap(); assert_eq!(maybe_vote.approve, true); + Ok(()) } - defender_vote { - let founder = setup_society::()?; + #[benchmark] + fn defender_vote() -> Result<(), BenchmarkError> { + setup_society::()?; let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let _ = Society::::insert_member(&caller, 1u32.into()); let defender: T::AccountId = account("defender", 0, 0); Defending::::put((defender, caller.clone(), Tally::default())); - }: _(RawOrigin::Signed(caller.clone()), false) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), false); + let round = RoundCount::::get(); let skeptic_vote: Vote = DefenderVotes::::get(round, &caller).unwrap(); assert_eq!(skeptic_vote.approve, false); + Ok(()) } - payout { - let founder = setup_funded_society::()?; + #[benchmark] + fn payout() -> Result<(), BenchmarkError> { + setup_funded_society::()?; // Payee's account already exists and is a member. let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, mock_balance_deposit::()); let _ = Society::::insert_member(&caller, 0u32.into()); // Introduce payout. Society::::bump_payout(&caller, 0u32.into(), 1u32.into()); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + let record = Payouts::::get(caller); assert!(record.payouts.is_empty()); + Ok(()) } - waive_repay { - let founder = setup_funded_society::()?; + #[benchmark] + fn waive_repay() -> Result<(), BenchmarkError> { + setup_funded_society::()?; let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let _ = Society::::insert_member(&caller, 0u32.into()); Society::::bump_payout(&caller, 0u32.into(), 1u32.into()); - }: _(RawOrigin::Signed(caller.clone()), 1u32.into()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), 1u32.into()); + let record = Payouts::::get(caller); assert!(record.payouts.is_empty()); + Ok(()) } - found_society { + #[benchmark] + fn found_society() -> Result<(), BenchmarkError> { let founder: T::AccountId = whitelisted_caller(); let can_found = T::FounderSetOrigin::try_successful_origin().map_err(|_| "No origin")?; - let founder_lookup: ::Source = T::Lookup::unlookup(founder.clone()); - }: _(can_found, founder_lookup, 5, 3, 3, mock_balance_deposit::(), b"benchmarking-society".to_vec()) - verify { + let founder_lookup: ::Source = + T::Lookup::unlookup(founder.clone()); + + #[extrinsic_call] + _( + can_found as T::RuntimeOrigin, + founder_lookup, + 5, + 3, + 3, + mock_balance_deposit::(), + b"benchmarking-society".to_vec(), + ); + assert_eq!(Founder::::get(), Some(founder.clone())); + Ok(()) } - dissolve { + #[benchmark] + fn dissolve() -> Result<(), BenchmarkError> { let founder = setup_society::()?; let members_and_candidates = vec![("m1", "c1"), ("m2", "c2"), ("m3", "c3"), ("m4", "c4")]; let members_count = members_and_candidates.clone().len() as u32; for (m, c) in members_and_candidates { let member: T::AccountId = account(m, 0, 0); let _ = Society::::insert_member(&member, 100u32.into()); - let candidate = add_candidate::(c, Tally { approvals: 1u32.into(), rejections: 1u32.into() }, false); - let candidate_lookup: ::Source = T::Lookup::unlookup(candidate); + let candidate = add_candidate::( + c, + Tally { approvals: 1u32.into(), rejections: 1u32.into() }, + false, + ); + let candidate_lookup: ::Source = + T::Lookup::unlookup(candidate); let _ = Society::::vote(RawOrigin::Signed(member).into(), candidate_lookup, true); } // Leaving only Founder member. - MemberCount::::mutate(|i| { i.saturating_reduce(members_count) }); - }: _(RawOrigin::Signed(founder)) - verify { + MemberCount::::mutate(|i| i.saturating_reduce(members_count)); + + #[extrinsic_call] + _(RawOrigin::Signed(founder)); + assert_eq!(Founder::::get(), None); + Ok(()) } - judge_suspended_member { + #[benchmark] + fn judge_suspended_member() -> Result<(), BenchmarkError> { let founder = setup_society::()?; let caller: T::AccountId = whitelisted_caller(); - let caller_lookup: ::Source = T::Lookup::unlookup(caller.clone()); + let caller_lookup: ::Source = + T::Lookup::unlookup(caller.clone()); let _ = Society::::insert_member(&caller, 0u32.into()); let _ = Society::::suspend_member(&caller); - }: _(RawOrigin::Signed(founder), caller_lookup, false) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(founder), caller_lookup, false); + assert_eq!(SuspendedMembers::::contains_key(&caller), false); + Ok(()) } - set_parameters { + #[benchmark] + fn set_parameters() -> Result<(), BenchmarkError> { let founder = setup_society::()?; let max_members = 10u32; let max_intake = 10u32; let max_strikes = 10u32; let candidate_deposit: BalanceOf = 10u32.into(); let params = GroupParams { max_members, max_intake, max_strikes, candidate_deposit }; - }: _(RawOrigin::Signed(founder), max_members, max_intake, max_strikes, candidate_deposit) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(founder), max_members, max_intake, max_strikes, candidate_deposit); + assert_eq!(Parameters::::get(), Some(params)); + Ok(()) } - punish_skeptic { - let founder = setup_society::()?; + #[benchmark] + fn punish_skeptic() -> Result<(), BenchmarkError> { + setup_society::()?; let candidate = add_candidate::("candidate", Default::default(), false); let skeptic: T::AccountId = account("skeptic", 0, 0); let _ = Society::::insert_member(&skeptic, 0u32.into()); Skeptic::::put(&skeptic); if let Period::Voting { more, .. } = Society::::period() { - frame_system::Pallet::::set_block_number(frame_system::Pallet::::block_number() + more); + frame_system::Pallet::::set_block_number( + frame_system::Pallet::::block_number() + more, + ); } - }: _(RawOrigin::Signed(candidate.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(candidate.clone())); + let candidacy = Candidates::::get(&candidate).unwrap(); assert_eq!(candidacy.skeptic_struck, true); + Ok(()) } - claim_membership { - let founder = setup_society::()?; - let candidate = add_candidate::("candidate", Tally { approvals: 3u32.into(), rejections: 0u32.into() }, false); + #[benchmark] + fn claim_membership() -> Result<(), BenchmarkError> { + setup_society::()?; + let candidate = add_candidate::( + "candidate", + Tally { approvals: 3u32.into(), rejections: 0u32.into() }, + false, + ); increment_round::(); - }: _(RawOrigin::Signed(candidate.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(candidate.clone())); + assert!(!Candidates::::contains_key(&candidate)); assert!(Members::::contains_key(&candidate)); + Ok(()) } - bestow_membership { + #[benchmark] + fn bestow_membership() -> Result<(), BenchmarkError> { let founder = setup_society::()?; - let candidate = add_candidate::("candidate", Tally { approvals: 3u32.into(), rejections: 1u32.into() }, false); + let candidate = add_candidate::( + "candidate", + Tally { approvals: 3u32.into(), rejections: 1u32.into() }, + false, + ); increment_round::(); - }: _(RawOrigin::Signed(founder), candidate.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(founder), candidate.clone()); + assert!(!Candidates::::contains_key(&candidate)); assert!(Members::::contains_key(&candidate)); + Ok(()) } - kick_candidate { + #[benchmark] + fn kick_candidate() -> Result<(), BenchmarkError> { let founder = setup_society::()?; - let candidate = add_candidate::("candidate", Tally { approvals: 1u32.into(), rejections: 1u32.into() }, false); + let candidate = add_candidate::( + "candidate", + Tally { approvals: 1u32.into(), rejections: 1u32.into() }, + false, + ); increment_round::(); - }: _(RawOrigin::Signed(founder), candidate.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(founder), candidate.clone()); + assert!(!Candidates::::contains_key(&candidate)); + Ok(()) } - resign_candidacy { - let founder = setup_society::()?; - let candidate = add_candidate::("candidate", Tally { approvals: 0u32.into(), rejections: 0u32.into() }, false); - }: _(RawOrigin::Signed(candidate.clone())) - verify { + #[benchmark] + fn resign_candidacy() -> Result<(), BenchmarkError> { + setup_society::()?; + let candidate = add_candidate::( + "candidate", + Tally { approvals: 0u32.into(), rejections: 0u32.into() }, + false, + ); + + #[extrinsic_call] + _(RawOrigin::Signed(candidate.clone())); + assert!(!Candidates::::contains_key(&candidate)); + Ok(()) } - drop_candidate { - let founder = setup_society::()?; - let candidate = add_candidate::("candidate", Tally { approvals: 0u32.into(), rejections: 3u32.into() }, false); + #[benchmark] + fn drop_candidate() -> Result<(), BenchmarkError> { + setup_society::()?; + let candidate = add_candidate::( + "candidate", + Tally { approvals: 0u32.into(), rejections: 3u32.into() }, + false, + ); let caller: T::AccountId = whitelisted_caller(); let _ = Society::::insert_member(&caller, 0u32.into()); let mut round_count = RoundCount::::get(); round_count = round_count.saturating_add(2u32); RoundCount::::put(round_count); - }: _(RawOrigin::Signed(caller), candidate.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), candidate.clone()); + assert!(!Candidates::::contains_key(&candidate)); + Ok(()) } - cleanup_candidacy { - let founder = setup_society::()?; - let candidate = add_candidate::("candidate", Tally { approvals: 0u32.into(), rejections: 0u32.into() }, false); + #[benchmark] + fn cleanup_candidacy() -> Result<(), BenchmarkError> { + setup_society::()?; + let candidate = add_candidate::( + "candidate", + Tally { approvals: 0u32.into(), rejections: 0u32.into() }, + false, + ); let member_one: T::AccountId = account("one", 0, 0); let member_two: T::AccountId = account("two", 0, 0); let _ = Society::::insert_member(&member_one, 0u32.into()); let _ = Society::::insert_member(&member_two, 0u32.into()); - let candidate_lookup: ::Source = T::Lookup::unlookup(candidate.clone()); - let _ = Society::::vote(RawOrigin::Signed(member_one.clone()).into(), candidate_lookup.clone(), true); - let _ = Society::::vote(RawOrigin::Signed(member_two.clone()).into(), candidate_lookup, true); + let candidate_lookup: ::Source = + T::Lookup::unlookup(candidate.clone()); + let _ = Society::::vote( + RawOrigin::Signed(member_one.clone()).into(), + candidate_lookup.clone(), + true, + ); + let _ = Society::::vote( + RawOrigin::Signed(member_two.clone()).into(), + candidate_lookup, + true, + ); Candidates::::remove(&candidate); - }: _(RawOrigin::Signed(member_one), candidate.clone(), 5) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(member_one), candidate.clone(), 5); + assert_eq!(Votes::::get(&candidate, &member_two), None); + Ok(()) } - cleanup_challenge { - let founder = setup_society::()?; + #[benchmark] + fn cleanup_challenge() -> Result<(), BenchmarkError> { + setup_society::()?; ChallengeRoundCount::::put(1u32); let member: T::AccountId = whitelisted_caller(); let _ = Society::::insert_member(&member, 0u32.into()); @@ -364,9 +500,12 @@ benchmarks_instance_pallet! { ChallengeRoundCount::::put(2u32); let mut challenge_round = ChallengeRoundCount::::get(); challenge_round = challenge_round.saturating_sub(1u32); - }: _(RawOrigin::Signed(member.clone()), challenge_round, 1u32) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(member.clone()), challenge_round, 1u32); + assert_eq!(DefenderVotes::::get(challenge_round, &defender), None); + Ok(()) } impl_benchmark_test_suite!( diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs index 04879cd87091..b893bb6fba7d 100644 --- a/substrate/frame/society/src/lib.rs +++ b/substrate/frame/society/src/lib.rs @@ -297,14 +297,14 @@ type NegativeImbalanceOf = <>::Currency as Currency< >>::NegativeImbalance; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Vote { approve: bool, weight: u32, } /// A judgement by the suspension judgement origin on a suspended candidate. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum Judgement { /// The suspension judgement origin takes no direct judgment /// and places the candidate back into the bid pool. @@ -316,7 +316,9 @@ pub enum Judgement { } /// Details of a payout given as a per-block linear "trickle". -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, Default, TypeInfo)] +#[derive( + Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen, +)] pub struct Payout { /// Total value of the payout. value: Balance, @@ -329,7 +331,7 @@ pub struct Payout { } /// Status of a vouching member. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum VouchingStatus { /// Member is currently vouching for a user. Vouching, @@ -341,7 +343,7 @@ pub enum VouchingStatus { pub type StrikeCount = u32; /// A bid for entry into society. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Bid { /// The bidder/candidate trying to enter society who: AccountId, @@ -361,7 +363,9 @@ pub type Rank = u32; pub type VoteCount = u32; /// Tally of votes. -#[derive(Default, Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive( + Default, Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] pub struct Tally { /// The approval votes. approvals: VoteCount, @@ -388,7 +392,7 @@ impl Tally { } /// A bid for entry into society. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Candidacy { /// The index of the round where the candidacy began. round: RoundIndex, @@ -403,7 +407,7 @@ pub struct Candidacy { } /// A vote by a member on a candidate application. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum BidKind { /// The given deposit was paid for this bid. Deposit(Balance), @@ -422,7 +426,7 @@ pub type PayoutsFor = BoundedVec<(BlockNumberFor, BalanceOf), >::MaxPayouts>; /// Information concerning a member. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct MemberRecord { rank: Rank, strikes: StrikeCount, @@ -431,7 +435,7 @@ pub struct MemberRecord { } /// Information concerning a member. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, Default)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)] pub struct PayoutRecord { paid: Balance, payouts: PayoutsVec, @@ -443,7 +447,7 @@ pub type PayoutRecordFor = PayoutRecord< >; /// Record for an individual new member who was elevated from a candidate recently. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct IntakeRecord { who: AccountId, bid: Balance, @@ -453,7 +457,7 @@ pub struct IntakeRecord { pub type IntakeRecordFor = IntakeRecord<::AccountId, BalanceOf>; -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct GroupParams { max_members: u32, max_intake: u32, @@ -471,7 +475,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] diff --git a/substrate/frame/society/src/weights.rs b/substrate/frame/society/src/weights.rs index 17ff0318f6a6..f6f59d20d659 100644 --- a/substrate/frame/society/src/weights.rs +++ b/substrate/frame/society/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_society` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -90,8 +90,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `444` // Estimated: `3909` - // Minimum execution time: 31_464_000 picoseconds. - Weight::from_parts(32_533_000, 3909) + // Minimum execution time: 37_812_000 picoseconds. + Weight::from_parts(38_375_000, 3909) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -101,8 +101,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `461` // Estimated: `1946` - // Minimum execution time: 24_132_000 picoseconds. - Weight::from_parts(24_936_000, 1946) + // Minimum execution time: 28_526_000 picoseconds. + Weight::from_parts(29_680_000, 1946) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -118,8 +118,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `481` // Estimated: `6421` - // Minimum execution time: 22_568_000 picoseconds. - Weight::from_parts(24_273_000, 6421) + // Minimum execution time: 28_051_000 picoseconds. + Weight::from_parts(29_088_000, 6421) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -131,8 +131,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `535` // Estimated: `4000` - // Minimum execution time: 15_524_000 picoseconds. - Weight::from_parts(16_324_000, 4000) + // Minimum execution time: 20_861_000 picoseconds. + Weight::from_parts(21_379_000, 4000) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -146,8 +146,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 22_360_000 picoseconds. - Weight::from_parts(23_318_000, 4034) + // Minimum execution time: 27_803_000 picoseconds. + Weight::from_parts(28_621_000, 4034) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -163,8 +163,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `561` // Estimated: `4026` - // Minimum execution time: 19_457_000 picoseconds. - Weight::from_parts(20_461_000, 4026) + // Minimum execution time: 24_774_000 picoseconds. + Weight::from_parts(26_040_000, 4026) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -176,10 +176,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `4115` - // Minimum execution time: 52_032_000 picoseconds. - Weight::from_parts(52_912_000, 4115) + // Measured: `687` + // Estimated: `4152` + // Minimum execution time: 58_072_000 picoseconds. + Weight::from_parts(59_603_000, 4152) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -191,8 +191,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `547` // Estimated: `4012` - // Minimum execution time: 19_479_000 picoseconds. - Weight::from_parts(20_120_000, 4012) + // Minimum execution time: 24_809_000 picoseconds. + Weight::from_parts(25_927_000, 4012) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -214,8 +214,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `1665` - // Minimum execution time: 15_843_000 picoseconds. - Weight::from_parts(16_617_000, 1665) + // Minimum execution time: 15_541_000 picoseconds. + Weight::from_parts(15_950_000, 1665) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -255,8 +255,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1654` // Estimated: `15019` - // Minimum execution time: 58_302_000 picoseconds. - Weight::from_parts(59_958_000, 15019) + // Minimum execution time: 62_275_000 picoseconds. + Weight::from_parts(64_251_000, 15019) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(30_u64)) } @@ -272,8 +272,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `505` // Estimated: `3970` - // Minimum execution time: 20_044_000 picoseconds. - Weight::from_parts(20_884_000, 3970) + // Minimum execution time: 25_561_000 picoseconds. + Weight::from_parts(26_796_000, 3970) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -287,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `387` // Estimated: `1872` - // Minimum execution time: 11_183_000 picoseconds. - Weight::from_parts(11_573_000, 1872) + // Minimum execution time: 12_183_000 picoseconds. + Weight::from_parts(12_813_000, 1872) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -308,8 +308,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `636` // Estimated: `4101` - // Minimum execution time: 24_149_000 picoseconds. - Weight::from_parts(25_160_000, 4101) + // Minimum execution time: 30_355_000 picoseconds. + Weight::from_parts(31_281_000, 4101) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -333,8 +333,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `632` // Estimated: `4097` - // Minimum execution time: 37_992_000 picoseconds. - Weight::from_parts(39_226_000, 4097) + // Minimum execution time: 43_935_000 picoseconds. + Weight::from_parts(45_511_000, 4097) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -360,8 +360,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `650` // Estimated: `4115` - // Minimum execution time: 39_383_000 picoseconds. - Weight::from_parts(40_367_000, 4115) + // Minimum execution time: 46_043_000 picoseconds. + Weight::from_parts(47_190_000, 4115) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -377,8 +377,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776` // Estimated: `6196` - // Minimum execution time: 40_060_000 picoseconds. - Weight::from_parts(40_836_000, 6196) + // Minimum execution time: 46_161_000 picoseconds. + Weight::from_parts(47_207_000, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -392,8 +392,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `746` // Estimated: `6196` - // Minimum execution time: 37_529_000 picoseconds. - Weight::from_parts(38_342_000, 6196) + // Minimum execution time: 43_176_000 picoseconds. + Weight::from_parts(44_714_000, 6196) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -407,8 +407,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `758` // Estimated: `6196` - // Minimum execution time: 37_992_000 picoseconds. - Weight::from_parts(39_002_000, 6196) + // Minimum execution time: 43_972_000 picoseconds. + Weight::from_parts(45_094_000, 6196) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -422,8 +422,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `552` // Estimated: `6492` - // Minimum execution time: 17_266_000 picoseconds. - Weight::from_parts(18_255_000, 6492) + // Minimum execution time: 19_900_000 picoseconds. + Weight::from_parts(20_940_000, 6492) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -435,8 +435,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3975` - // Minimum execution time: 11_636_000 picoseconds. - Weight::from_parts(12_122_000, 3975) + // Minimum execution time: 14_358_000 picoseconds. + Weight::from_parts(15_014_000, 3975) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -458,8 +458,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `444` // Estimated: `3909` - // Minimum execution time: 31_464_000 picoseconds. - Weight::from_parts(32_533_000, 3909) + // Minimum execution time: 37_812_000 picoseconds. + Weight::from_parts(38_375_000, 3909) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -469,8 +469,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `461` // Estimated: `1946` - // Minimum execution time: 24_132_000 picoseconds. - Weight::from_parts(24_936_000, 1946) + // Minimum execution time: 28_526_000 picoseconds. + Weight::from_parts(29_680_000, 1946) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -486,8 +486,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `481` // Estimated: `6421` - // Minimum execution time: 22_568_000 picoseconds. - Weight::from_parts(24_273_000, 6421) + // Minimum execution time: 28_051_000 picoseconds. + Weight::from_parts(29_088_000, 6421) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -499,8 +499,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `535` // Estimated: `4000` - // Minimum execution time: 15_524_000 picoseconds. - Weight::from_parts(16_324_000, 4000) + // Minimum execution time: 20_861_000 picoseconds. + Weight::from_parts(21_379_000, 4000) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -514,8 +514,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 22_360_000 picoseconds. - Weight::from_parts(23_318_000, 4034) + // Minimum execution time: 27_803_000 picoseconds. + Weight::from_parts(28_621_000, 4034) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -531,8 +531,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `561` // Estimated: `4026` - // Minimum execution time: 19_457_000 picoseconds. - Weight::from_parts(20_461_000, 4026) + // Minimum execution time: 24_774_000 picoseconds. + Weight::from_parts(26_040_000, 4026) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -544,10 +544,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `4115` - // Minimum execution time: 52_032_000 picoseconds. - Weight::from_parts(52_912_000, 4115) + // Measured: `687` + // Estimated: `4152` + // Minimum execution time: 58_072_000 picoseconds. + Weight::from_parts(59_603_000, 4152) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -559,8 +559,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `547` // Estimated: `4012` - // Minimum execution time: 19_479_000 picoseconds. - Weight::from_parts(20_120_000, 4012) + // Minimum execution time: 24_809_000 picoseconds. + Weight::from_parts(25_927_000, 4012) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -582,8 +582,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `180` // Estimated: `1665` - // Minimum execution time: 15_843_000 picoseconds. - Weight::from_parts(16_617_000, 1665) + // Minimum execution time: 15_541_000 picoseconds. + Weight::from_parts(15_950_000, 1665) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -623,8 +623,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1654` // Estimated: `15019` - // Minimum execution time: 58_302_000 picoseconds. - Weight::from_parts(59_958_000, 15019) + // Minimum execution time: 62_275_000 picoseconds. + Weight::from_parts(64_251_000, 15019) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(30_u64)) } @@ -640,8 +640,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `505` // Estimated: `3970` - // Minimum execution time: 20_044_000 picoseconds. - Weight::from_parts(20_884_000, 3970) + // Minimum execution time: 25_561_000 picoseconds. + Weight::from_parts(26_796_000, 3970) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -655,8 +655,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `387` // Estimated: `1872` - // Minimum execution time: 11_183_000 picoseconds. - Weight::from_parts(11_573_000, 1872) + // Minimum execution time: 12_183_000 picoseconds. + Weight::from_parts(12_813_000, 1872) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -676,8 +676,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `636` // Estimated: `4101` - // Minimum execution time: 24_149_000 picoseconds. - Weight::from_parts(25_160_000, 4101) + // Minimum execution time: 30_355_000 picoseconds. + Weight::from_parts(31_281_000, 4101) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -701,8 +701,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `632` // Estimated: `4097` - // Minimum execution time: 37_992_000 picoseconds. - Weight::from_parts(39_226_000, 4097) + // Minimum execution time: 43_935_000 picoseconds. + Weight::from_parts(45_511_000, 4097) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -728,8 +728,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `650` // Estimated: `4115` - // Minimum execution time: 39_383_000 picoseconds. - Weight::from_parts(40_367_000, 4115) + // Minimum execution time: 46_043_000 picoseconds. + Weight::from_parts(47_190_000, 4115) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -745,8 +745,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776` // Estimated: `6196` - // Minimum execution time: 40_060_000 picoseconds. - Weight::from_parts(40_836_000, 6196) + // Minimum execution time: 46_161_000 picoseconds. + Weight::from_parts(47_207_000, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -760,8 +760,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `746` // Estimated: `6196` - // Minimum execution time: 37_529_000 picoseconds. - Weight::from_parts(38_342_000, 6196) + // Minimum execution time: 43_176_000 picoseconds. + Weight::from_parts(44_714_000, 6196) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -775,8 +775,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `758` // Estimated: `6196` - // Minimum execution time: 37_992_000 picoseconds. - Weight::from_parts(39_002_000, 6196) + // Minimum execution time: 43_972_000 picoseconds. + Weight::from_parts(45_094_000, 6196) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -790,8 +790,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `552` // Estimated: `6492` - // Minimum execution time: 17_266_000 picoseconds. - Weight::from_parts(18_255_000, 6492) + // Minimum execution time: 19_900_000 picoseconds. + Weight::from_parts(20_940_000, 6492) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -803,8 +803,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3975` - // Minimum execution time: 11_636_000 picoseconds. - Weight::from_parts(12_122_000, 3975) + // Minimum execution time: 14_358_000 picoseconds. + Weight::from_parts(15_014_000, 3975) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index a8d2c0b3fc56..8031ddf96e6a 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -219,8 +219,8 @@ pub mod prelude { /// Runtime traits #[doc(no_inline)] pub use sp_runtime::traits::{ - Bounded, DispatchInfoOf, Dispatchable, SaturatedConversion, Saturating, StaticLookup, - TrailingZeroInput, + BlockNumberProvider, Bounded, DispatchInfoOf, Dispatchable, SaturatedConversion, + Saturating, StaticLookup, TrailingZeroInput, }; /// Other error/result types for runtime @@ -373,7 +373,10 @@ pub mod runtime { }; /// Types to define your runtime version. - pub use sp_version::{create_runtime_str, runtime_version, RuntimeVersion}; + // TODO: Remove deprecation suppression once + #[allow(deprecated)] + pub use sp_version::create_runtime_str; + pub use sp_version::{runtime_version, RuntimeVersion}; #[cfg(feature = "std")] pub use sp_version::NativeVersion; @@ -388,7 +391,7 @@ pub mod runtime { LOCAL_TESTNET_RUNTIME_PRESET, }; pub use sp_inherents::{CheckInherentsResult, InherentData}; - pub use sp_keyring::AccountKeyring; + pub use sp_keyring::Sr25519Keyring; pub use sp_runtime::{ApplyExtrinsicResult, ExtrinsicInclusionMode}; } diff --git a/substrate/frame/staking/CHANGELOG.md b/substrate/frame/staking/CHANGELOG.md index 113b7a6200b6..064a7d4a48f4 100644 --- a/substrate/frame/staking/CHANGELOG.md +++ b/substrate/frame/staking/CHANGELOG.md @@ -7,6 +7,18 @@ on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). We maintain a single integer version number for staking pallet to keep track of all storage migrations. +## [v16] + + +### Added + +- New default implementation of `DisablingStrategy` - `UpToLimitWithReEnablingDisablingStrategy`. + Same as `UpToLimitDisablingStrategy` except when a limit (1/3 default) is reached. When limit is + reached the offender is only disabled if his offence is greater or equal than some other already + disabled offender. The smallest possible offender is re-enabled to make space for the new greater + offender. A limit should thus always be respected. +- `DisabledValidators` changed format to include severity of the offence. + ## [v15] ### Added diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index a6a0ccd3b0a7..22176b6d720b 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -16,40 +16,40 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { features = ["alloc", "derive"], workspace = true } codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive", "serde"], workspace = true } -sp-io = { workspace = true } -sp-runtime = { features = ["serde"], workspace = true } -sp-staking = { features = ["serde"], workspace = true } +frame-election-provider-support = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +pallet-authorship = { workspace = true } pallet-session = { features = [ "historical", ], workspace = true } -pallet-authorship = { workspace = true } +scale-info = { features = ["derive", "serde"], workspace = true } +serde = { features = ["alloc", "derive"], workspace = true } sp-application-crypto = { features = ["serde"], workspace = true } -frame-election-provider-support = { workspace = true } -log = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-staking = { features = ["serde"], workspace = true } # Optional imports for benchmarking frame-benchmarking = { optional = true, workspace = true } rand_chacha = { optional = true, workspace = true } [dev-dependencies] +frame-benchmarking = { workspace = true, default-features = true } +frame-election-provider-support = { workspace = true, default-features = true } +pallet-bags-list = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } +pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +rand_chacha = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-npos-elections = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } -pallet-bags-list = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } substrate-test-utils = { workspace = true } -frame-benchmarking = { workspace = true, default-features = true } -frame-election-provider-support = { workspace = true, default-features = true } -rand_chacha = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 96bd3860542f..79d8dd3fbc30 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -708,7 +708,7 @@ mod benchmarks { >::insert( current_era, validator.clone(), - >::validators(&validator), + Validators::::get(&validator), ); let caller = whitelisted_caller(); @@ -975,20 +975,22 @@ mod benchmarks { ) -> Result<(), BenchmarkError> { // number of nominator intention. let n = MaxNominators::::get(); + create_validators_with_nominators_for_era::( + v, + n, + MaxNominationsOf::::get() as usize, + false, + None, + )?; + + let targets; #[block] { - create_validators_with_nominators_for_era::( - v, - n, - MaxNominationsOf::::get() as usize, - false, - None, - )?; + // default bounds are unbounded. + targets = >::get_npos_targets(DataProviderBounds::default()); } - // default bounds are unbounded. - let targets = >::get_npos_targets(DataProviderBounds::default()); assert_eq!(targets.len() as u32, v); Ok(()) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 19d999109d8d..6361663b2b1c 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -324,7 +324,7 @@ use sp_runtime::{ Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, }; use sp_staking::{ - offence::{Offence, OffenceError, ReportOffence}, + offence::{Offence, OffenceError, OffenceSeverity, ReportOffence}, EraIndex, ExposurePage, OnStakingUpdate, Page, PagedExposureMetadata, SessionIndex, StakingAccount, }; @@ -849,6 +849,9 @@ pub trait SessionInterface { /// Disable the validator at the given index, returns `false` if the validator was already /// disabled or the index is out of bounds. fn disable_validator(validator_index: u32) -> bool; + /// Re-enable a validator that was previously disabled. Returns `false` if the validator was + /// already enabled or the index is out of bounds. + fn enable_validator(validator_index: u32) -> bool; /// Get the validators from session. fn validators() -> Vec; /// Prune historical session tries up to but not including the given index. @@ -873,6 +876,10 @@ where >::disable_index(validator_index) } + fn enable_validator(validator_index: u32) -> bool { + >::enable_index(validator_index) + } + fn validators() -> Vec<::AccountId> { >::validators() } @@ -886,6 +893,9 @@ impl SessionInterface for () { fn disable_validator(_: u32) -> bool { true } + fn enable_validator(_: u32) -> bool { + true + } fn validators() -> Vec { Vec::new() } @@ -996,7 +1006,7 @@ impl Convert for ExposureOf { fn convert(validator: T::AccountId) -> Option>> { - >::active_era() + ActiveEra::::get() .map(|active_era| >::eras_stakers(active_era.index, &validator)) } } @@ -1271,19 +1281,47 @@ impl BenchmarkingConfig for TestBenchmarkingConfig { /// Controls validator disabling pub trait DisablingStrategy { - /// Make a disabling decision. Returns the index of the validator to disable or `None` if no new - /// validator should be disabled. + /// Make a disabling decision. Returning a [`DisablingDecision`] fn decision( offender_stash: &T::AccountId, + offender_slash_severity: OffenceSeverity, slash_era: EraIndex, - currently_disabled: &Vec, - ) -> Option; + currently_disabled: &Vec<(u32, OffenceSeverity)>, + ) -> DisablingDecision; } -/// Implementation of [`DisablingStrategy`] which disables validators from the active set up to a -/// threshold. `DISABLING_LIMIT_FACTOR` is the factor of the maximum disabled validators in the -/// active set. E.g. setting this value to `3` means no more than 1/3 of the validators in the -/// active set can be disabled in an era. +/// Helper struct representing a decision coming from a given [`DisablingStrategy`] implementing +/// `decision` +/// +/// `disable` is the index of the validator to disable, +/// `reenable` is the index of the validator to re-enable. +#[derive(Debug)] +pub struct DisablingDecision { + pub disable: Option, + pub reenable: Option, +} + +/// Calculate the disabling limit based on the number of validators and the disabling limit factor. +/// +/// This is a sensible default implementation for the disabling limit factor for most disabling +/// strategies. +/// +/// Disabling limit factor n=2 -> 1/n = 1/2 = 50% of validators can be disabled +fn factor_based_disable_limit(validators_len: usize, disabling_limit_factor: usize) -> usize { + validators_len + .saturating_sub(1) + .checked_div(disabling_limit_factor) + .unwrap_or_else(|| { + defensive!("DISABLING_LIMIT_FACTOR should not be 0"); + 0 + }) +} + +/// Implementation of [`DisablingStrategy`] using factor_based_disable_limit which disables +/// validators from the active set up to a threshold. `DISABLING_LIMIT_FACTOR` is the factor of the +/// maximum disabled validators in the active set. E.g. setting this value to `3` means no more than +/// 1/3 of the validators in the active set can be disabled in an era. +/// /// By default a factor of 3 is used which is the byzantine threshold. pub struct UpToLimitDisablingStrategy; @@ -1291,13 +1329,7 @@ impl UpToLimitDisablingStrategy usize { - validators_len - .saturating_sub(1) - .checked_div(DISABLING_LIMIT_FACTOR) - .unwrap_or_else(|| { - defensive!("DISABLING_LIMIT_FACTOR should not be 0"); - 0 - }) + factor_based_disable_limit(validators_len, DISABLING_LIMIT_FACTOR) } } @@ -1306,9 +1338,10 @@ impl DisablingStrategy { fn decision( offender_stash: &T::AccountId, + _offender_slash_severity: OffenceSeverity, slash_era: EraIndex, - currently_disabled: &Vec, - ) -> Option { + currently_disabled: &Vec<(u32, OffenceSeverity)>, + ) -> DisablingDecision { let active_set = T::SessionInterface::validators(); // We don't disable more than the limit @@ -1318,7 +1351,7 @@ impl DisablingStrategy "Won't disable: reached disabling limit {:?}", Self::disable_limit(active_set.len()) ); - return None + return DisablingDecision { disable: None, reenable: None } } // We don't disable for offences in previous eras @@ -1326,21 +1359,119 @@ impl DisablingStrategy log!( debug, "Won't disable: current_era {:?} > slash_era {:?}", - Pallet::::current_era().unwrap_or_default(), + CurrentEra::::get().unwrap_or_default(), slash_era ); - return None + return DisablingDecision { disable: None, reenable: None } } let offender_idx = if let Some(idx) = active_set.iter().position(|i| i == offender_stash) { idx as u32 } else { log!(debug, "Won't disable: offender not in active set",); - return None + return DisablingDecision { disable: None, reenable: None } }; log!(debug, "Will disable {:?}", offender_idx); - Some(offender_idx) + DisablingDecision { disable: Some(offender_idx), reenable: None } + } +} + +/// Implementation of [`DisablingStrategy`] which disables validators from the active set up to a +/// limit (factor_based_disable_limit) and if the limit is reached and the new offender is higher +/// (bigger punishment/severity) then it re-enables the lowest offender to free up space for the new +/// offender. +/// +/// This strategy is not based on cumulative severity of offences but only on the severity of the +/// highest offence. Offender first committing a 25% offence and then a 50% offence will be treated +/// the same as an offender committing 50% offence. +/// +/// An extension of [`UpToLimitDisablingStrategy`]. +pub struct UpToLimitWithReEnablingDisablingStrategy; + +impl + UpToLimitWithReEnablingDisablingStrategy +{ + /// Disabling limit calculated from the total number of validators in the active set. When + /// reached re-enabling logic might kick in. + pub fn disable_limit(validators_len: usize) -> usize { + factor_based_disable_limit(validators_len, DISABLING_LIMIT_FACTOR) + } +} + +impl DisablingStrategy + for UpToLimitWithReEnablingDisablingStrategy +{ + fn decision( + offender_stash: &T::AccountId, + offender_slash_severity: OffenceSeverity, + slash_era: EraIndex, + currently_disabled: &Vec<(u32, OffenceSeverity)>, + ) -> DisablingDecision { + let active_set = T::SessionInterface::validators(); + + // We don't disable for offences in previous eras + if ActiveEra::::get().map(|e| e.index).unwrap_or_default() > slash_era { + log!( + debug, + "Won't disable: current_era {:?} > slash_era {:?}", + Pallet::::current_era().unwrap_or_default(), + slash_era + ); + return DisablingDecision { disable: None, reenable: None } + } + + // We don't disable validators that are not in the active set + let offender_idx = if let Some(idx) = active_set.iter().position(|i| i == offender_stash) { + idx as u32 + } else { + log!(debug, "Won't disable: offender not in active set",); + return DisablingDecision { disable: None, reenable: None } + }; + + // Check if offender is already disabled + if let Some((_, old_severity)) = + currently_disabled.iter().find(|(idx, _)| *idx == offender_idx) + { + if offender_slash_severity > *old_severity { + log!(debug, "Offender already disabled but with lower severity, will disable again to refresh severity of {:?}", offender_idx); + return DisablingDecision { disable: Some(offender_idx), reenable: None }; + } else { + log!(debug, "Offender already disabled with higher or equal severity"); + return DisablingDecision { disable: None, reenable: None }; + } + } + + // We don't disable more than the limit (but we can re-enable a smaller offender to make + // space) + if currently_disabled.len() >= Self::disable_limit(active_set.len()) { + log!( + debug, + "Reached disabling limit {:?}, checking for re-enabling", + Self::disable_limit(active_set.len()) + ); + + // Find the smallest offender to re-enable that is not higher than + // offender_slash_severity + if let Some((smallest_idx, _)) = currently_disabled + .iter() + .filter(|(_, severity)| *severity <= offender_slash_severity) + .min_by_key(|(_, severity)| *severity) + { + log!(debug, "Will disable {:?} and re-enable {:?}", offender_idx, smallest_idx); + return DisablingDecision { + disable: Some(offender_idx), + reenable: Some(*smallest_idx), + } + } else { + log!(debug, "No smaller offender found to re-enable"); + return DisablingDecision { disable: None, reenable: None } + } + } else { + // If we are not at the limit, just disable the new offender and dont re-enable anyone + log!(debug, "Will disable {:?}", offender_idx); + return DisablingDecision { disable: Some(offender_idx), reenable: None } + } } } diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 5c9cf8613213..9dfa93c70b32 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -60,6 +60,79 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +/// Migrating `DisabledValidators` from `Vec` to `Vec<(u32, OffenceSeverity)>` to track offense +/// severity for re-enabling purposes. +pub mod v16 { + use super::*; + use sp_staking::offence::OffenceSeverity; + + pub struct VersionUncheckedMigrateV15ToV16(core::marker::PhantomData); + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let old_disabled_validators = v15::DisabledValidators::::get(); + Ok(old_disabled_validators.encode()) + } + + fn on_runtime_upgrade() -> Weight { + // Migrating `DisabledValidators` from `Vec` to `Vec<(u32, OffenceSeverity)>`. + // Using max severity (PerBill 100%) for the migration which effectively makes it so + // offenders before the migration will not be re-enabled this era unless there are + // other 100% offenders. + let max_offence = OffenceSeverity(Perbill::from_percent(100)); + // Inject severity + let migrated = v15::DisabledValidators::::take() + .into_iter() + .map(|v| (v, max_offence)) + .collect::>(); + + DisabledValidators::::set(migrated); + + log!(info, "v16 applied successfully."); + T::DbWeight::get().reads_writes(1, 1) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { + // Decode state to get old_disabled_validators in a format of Vec + let old_disabled_validators = + Vec::::decode(&mut state.as_slice()).expect("Failed to decode state"); + let new_disabled_validators = DisabledValidators::::get(); + + // Compare lengths + frame_support::ensure!( + old_disabled_validators.len() == new_disabled_validators.len(), + "DisabledValidators length mismatch" + ); + + // Compare contents + let new_disabled_validators = + new_disabled_validators.into_iter().map(|(v, _)| v).collect::>(); + frame_support::ensure!( + old_disabled_validators == new_disabled_validators, + "DisabledValidator ids mismatch" + ); + + // Verify severity + let max_severity = OffenceSeverity(Perbill::from_percent(100)); + let new_disabled_validators = DisabledValidators::::get(); + for (_, severity) in new_disabled_validators { + frame_support::ensure!(severity == max_severity, "Severity mismatch"); + } + + Ok(()) + } + } + + pub type MigrateV15ToV16 = VersionedMigration< + 15, + 16, + VersionUncheckedMigrateV15ToV16, + Pallet, + ::DbWeight, + >; +} + /// Migrating `OffendingValidators` from `Vec<(u32, bool)>` to `Vec` pub mod v15 { use super::*; @@ -67,6 +140,9 @@ pub mod v15 { // The disabling strategy used by staking pallet type DefaultDisablingStrategy = UpToLimitDisablingStrategy; + #[storage_alias] + pub(crate) type DisabledValidators = StorageValue, Vec, ValueQuery>; + pub struct VersionUncheckedMigrateV14ToV15(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV14ToV15 { fn on_runtime_upgrade() -> Weight { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4a0209fc5b08..df8cb38e8b37 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -258,7 +258,8 @@ impl OnStakingUpdate for EventListenerMock { } } -// Disabling threshold for `UpToLimitDisablingStrategy` +// Disabling threshold for `UpToLimitDisablingStrategy` and +// `UpToLimitWithReEnablingDisablingStrategy`` pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3; #[derive_impl(crate::config_preludes::TestDefaultConfig)] @@ -284,7 +285,8 @@ impl crate::pallet::pallet::Config for Test { type HistoryDepth = HistoryDepth; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type EventListeners = EventListenerMock; - type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type DisablingStrategy = + pallet_staking::UpToLimitWithReEnablingDisablingStrategy; } pub struct WeightedNominationsQuota; @@ -568,11 +570,11 @@ impl ExtBuilder { } pub(crate) fn active_era() -> EraIndex { - Staking::active_era().unwrap().index + pallet_staking::ActiveEra::::get().unwrap().index } pub(crate) fn current_era() -> EraIndex { - Staking::current_era().unwrap() + pallet_staking::CurrentEra::::get().unwrap() } pub(crate) fn bond(who: AccountId, val: Balance) { @@ -663,7 +665,7 @@ pub(crate) fn start_active_era(era_index: EraIndex) { pub(crate) fn current_total_payout_for_duration(duration: u64) -> Balance { let (payout, _rest) = ::EraPayout::era_payout( - Staking::eras_total_stake(active_era()), + pallet_staking::ErasTotalStake::::get(active_era()), pallet_balances::TotalIssuance::::get(), duration, ); @@ -673,7 +675,7 @@ pub(crate) fn current_total_payout_for_duration(duration: u64) -> Balance { pub(crate) fn maximum_payout_for_duration(duration: u64) -> Balance { let (payout, rest) = ::EraPayout::era_payout( - Staking::eras_total_stake(active_era()), + pallet_staking::ErasTotalStake::::get(active_era()), pallet_balances::TotalIssuance::::get(), duration, ); @@ -732,11 +734,11 @@ pub(crate) fn on_offence_in_era( } } - if Staking::active_era().unwrap().index == era { + if pallet_staking::ActiveEra::::get().unwrap().index == era { let _ = Staking::on_offence( offenders, slash_fraction, - Staking::eras_start_session_index(era).unwrap(), + pallet_staking::ErasStartSessionIndex::::get(era).unwrap(), ); } else { panic!("cannot slash in era {}", era); @@ -750,7 +752,7 @@ pub(crate) fn on_offence_now( >], slash_fraction: &[Perbill], ) { - let now = Staking::active_era().unwrap().index; + let now = pallet_staking::ActiveEra::::get().unwrap().index; on_offence_in_era(offenders, slash_fraction, now) } @@ -889,10 +891,10 @@ macro_rules! assert_session_era { $session, ); assert_eq!( - Staking::current_era().unwrap(), + CurrentEra::::get().unwrap(), $era, "wrong current era {} != {}", - Staking::current_era().unwrap(), + CurrentEra::::get().unwrap(), $era, ); }; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 6c4fe8140e8e..2ae925d03643 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -193,7 +193,7 @@ impl Pallet { ) -> Result { let mut ledger = Self::ledger(Controller(controller.clone()))?; let (stash, old_total) = (ledger.stash.clone(), ledger.total); - if let Some(current_era) = Self::current_era() { + if let Some(current_era) = CurrentEra::::get() { ledger = ledger.consolidate_unlocked(current_era) } let new_total = ledger.total; @@ -349,6 +349,8 @@ impl Pallet { Self::deposit_event(Event::::PayoutStarted { era_index: era, validator_stash: stash.clone(), + page, + next: EraInfo::::get_next_claimable_page(era, &stash, &ledger), }); let mut total_imbalance = PositiveImbalanceOf::::zero(); @@ -448,9 +450,9 @@ impl Pallet { session_index: SessionIndex, is_genesis: bool, ) -> Option>> { - if let Some(current_era) = Self::current_era() { + if let Some(current_era) = CurrentEra::::get() { // Initial era has been set. - let current_era_start_session_index = Self::eras_start_session_index(current_era) + let current_era_start_session_index = ErasStartSessionIndex::::get(current_era) .unwrap_or_else(|| { frame_support::print("Error: start_session_index must be set for current_era"); 0 @@ -490,12 +492,12 @@ impl Pallet { /// Start a session potentially starting an era. fn start_session(start_session: SessionIndex) { - let next_active_era = Self::active_era().map(|e| e.index + 1).unwrap_or(0); + let next_active_era = ActiveEra::::get().map(|e| e.index + 1).unwrap_or(0); // This is only `Some` when current era has already progressed to the next era, while the // active era is one behind (i.e. in the *last session of the active era*, or *first session // of the new current era*, depending on how you look at it). if let Some(next_active_era_start_session_index) = - Self::eras_start_session_index(next_active_era) + ErasStartSessionIndex::::get(next_active_era) { if next_active_era_start_session_index == start_session { Self::start_era(start_session); @@ -508,16 +510,16 @@ impl Pallet { } // disable all offending validators that have been disabled for the whole era - for index in >::get() { + for (index, _) in >::get() { T::SessionInterface::disable_validator(index); } } /// End a session potentially ending an era. fn end_session(session_index: SessionIndex) { - if let Some(active_era) = Self::active_era() { + if let Some(active_era) = ActiveEra::::get() { if let Some(next_active_era_start_session_index) = - Self::eras_start_session_index(active_era.index + 1) + ErasStartSessionIndex::::get(active_era.index + 1) { if next_active_era_start_session_index == session_index + 1 { Self::end_era(active_era, session_index); @@ -575,7 +577,7 @@ impl Pallet { let era_duration = (now_as_millis_u64.defensive_saturating_sub(active_era_start)) .saturated_into::(); - let staked = Self::eras_total_stake(&active_era.index); + let staked = ErasTotalStake::::get(&active_era.index); let issuance = asset::total_issuance::(); let (validator_payout, remainder) = @@ -666,7 +668,7 @@ impl Pallet { }; let exposures = Self::collect_exposures(election_result); - if (exposures.len() as u32) < Self::minimum_validator_count().max(1) { + if (exposures.len() as u32) < MinimumValidatorCount::::get().max(1) { // Session will panic if we ever return an empty validator set, thus max(1) ^^. match CurrentEra::::get() { Some(current_era) if current_era > 0 => log!( @@ -675,7 +677,7 @@ impl Pallet { elected, minimum is {})", CurrentEra::::get().unwrap_or(0), exposures.len(), - Self::minimum_validator_count(), + MinimumValidatorCount::::get(), ), None => { // The initial era is allowed to have no exposures. @@ -727,7 +729,7 @@ impl Pallet { // Collect the pref of all winners. for stash in &elected_stashes { - let pref = Self::validators(stash); + let pref = Validators::::get(stash); >::insert(&new_planned_era, stash, pref); } @@ -852,7 +854,7 @@ impl Pallet { /// /// COMPLEXITY: Complexity is `number_of_validator_to_reward x current_elected_len`. pub fn reward_by_ids(validators_points: impl IntoIterator) { - if let Some(active_era) = Self::active_era() { + if let Some(active_era) = ActiveEra::::get() { >::mutate(active_era.index, |era_rewards| { for (validator, points) in validators_points.into_iter() { *era_rewards.individual.entry(validator).or_default() += points; @@ -1194,7 +1196,7 @@ impl ElectionDataProvider for Pallet { fn desired_targets() -> data_provider::Result { Self::register_weight(T::DbWeight::get().reads(1)); - Ok(Self::validator_count()) + Ok(ValidatorCount::::get()) } fn electing_voters(bounds: DataProviderBounds) -> data_provider::Result>> { @@ -1227,10 +1229,10 @@ impl ElectionDataProvider for Pallet { } fn next_election_prediction(now: BlockNumberFor) -> BlockNumberFor { - let current_era = Self::current_era().unwrap_or(0); - let current_session = Self::current_planned_session(); + let current_era = CurrentEra::::get().unwrap_or(0); + let current_session = CurrentPlannedSession::::get(); let current_era_start_session_index = - Self::eras_start_session_index(current_era).unwrap_or(0); + ErasStartSessionIndex::::get(current_era).unwrap_or(0); // Number of session in the current era or the maximum session per era if reached. let era_progress = current_session .saturating_sub(current_era_start_session_index) @@ -1364,7 +1366,7 @@ impl historical::SessionManager Option>)>> { >::new_session(new_index).map(|validators| { - let current_era = Self::current_era() + let current_era = CurrentEra::::get() // Must be some as a new era has been created. .unwrap_or(0); @@ -1382,7 +1384,7 @@ impl historical::SessionManager Option>)>> { >::new_session_genesis(new_index).map( |validators| { - let current_era = Self::current_era() + let current_era = CurrentEra::::get() // Must be some as a new era has been created. .unwrap_or(0); @@ -1447,7 +1449,7 @@ where }; let active_era = { - let active_era = Self::active_era(); + let active_era = ActiveEra::::get(); add_db_reads_writes(1, 0); if active_era.is_none() { // This offence need not be re-submitted. @@ -1455,7 +1457,7 @@ where } active_era.expect("value checked not to be `None`; qed").index }; - let active_era_start_session_index = Self::eras_start_session_index(active_era) + let active_era_start_session_index = ErasStartSessionIndex::::get(active_era) .unwrap_or_else(|| { frame_support::print("Error: start_session_index must be set for current_era"); 0 @@ -1484,7 +1486,7 @@ where let slash_defer_duration = T::SlashDeferDuration::get(); - let invulnerables = Self::invulnerables(); + let invulnerables = Invulnerables::::get(); add_db_reads_writes(1, 0); for (details, slash_fraction) in offenders.iter().zip(slash_fraction) { @@ -1495,6 +1497,12 @@ where continue } + Self::deposit_event(Event::::SlashReported { + validator: stash.clone(), + fraction: *slash_fraction, + slash_era, + }); + let unapplied = slashing::compute_slash::(slashing::SlashParams { stash, slash: *slash_fraction, @@ -1505,12 +1513,6 @@ where reward_proportion, }); - Self::deposit_event(Event::::SlashReported { - validator: stash.clone(), - fraction: *slash_fraction, - slash_era, - }); - if let Some(mut unapplied) = unapplied { let nominators_len = unapplied.others.len() as u64; let reporters_len = details.reporters.len() as u64; @@ -1759,7 +1761,7 @@ impl StakingInterface for Pallet { } fn current_era() -> EraIndex { - Self::current_era().unwrap_or(Zero::zero()) + CurrentEra::::get().unwrap_or(Zero::zero()) } fn stake(who: &Self::AccountId) -> Result>, DispatchError> { @@ -1840,7 +1842,8 @@ impl StakingInterface for Pallet { } fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { - let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); + let num_slashing_spans = + SlashingSpans::::get(&who).map_or(0, |s| s.iter().count() as u32); Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) } @@ -1881,8 +1884,12 @@ impl StakingInterface for Pallet { } /// Whether `who` is a virtual staker whose funds are managed by another pallet. + /// + /// There is an assumption that, this account is keyless and managed by another pallet in the + /// runtime. Hence, it can never sign its own transactions. fn is_virtual_staker(who: &T::AccountId) -> bool { - VirtualStakers::::contains_key(who) + frame_system::Pallet::::account_nonce(who).is_zero() && + VirtualStakers::::contains_key(who) } fn slash_reward_fraction() -> Perbill { @@ -2103,6 +2110,10 @@ impl Pallet { Ledger::::get(stash.clone()).unwrap().stash == stash, "ledger corrupted for virtual staker" ); + ensure!( + frame_system::Pallet::::account_nonce(&stash).is_zero(), + "virtual stakers are keyless and should not have any nonce" + ); let reward_destination = >::get(stash.clone()).unwrap(); if let RewardDestination::Account(payee) = reward_destination { ensure!( @@ -2132,7 +2143,7 @@ impl Pallet { /// * For each era exposed validator, check if the exposure total is sane (exposure.total = /// exposure.own + exposure.own). fn check_exposures() -> Result<(), TryRuntimeError> { - let era = Self::active_era().unwrap().index; + let era = ActiveEra::::get().unwrap().index; ErasStakers::::iter_prefix_values(era) .map(|expo| { ensure!( @@ -2160,7 +2171,7 @@ impl Pallet { // Sanity check for the paged exposure of the active era. let mut exposures: BTreeMap>> = BTreeMap::new(); - let era = Self::active_era().unwrap().index; + let era = ActiveEra::::get().unwrap().index; let accumulator_default = PagedExposureMetadata { total: Zero::zero(), own: Zero::zero(), @@ -2222,7 +2233,7 @@ impl Pallet { fn check_nominators() -> Result<(), TryRuntimeError> { // a check per nominator to ensure their entire stake is correctly distributed. Will only // kick-in if the nomination was submitted before the current era. - let era = Self::active_era().unwrap().index; + let era = ActiveEra::::get().unwrap().index; // cache era exposures to avoid too many db reads. let era_exposures = T::SessionInterface::validators() @@ -2292,9 +2303,10 @@ impl Pallet { Ok(()) } + // Sorted by index fn ensure_disabled_validators_sorted() -> Result<(), TryRuntimeError> { ensure!( - DisabledValidators::::get().windows(2).all(|pair| pair[0] <= pair[1]), + DisabledValidators::::get().windows(2).all(|pair| pair[0].0 <= pair[1].0), "DisabledValidators is not sorted" ); Ok(()) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 28aa4f89b622..b3f8c18f704c 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -38,6 +38,7 @@ use sp_runtime::{ }; use sp_staking::{ + offence::OffenceSeverity, EraIndex, Page, SessionIndex, StakingAccount::{self, Controller, Stash}, StakingInterface, @@ -69,7 +70,7 @@ pub mod pallet { use super::*; /// The in-code storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(15); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(16); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -351,19 +352,16 @@ pub mod pallet { /// The ideal number of active validators. #[pallet::storage] - #[pallet::getter(fn validator_count)] pub type ValidatorCount = StorageValue<_, u32, ValueQuery>; /// Minimum number of staking participants before emergency conditions are imposed. #[pallet::storage] - #[pallet::getter(fn minimum_validator_count)] pub type MinimumValidatorCount = StorageValue<_, u32, ValueQuery>; /// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're /// easy to initialize and the performance hit is minimal (we expect no more than four /// invulnerables) and restricted to testnets. #[pallet::storage] - #[pallet::getter(fn invulnerables)] #[pallet::unbounded] pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; @@ -409,7 +407,6 @@ pub mod pallet { /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] - #[pallet::getter(fn validators)] pub type Validators = CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>; @@ -439,7 +436,6 @@ pub mod pallet { /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] - #[pallet::getter(fn nominators)] pub type Nominators = CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; @@ -463,7 +459,6 @@ pub mod pallet { /// This is the latest planned era, depending on how the Session pallet queues the validator /// set, it might be active or not. #[pallet::storage] - #[pallet::getter(fn current_era)] pub type CurrentEra = StorageValue<_, EraIndex>; /// The active era information, it holds index and start. @@ -471,7 +466,6 @@ pub mod pallet { /// The active era is the era being currently rewarded. Validator set of this era must be /// equal to [`SessionInterface::validators`]. #[pallet::storage] - #[pallet::getter(fn active_era)] pub type ActiveEra = StorageValue<_, ActiveEraInfo>; /// The session index at which the era start for the last [`Config::HistoryDepth`] eras. @@ -479,7 +473,6 @@ pub mod pallet { /// Note: This tracks the starting session (i.e. session index when era start being active) /// for the eras in `[CurrentEra - HISTORY_DEPTH, CurrentEra]`. #[pallet::storage] - #[pallet::getter(fn eras_start_session_index)] pub type ErasStartSessionIndex = StorageMap<_, Twox64Concat, EraIndex, SessionIndex>; /// Exposure of validator at era. @@ -543,7 +536,6 @@ pub mod pallet { /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. #[pallet::storage] #[pallet::unbounded] - #[pallet::getter(fn eras_stakers_clipped)] pub type ErasStakersClipped = StorageDoubleMap< _, Twox64Concat, @@ -580,7 +572,6 @@ pub mod pallet { /// /// It is removed after [`Config::HistoryDepth`] eras. #[pallet::storage] - #[pallet::getter(fn claimed_rewards)] #[pallet::unbounded] pub type ClaimedRewards = StorageDoubleMap< _, @@ -599,7 +590,6 @@ pub mod pallet { /// Is it removed after [`Config::HistoryDepth`] eras. // If prefs hasn't been set or has been removed then 0 commission is returned. #[pallet::storage] - #[pallet::getter(fn eras_validator_prefs)] pub type ErasValidatorPrefs = StorageDoubleMap< _, Twox64Concat, @@ -614,27 +604,23 @@ pub mod pallet { /// /// Eras that haven't finished yet or has been removed doesn't have reward. #[pallet::storage] - #[pallet::getter(fn eras_validator_reward)] pub type ErasValidatorReward = StorageMap<_, Twox64Concat, EraIndex, BalanceOf>; /// Rewards for the last [`Config::HistoryDepth`] eras. /// If reward hasn't been set or has been removed then 0 reward is returned. #[pallet::storage] #[pallet::unbounded] - #[pallet::getter(fn eras_reward_points)] pub type ErasRewardPoints = StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; /// The total amount staked for the last [`Config::HistoryDepth`] eras. /// If total hasn't been set or has been removed then 0 stake is returned. #[pallet::storage] - #[pallet::getter(fn eras_total_stake)] pub type ErasTotalStake = StorageMap<_, Twox64Concat, EraIndex, BalanceOf, ValueQuery>; /// Mode of era forcing. #[pallet::storage] - #[pallet::getter(fn force_era)] pub type ForceEra = StorageValue<_, Forcing, ValueQuery>; /// Maximum staked rewards, i.e. the percentage of the era inflation that @@ -647,13 +633,11 @@ pub mod pallet { /// /// The rest of the slashed value is handled by the `Slash`. #[pallet::storage] - #[pallet::getter(fn slash_reward_fraction)] pub type SlashRewardFraction = StorageValue<_, Perbill, ValueQuery>; /// The amount of currency given to reporters of a slash event which was /// canceled by extraordinary circumstances (e.g. governance). #[pallet::storage] - #[pallet::getter(fn canceled_payout)] pub type CanceledSlashPayout = StorageValue<_, BalanceOf, ValueQuery>; /// All unapplied slashes that are queued for later. @@ -695,7 +679,6 @@ pub mod pallet { /// Slashing spans for stash accounts. #[pallet::storage] - #[pallet::getter(fn slashing_spans)] #[pallet::unbounded] pub type SlashingSpans = StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>; @@ -715,7 +698,6 @@ pub mod pallet { /// /// This is basically in sync with the call to [`pallet_session::SessionManager::new_session`]. #[pallet::storage] - #[pallet::getter(fn current_planned_session)] pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; /// Indices of validators that have offended in the active era. The offenders are disabled for a @@ -723,11 +705,15 @@ pub mod pallet { /// implementor of [`DisablingStrategy`] defines if a validator should be disabled which /// implicitly means that the implementor also controls the max number of disabled validators. /// - /// The vec is always kept sorted so that we can find whether a given validator has previously - /// offended using binary search. + /// The vec is always kept sorted based on the u32 index so that we can find whether a given + /// validator has previously offended using binary search. + /// + /// Additionally, each disabled validator is associated with an `OffenceSeverity` which + /// represents how severe is the offence that got the validator disabled. #[pallet::storage] #[pallet::unbounded] - pub type DisabledValidators = StorageValue<_, Vec, ValueQuery>; + pub type DisabledValidators = + StorageValue<_, Vec<(u32, OffenceSeverity)>, ValueQuery>; /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators @@ -851,8 +837,13 @@ pub mod pallet { StakingElectionFailed, /// An account has stopped participating as either a validator or nominator. Chilled { stash: T::AccountId }, - /// The stakers' rewards are getting paid. - PayoutStarted { era_index: EraIndex, validator_stash: T::AccountId }, + /// A Page of stakers rewards are getting paid. `next` is `None` if all pages are claimed. + PayoutStarted { + era_index: EraIndex, + validator_stash: T::AccountId, + page: Page, + next: Option, + }, /// A validator has set their preferences. ValidatorPrefsSet { stash: T::AccountId, prefs: ValidatorPrefs }, /// Voters size limit reached. @@ -863,6 +854,10 @@ pub mod pallet { ForceEra { mode: Forcing }, /// Report of a controller batch deprecation. ControllerBatchDeprecated { failures: u32 }, + /// Validator has been disabled. + ValidatorDisabled { stash: T::AccountId }, + /// Validator has been re-enabled. + ValidatorReenabled { stash: T::AccountId }, } #[pallet::error] @@ -945,7 +940,7 @@ pub mod pallet { fn on_finalize(_n: BlockNumberFor) { // Set the start of the first era. - if let Some(mut active_era) = Self::active_era() { + if let Some(mut active_era) = ActiveEra::::get() { if active_era.start.is_none() { let now_as_millis_u64 = T::UnixTime::now().as_millis().saturated_into::(); active_era.start = Some(now_as_millis_u64); @@ -986,6 +981,156 @@ pub mod pallet { } } + impl Pallet { + /// Get the ideal number of active validators. + pub fn validator_count() -> u32 { + ValidatorCount::::get() + } + + /// Get the minimum number of staking participants before emergency conditions are imposed. + pub fn minimum_validator_count() -> u32 { + MinimumValidatorCount::::get() + } + + /// Get the validators that may never be slashed or forcibly kicked out. + pub fn invulnerables() -> Vec { + Invulnerables::::get() + } + + /// Get the preferences of a given validator. + pub fn validators(account_id: EncodeLikeAccountId) -> ValidatorPrefs + where + EncodeLikeAccountId: codec::EncodeLike, + { + Validators::::get(account_id) + } + + /// Get the nomination preferences of a given nominator. + pub fn nominators( + account_id: EncodeLikeAccountId, + ) -> Option> + where + EncodeLikeAccountId: codec::EncodeLike, + { + Nominators::::get(account_id) + } + + /// Get the current era index. + pub fn current_era() -> Option { + CurrentEra::::get() + } + + /// Get the active era information. + pub fn active_era() -> Option { + ActiveEra::::get() + } + + /// Get the session index at which the era starts for the last [`Config::HistoryDepth`] + /// eras. + pub fn eras_start_session_index( + era_index: EncodeLikeEraIndex, + ) -> Option + where + EncodeLikeEraIndex: codec::EncodeLike, + { + ErasStartSessionIndex::::get(era_index) + } + + /// Get the clipped exposure of a given validator at an era. + pub fn eras_stakers_clipped( + era_index: EncodeLikeEraIndex, + account_id: EncodeLikeAccountId, + ) -> Exposure> + where + EncodeLikeEraIndex: codec::EncodeLike, + EncodeLikeAccountId: codec::EncodeLike, + { + ErasStakersClipped::::get(era_index, account_id) + } + + /// Get the paged history of claimed rewards by era for given validator. + pub fn claimed_rewards( + era_index: EncodeLikeEraIndex, + account_id: EncodeLikeAccountId, + ) -> Vec + where + EncodeLikeEraIndex: codec::EncodeLike, + EncodeLikeAccountId: codec::EncodeLike, + { + ClaimedRewards::::get(era_index, account_id) + } + + /// Get the preferences of given validator at given era. + pub fn eras_validator_prefs( + era_index: EncodeLikeEraIndex, + account_id: EncodeLikeAccountId, + ) -> ValidatorPrefs + where + EncodeLikeEraIndex: codec::EncodeLike, + EncodeLikeAccountId: codec::EncodeLike, + { + ErasValidatorPrefs::::get(era_index, account_id) + } + + /// Get the total validator era payout for the last [`Config::HistoryDepth`] eras. + pub fn eras_validator_reward( + era_index: EncodeLikeEraIndex, + ) -> Option> + where + EncodeLikeEraIndex: codec::EncodeLike, + { + ErasValidatorReward::::get(era_index) + } + + /// Get the rewards for the last [`Config::HistoryDepth`] eras. + pub fn eras_reward_points( + era_index: EncodeLikeEraIndex, + ) -> EraRewardPoints + where + EncodeLikeEraIndex: codec::EncodeLike, + { + ErasRewardPoints::::get(era_index) + } + + /// Get the total amount staked for the last [`Config::HistoryDepth`] eras. + pub fn eras_total_stake(era_index: EncodeLikeEraIndex) -> BalanceOf + where + EncodeLikeEraIndex: codec::EncodeLike, + { + ErasTotalStake::::get(era_index) + } + + /// Get the mode of era forcing. + pub fn force_era() -> Forcing { + ForceEra::::get() + } + + /// Get the percentage of the slash that is distributed to reporters. + pub fn slash_reward_fraction() -> Perbill { + SlashRewardFraction::::get() + } + + /// Get the amount of canceled slash payout. + pub fn canceled_payout() -> BalanceOf { + CanceledSlashPayout::::get() + } + + /// Get the slashing spans for given account. + pub fn slashing_spans( + account_id: EncodeLikeAccountId, + ) -> Option + where + EncodeLikeAccountId: codec::EncodeLike, + { + SlashingSpans::::get(account_id) + } + + /// Get the last planned session scheduled by the session pallet. + pub fn current_planned_session() -> SessionIndex { + CurrentPlannedSession::::get() + } + } + #[pallet::call] impl Pallet { /// Take the origin account as a stash and lock up `value` of its balance. `controller` will @@ -1102,7 +1247,7 @@ pub mod pallet { let maybe_withdraw_weight = { if unlocking == T::MaxUnlockingChunks::get() as usize { let real_num_slashing_spans = - Self::slashing_spans(&controller).map_or(0, |s| s.iter().count()); + SlashingSpans::::get(&controller).map_or(0, |s| s.iter().count()); Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)?) } else { None @@ -1142,7 +1287,7 @@ pub mod pallet { ensure!(ledger.active >= min_active_bond, Error::::InsufficientBond); // Note: in case there is no current era it is fine to bond one era more. - let era = Self::current_era() + let era = CurrentEra::::get() .unwrap_or(0) .defensive_saturating_add(T::BondingDuration::get()); if let Some(chunk) = ledger.unlocking.last_mut().filter(|chunk| chunk.era == era) { @@ -1312,7 +1457,7 @@ pub mod pallet { let nominations = Nominations { targets, // Initial nominations are considered submitted at era 0. See `Nominations` doc. - submitted_in: Self::current_era().unwrap_or(0), + submitted_in: CurrentEra::::get().unwrap_or(0), suppressed: false, }; diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 9fb782265b8b..ae76b0707dcb 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -65,7 +65,7 @@ use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, RuntimeDebug, }; -use sp_staking::{EraIndex, StakingInterface}; +use sp_staking::{offence::OffenceSeverity, EraIndex, StakingInterface}; /// The proportion of the slashing reward to be paid out on the first slashing detection. /// This is f_1 in the paper. @@ -321,17 +321,48 @@ fn kick_out_if_recent(params: SlashParams) { } /// Inform the [`DisablingStrategy`] implementation about the new offender and disable the list of -/// validators provided by [`make_disabling_decision`]. +/// validators provided by [`decision`]. fn add_offending_validator(params: &SlashParams) { DisabledValidators::::mutate(|disabled| { - if let Some(offender) = - T::DisablingStrategy::decision(params.stash, params.slash_era, &disabled) - { - // Add the validator to `DisabledValidators` and disable it. Do nothing if it is - // already disabled. - if let Err(index) = disabled.binary_search_by_key(&offender, |index| *index) { - disabled.insert(index, offender); - T::SessionInterface::disable_validator(offender); + let new_severity = OffenceSeverity(params.slash); + let decision = + T::DisablingStrategy::decision(params.stash, new_severity, params.slash_era, &disabled); + + if let Some(offender_idx) = decision.disable { + // Check if the offender is already disabled + match disabled.binary_search_by_key(&offender_idx, |(index, _)| *index) { + // Offender is already disabled, update severity if the new one is higher + Ok(index) => { + let (_, old_severity) = &mut disabled[index]; + if new_severity > *old_severity { + *old_severity = new_severity; + } + }, + Err(index) => { + // Offender is not disabled, add to `DisabledValidators` and disable it + disabled.insert(index, (offender_idx, new_severity)); + // Propagate disablement to session level + T::SessionInterface::disable_validator(offender_idx); + // Emit event that a validator got disabled + >::deposit_event(super::Event::::ValidatorDisabled { + stash: params.stash.clone(), + }); + }, + } + } + + if let Some(reenable_idx) = decision.reenable { + // Remove the validator from `DisabledValidators` and re-enable it. + if let Ok(index) = disabled.binary_search_by_key(&reenable_idx, |(index, _)| *index) { + disabled.remove(index); + // Propagate re-enablement to session level + T::SessionInterface::enable_validator(reenable_idx); + // Emit event that a validator got re-enabled + let reenabled_stash = + T::SessionInterface::validators()[reenable_idx as usize].clone(); + >::deposit_event(super::Event::::ValidatorReenabled { + stash: reenabled_stash, + }); } } }); diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index efd4a40f1ab4..81337710aa90 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -236,5 +236,5 @@ pub fn create_validators_with_nominators_for_era( /// get the current era. pub fn current_era() -> EraIndex { - >::current_era().unwrap_or(0) + CurrentEra::::get().unwrap_or(0) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 639f4096456f..6c2335e1aac8 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -200,7 +200,7 @@ fn basic_setup_works() { legacy_claimed_rewards: bounded_vec![], } ); - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); assert_eq!( Staking::eras_stakers(active_era(), &11), @@ -220,10 +220,10 @@ fn basic_setup_works() { ); // initial total stake = 1125 + 1375 - assert_eq!(Staking::eras_total_stake(active_era()), 2500); + assert_eq!(ErasTotalStake::::get(active_era()), 2500); // The number of validators required. - assert_eq!(Staking::validator_count(), 2); + assert_eq!(ValidatorCount::::get(), 2); // Initial Era and session assert_eq!(active_era(), 0); @@ -233,7 +233,7 @@ fn basic_setup_works() { assert_eq!(asset::stakeable_balance::(&10), 1); // New era is not being forced - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); }); } @@ -336,7 +336,7 @@ fn rewards_should_work() { assert_eq!(asset::total_balance::(&21), init_balance_21); assert_eq!(asset::total_balance::(&101), init_balance_101); assert_eq!( - Staking::eras_reward_points(active_era()), + ErasRewardPoints::::get(active_era()), EraRewardPoints { total: 50 * 3, individual: vec![(11, 100), (21, 50)].into_iter().collect(), @@ -530,8 +530,8 @@ fn less_than_needed_candidates_works() { .validator_count(4) .nominate(false) .build_and_execute(|| { - assert_eq!(Staking::validator_count(), 4); - assert_eq!(Staking::minimum_validator_count(), 1); + assert_eq!(ValidatorCount::::get(), 4); + assert_eq!(MinimumValidatorCount::::get(), 1); assert_eq_uvec!(validator_controllers(), vec![31, 21, 11]); mock::start_active_era(1); @@ -1096,7 +1096,7 @@ fn reward_destination_works() { ); // (era 0, page 0) is claimed - assert_eq!(Staking::claimed_rewards(0, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(0, &11), vec![0]); // Change RewardDestination to Stash >::insert(&11, RewardDestination::Stash); @@ -1127,7 +1127,7 @@ fn reward_destination_works() { ); // (era 1, page 0) is claimed - assert_eq!(Staking::claimed_rewards(1, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(1, &11), vec![0]); // Change RewardDestination to Account >::insert(&11, RewardDestination::Account(11)); @@ -1159,7 +1159,7 @@ fn reward_destination_works() { ); // (era 2, page 0) is claimed - assert_eq!(Staking::claimed_rewards(2, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(2, &11), vec![0]); }); } @@ -1852,7 +1852,7 @@ fn reward_to_stake_works() { .set_stake(21, 2000) .try_state(false) .build_and_execute(|| { - assert_eq!(Staking::validator_count(), 2); + assert_eq!(ValidatorCount::::get(), 2); // Confirm account 10 and 20 are validators assert!(>::contains_key(&11) && >::contains_key(&21)); @@ -2281,7 +2281,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { #[test] fn new_era_elects_correct_number_of_validators() { ExtBuilder::default().nominate(true).validator_count(1).build_and_execute(|| { - assert_eq!(Staking::validator_count(), 1); + assert_eq!(ValidatorCount::::get(), 1); assert_eq!(validator_controllers().len(), 1); Session::on_initialize(System::block_number()); @@ -2431,11 +2431,11 @@ fn era_is_always_same_length() { let session_per_era = >::get(); mock::start_active_era(1); - assert_eq!(Staking::eras_start_session_index(current_era()).unwrap(), session_per_era); + assert_eq!(ErasStartSessionIndex::::get(current_era()).unwrap(), session_per_era); mock::start_active_era(2); assert_eq!( - Staking::eras_start_session_index(current_era()).unwrap(), + ErasStartSessionIndex::::get(current_era()).unwrap(), session_per_era * 2u32 ); @@ -2444,11 +2444,11 @@ fn era_is_always_same_length() { advance_session(); advance_session(); assert_eq!(current_era(), 3); - assert_eq!(Staking::eras_start_session_index(current_era()).unwrap(), session + 2); + assert_eq!(ErasStartSessionIndex::::get(current_era()).unwrap(), session + 2); mock::start_active_era(4); assert_eq!( - Staking::eras_start_session_index(current_era()).unwrap(), + ErasStartSessionIndex::::get(current_era()).unwrap(), session + 2u32 + session_per_era ); }); @@ -2465,7 +2465,7 @@ fn offence_doesnt_force_new_era() { &[Perbill::from_percent(5)], ); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); }); } @@ -2473,7 +2473,7 @@ fn offence_doesnt_force_new_era() { fn offence_ensures_new_era_without_clobbering() { ExtBuilder::default().build_and_execute(|| { assert_ok!(Staking::force_new_era_always(RuntimeOrigin::root())); - assert_eq!(Staking::force_era(), Forcing::ForceAlways); + assert_eq!(ForceEra::::get(), Forcing::ForceAlways); on_offence_now( &[OffenceDetails { @@ -2483,7 +2483,7 @@ fn offence_ensures_new_era_without_clobbering() { &[Perbill::from_percent(5)], ); - assert_eq!(Staking::force_era(), Forcing::ForceAlways); + assert_eq!(ForceEra::::get(), Forcing::ForceAlways); }); } @@ -2507,7 +2507,7 @@ fn offence_deselects_validator_even_when_slash_is_zero() { &[Perbill::from_percent(0)], ); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); assert!(is_disabled(11)); mock::start_active_era(1); @@ -2557,14 +2557,14 @@ fn validator_is_not_disabled_for_an_offence_in_previous_era() { &[Perbill::from_percent(0)], ); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); assert!(is_disabled(11)); mock::start_active_era(2); // the validator is not disabled in the new era Staking::validate(RuntimeOrigin::signed(11), Default::default()).unwrap(); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); assert!(>::contains_key(11)); assert!(Session::validators().contains(&11)); @@ -2585,7 +2585,7 @@ fn validator_is_not_disabled_for_an_offence_in_previous_era() { assert!(!is_disabled(11)); // and we are not forcing a new era - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_in_era( &[OffenceDetails { @@ -2601,7 +2601,7 @@ fn validator_is_not_disabled_for_an_offence_in_previous_era() { assert!(Validators::::iter().any(|(stash, _)| stash == 11)); assert!(!is_disabled(11)); // and we are still not forcing a new era - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); }); } @@ -2733,7 +2733,7 @@ fn dont_slash_if_fraction_is_zero() { // The validator hasn't been slashed. The new era is not forced. assert_eq!(asset::stakeable_balance::(&11), 1000); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); }); } @@ -2754,7 +2754,7 @@ fn only_slash_for_max_in_era() { // The validator has been slashed and has been force-chilled. assert_eq!(asset::stakeable_balance::(&11), 500); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_now( &[OffenceDetails { @@ -3033,7 +3033,7 @@ fn deferred_slashes_are_deferred() { ); // nominations are not removed regardless of the deferring. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); assert_eq!(asset::stakeable_balance::(&11), 1000); assert_eq!(asset::stakeable_balance::(&101), 2000); @@ -3078,7 +3078,7 @@ fn retroactive_deferred_slashes_two_eras_before() { mock::start_active_era(3); - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); System::reset_events(); on_offence_in_era( @@ -3169,7 +3169,7 @@ fn staker_cannot_bail_deferred_slash() { assert_ok!(Staking::chill(RuntimeOrigin::signed(101))); assert_ok!(Staking::unbond(RuntimeOrigin::signed(101), 500)); - assert_eq!(Staking::current_era().unwrap(), 1); + assert_eq!(CurrentEra::::get().unwrap(), 1); assert_eq!(active_era(), 1); assert_eq!( @@ -3191,14 +3191,14 @@ fn staker_cannot_bail_deferred_slash() { mock::start_active_era(2); assert_eq!(asset::stakeable_balance::(&11), 1000); assert_eq!(asset::stakeable_balance::(&101), 2000); - assert_eq!(Staking::current_era().unwrap(), 2); + assert_eq!(CurrentEra::::get().unwrap(), 2); assert_eq!(active_era(), 2); // no slash yet. mock::start_active_era(3); assert_eq!(asset::stakeable_balance::(&11), 1000); assert_eq!(asset::stakeable_balance::(&101), 2000); - assert_eq!(Staking::current_era().unwrap(), 3); + assert_eq!(CurrentEra::::get().unwrap(), 3); assert_eq!(active_era(), 3); // and cannot yet unbond: @@ -3378,7 +3378,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq!(asset::stakeable_balance::(&101), 2000); // 100 has approval for 11 as of now - assert!(Staking::nominators(101).unwrap().targets.contains(&11)); + assert!(Nominators::::get(101).unwrap().targets.contains(&11)); // 11 and 21 both have the support of 100 let exposure_11 = Staking::eras_stakers(active_era(), &11); @@ -3402,6 +3402,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid fraction: Perbill::from_percent(10), slash_era: 1 }, + Event::ValidatorDisabled { stash: 11 }, Event::Slashed { staker: 11, amount: 100 }, Event::Slashed { staker: 101, amount: 12 }, ] @@ -3443,8 +3444,8 @@ fn non_slashable_offence_disables_validator() { mock::start_active_era(1); assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); - let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); - let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_11 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &21); // offence with no slash associated on_offence_now( @@ -3453,7 +3454,7 @@ fn non_slashable_offence_disables_validator() { ); // it does NOT affect the nominator. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); // offence that slashes 25% of the bond on_offence_now( @@ -3462,7 +3463,7 @@ fn non_slashable_offence_disables_validator() { ); // it DOES NOT affect the nominator. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); assert_eq!( staking_events_since_last_call(), @@ -3474,11 +3475,13 @@ fn non_slashable_offence_disables_validator() { fraction: Perbill::from_percent(0), slash_era: 1 }, + Event::ValidatorDisabled { stash: 11 }, Event::SlashReported { validator: 21, fraction: Perbill::from_percent(25), slash_era: 1 }, + Event::ValidatorDisabled { stash: 21 }, Event::Slashed { staker: 21, amount: 250 }, Event::Slashed { staker: 101, amount: 94 } ] @@ -3501,11 +3504,12 @@ fn slashing_independent_of_disabling_validator() { mock::start_active_era(1); assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51]); - let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); - let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_11 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &21); - let now = Staking::active_era().unwrap().index; + let now = ActiveEra::::get().unwrap().index; + // --- Disable without a slash --- // offence with no slash associated on_offence_in_era( &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], @@ -3514,9 +3518,20 @@ fn slashing_independent_of_disabling_validator() { ); // nomination remains untouched. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); - // offence that slashes 25% of the bond + // first validator is disabled but not slashed + assert!(is_disabled(11)); + + // --- Slash without disabling --- + // offence that slashes 50% of the bond (setup for next slash) + on_offence_in_era( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::from_percent(50)], + now, + ); + + // offence that slashes 25% of the bond but does not disable on_offence_in_era( &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], &[Perbill::from_percent(25)], @@ -3524,7 +3539,11 @@ fn slashing_independent_of_disabling_validator() { ); // nomination remains untouched. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); + + // second validator is slashed but not disabled + assert!(!is_disabled(21)); + assert!(is_disabled(11)); assert_eq!( staking_events_since_last_call(), @@ -3536,6 +3555,14 @@ fn slashing_independent_of_disabling_validator() { fraction: Perbill::from_percent(0), slash_era: 1 }, + Event::ValidatorDisabled { stash: 11 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(50), + slash_era: 1 + }, + Event::Slashed { staker: 11, amount: 500 }, + Event::Slashed { staker: 101, amount: 62 }, Event::SlashReported { validator: 21, fraction: Perbill::from_percent(25), @@ -3545,11 +3572,6 @@ fn slashing_independent_of_disabling_validator() { Event::Slashed { staker: 101, amount: 94 } ] ); - - // first validator is disabled but not slashed - assert!(is_disabled(11)); - // second validator is slashed but not disabled - assert!(!is_disabled(21)); }); } @@ -3563,7 +3585,7 @@ fn offence_threshold_doesnt_trigger_new_era() { assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41]); assert_eq!( - UpToLimitDisablingStrategy::::disable_limit( + UpToLimitWithReEnablingDisablingStrategy::::disable_limit( Session::validators().len() ), 1 @@ -3572,13 +3594,13 @@ fn offence_threshold_doesnt_trigger_new_era() { // we have 4 validators and an offending validator threshold of 1/3, // even if the third validator commits an offence a new era should not be forced - let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); - let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); - let exposure_31 = Staking::eras_stakers(Staking::active_era().unwrap().index, &31); + let exposure_11 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &21); + let exposure_31 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &31); on_offence_now( &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], - &[Perbill::zero()], + &[Perbill::from_percent(50)], ); // 11 should be disabled because the byzantine threshold is 1 @@ -3622,8 +3644,8 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); assert_eq!(::SessionsPerEra::get(), 3); - let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); - let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_11 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(ActiveEra::::get().unwrap().index, &21); on_offence_now( &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], @@ -3631,7 +3653,7 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { ); // nominations are not updated. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); // validator 21 gets disabled since it got slashed assert!(is_disabled(21)); @@ -3648,7 +3670,7 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { ); // nominations are not updated. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); advance_session(); @@ -3713,7 +3735,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { let active_era = active_era(); // This is the latest planned era in staking, not the active era - let current_era = Staking::current_era().unwrap(); + let current_era = CurrentEra::::get().unwrap(); // Last kept is 1: assert!(current_era - HistoryDepth::get() == 1); @@ -3777,7 +3799,7 @@ fn zero_slash_keeps_nominators() { assert!(Validators::::iter().any(|(stash, _)| stash == 11)); assert!(is_disabled(11)); // and their nominations are kept. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!(Nominators::::get(101).unwrap().targets, vec![11, 21]); }); } @@ -3836,8 +3858,8 @@ fn six_session_delay() { assert_eq!(active_era(), init_active_era + 2); // That reward are correct - assert_eq!(Staking::eras_reward_points(init_active_era).total, 1); - assert_eq!(Staking::eras_reward_points(init_active_era + 1).total, 2); + assert_eq!(ErasRewardPoints::::get(init_active_era).total, 1); + assert_eq!(ErasRewardPoints::::get(init_active_era + 1).total, 2); }); } @@ -3978,6 +4000,7 @@ fn test_multi_page_payout_stakers_by_page() { assert!(matches!( staking_events_since_last_call().as_slice(), &[ + Event::PayoutStarted { era_index: 1, validator_stash: 11, page: 0, next: Some(1) }, .., Event::Rewarded { stash: 1063, dest: RewardDestination::Stash, amount: 111 }, Event::Rewarded { stash: 1064, dest: RewardDestination::Stash, amount: 111 }, @@ -4001,7 +4024,7 @@ fn test_multi_page_payout_stakers_by_page() { assert!(matches!( events.as_slice(), &[ - Event::PayoutStarted { era_index: 1, validator_stash: 11 }, + Event::PayoutStarted { era_index: 1, validator_stash: 11, page: 1, next: None }, Event::Rewarded { stash: 1065, dest: RewardDestination::Stash, amount: 111 }, Event::Rewarded { stash: 1066, dest: RewardDestination::Stash, amount: 111 }, .. @@ -4081,7 +4104,7 @@ fn test_multi_page_payout_stakers_by_page() { } } - assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]); + assert_eq!(ClaimedRewards::::get(14, &11), vec![0, 1]); let last_era = 99; let history_depth = HistoryDepth::get(); @@ -4096,7 +4119,7 @@ fn test_multi_page_payout_stakers_by_page() { // verify we clean up history as we go for era in 0..15 { - assert_eq!(Staking::claimed_rewards(era, &11), Vec::::new()); + assert_eq!(ClaimedRewards::::get(era, &11), Vec::::new()); } // verify only page 0 is marked as claimed @@ -4106,7 +4129,7 @@ fn test_multi_page_payout_stakers_by_page() { first_claimable_reward_era, 0 )); - assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(first_claimable_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed assert_ok!(Staking::payout_stakers_by_page( @@ -4115,7 +4138,7 @@ fn test_multi_page_payout_stakers_by_page() { first_claimable_reward_era, 1 )); - assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); + assert_eq!(ClaimedRewards::::get(first_claimable_reward_era, &11), vec![0, 1]); // verify only page 0 is marked as claimed assert_ok!(Staking::payout_stakers_by_page( @@ -4124,7 +4147,7 @@ fn test_multi_page_payout_stakers_by_page() { last_reward_era, 0 )); - assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(last_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed assert_ok!(Staking::payout_stakers_by_page( @@ -4133,15 +4156,15 @@ fn test_multi_page_payout_stakers_by_page() { last_reward_era, 1 )); - assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); + assert_eq!(ClaimedRewards::::get(last_reward_era, &11), vec![0, 1]); // Out of order claims works. assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 69, 0)); - assert_eq!(Staking::claimed_rewards(69, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(69, &11), vec![0]); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 23, 1)); - assert_eq!(Staking::claimed_rewards(23, &11), vec![1]); + assert_eq!(ClaimedRewards::::get(23, &11), vec![1]); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 42, 0)); - assert_eq!(Staking::claimed_rewards(42, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(42, &11), vec![0]); }); } @@ -4292,7 +4315,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { } } - assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]); + assert_eq!(ClaimedRewards::::get(14, &11), vec![0, 1]); let last_era = 99; let history_depth = HistoryDepth::get(); @@ -4307,7 +4330,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify we clean up history as we go for era in 0..15 { - assert_eq!(Staking::claimed_rewards(era, &11), Vec::::new()); + assert_eq!(ClaimedRewards::::get(era, &11), Vec::::new()); } // verify only page 0 is marked as claimed @@ -4316,7 +4339,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { 11, first_claimable_reward_era )); - assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); + assert_eq!(ClaimedRewards::::get(first_claimable_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed assert_ok!(Staking::payout_stakers( @@ -4324,7 +4347,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { 11, first_claimable_reward_era, )); - assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); + assert_eq!(ClaimedRewards::::get(first_claimable_reward_era, &11), vec![0, 1]); // change order and verify only page 1 is marked as claimed assert_ok!(Staking::payout_stakers_by_page( @@ -4333,12 +4356,12 @@ fn test_multi_page_payout_stakers_backward_compatible() { last_reward_era, 1 )); - assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1]); + assert_eq!(ClaimedRewards::::get(last_reward_era, &11), vec![1]); // verify page 0 is claimed even when explicit page is not passed assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era,)); - assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1, 0]); + assert_eq!(ClaimedRewards::::get(last_reward_era, &11), vec![1, 0]); // cannot claim any more pages assert_noop!( @@ -4362,10 +4385,10 @@ fn test_multi_page_payout_stakers_backward_compatible() { // Out of order claims works. assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2]); + assert_eq!(ClaimedRewards::::get(test_era, &11), vec![2]); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0]); + assert_eq!(ClaimedRewards::::get(test_era, &11), vec![2, 0]); // cannot claim page 2 again assert_noop!( @@ -4374,10 +4397,10 @@ fn test_multi_page_payout_stakers_backward_compatible() { ); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1]); + assert_eq!(ClaimedRewards::::get(test_era, &11), vec![2, 0, 1]); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1, 3]); + assert_eq!(ClaimedRewards::::get(test_era, &11), vec![2, 0, 1, 3]); }); } @@ -7008,7 +7031,8 @@ mod staking_interface { Error::::IncorrectSlashingSpans ); - let num_slashing_spans = Staking::slashing_spans(&11).map_or(0, |s| s.iter().count()); + let num_slashing_spans = + SlashingSpans::::get(&11).map_or(0, |s| s.iter().count()); assert_ok!(Staking::withdraw_unbonded( RuntimeOrigin::signed(11), num_slashing_spans as u32 @@ -8011,7 +8035,8 @@ mod ledger_recovery { assert_eq!(asset::staked::(&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. @@ -8274,11 +8299,14 @@ mod byzantine_threshold_disabling_strategy { use crate::{ tests::Test, ActiveEra, ActiveEraInfo, DisablingStrategy, UpToLimitDisablingStrategy, }; - use sp_staking::EraIndex; + use sp_runtime::Perbill; + use sp_staking::{offence::OffenceSeverity, EraIndex}; // Common test data - the stash of the offending validator, the era of the offence and the // active set const OFFENDER_ID: ::AccountId = 7; + const MAX_OFFENDER_SEVERITY: OffenceSeverity = OffenceSeverity(Perbill::from_percent(100)); + const MIN_OFFENDER_SEVERITY: OffenceSeverity = OffenceSeverity(Perbill::from_percent(0)); const SLASH_ERA: EraIndex = 1; const ACTIVE_SET: [::ValidatorId; 7] = [1, 2, 3, 4, 5, 6, 7]; const OFFENDER_VALIDATOR_IDX: u32 = 6; // the offender is with index 6 in the active set @@ -8290,48 +8318,766 @@ mod byzantine_threshold_disabling_strategy { pallet_session::Validators::::put(ACTIVE_SET.to_vec()); ActiveEra::::put(ActiveEraInfo { index: 2, start: None }); - let disable_offender = + let disabling_decision = >::decision( &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, SLASH_ERA, &initially_disabled, ); - assert!(disable_offender.is_none()); + assert!(disabling_decision.disable.is_none() && disabling_decision.reenable.is_none()); }); } #[test] fn dont_disable_beyond_byzantine_threshold() { sp_io::TestExternalities::default().execute_with(|| { - let initially_disabled = vec![1, 2]; + let initially_disabled = vec![(1, MIN_OFFENDER_SEVERITY), (2, MAX_OFFENDER_SEVERITY)]; pallet_session::Validators::::put(ACTIVE_SET.to_vec()); - let disable_offender = + let disabling_decision = >::decision( &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, SLASH_ERA, &initially_disabled, ); - assert!(disable_offender.is_none()); + assert!(disabling_decision.disable.is_none() && disabling_decision.reenable.is_none()); }); } #[test] fn disable_when_below_byzantine_threshold() { sp_io::TestExternalities::default().execute_with(|| { - let initially_disabled = vec![1]; + let initially_disabled = vec![(1, MAX_OFFENDER_SEVERITY)]; pallet_session::Validators::::put(ACTIVE_SET.to_vec()); - let disable_offender = + let disabling_decision = >::decision( &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, SLASH_ERA, &initially_disabled, ); - assert_eq!(disable_offender, Some(OFFENDER_VALIDATOR_IDX)); + assert_eq!(disabling_decision.disable, Some(OFFENDER_VALIDATOR_IDX)); + }); + } +} + +mod disabling_strategy_with_reenabling { + use crate::{ + tests::Test, ActiveEra, ActiveEraInfo, DisablingStrategy, + UpToLimitWithReEnablingDisablingStrategy, + }; + use sp_runtime::Perbill; + use sp_staking::{offence::OffenceSeverity, EraIndex}; + + // Common test data - the stash of the offending validator, the era of the offence and the + // active set + const OFFENDER_ID: ::AccountId = 7; + const MAX_OFFENDER_SEVERITY: OffenceSeverity = OffenceSeverity(Perbill::from_percent(100)); + const LOW_OFFENDER_SEVERITY: OffenceSeverity = OffenceSeverity(Perbill::from_percent(0)); + const SLASH_ERA: EraIndex = 1; + const ACTIVE_SET: [::ValidatorId; 7] = [1, 2, 3, 4, 5, 6, 7]; + const OFFENDER_VALIDATOR_IDX: u32 = 6; // the offender is with index 6 in the active set + + #[test] + fn dont_disable_for_ancient_offence() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + ActiveEra::::put(ActiveEraInfo { index: 2, start: None }); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_none() && disabling_decision.reenable.is_none()); + }); + } + + #[test] + fn disable_when_below_byzantine_threshold() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![(0, MAX_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + // Disable Offender and do not re-enable anyone + assert_eq!(disabling_decision.disable, Some(OFFENDER_VALIDATOR_IDX)); + assert_eq!(disabling_decision.reenable, None); + }); + } + + #[test] + fn reenable_arbitrary_on_equal_severity() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![(0, MAX_OFFENDER_SEVERITY), (1, MAX_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_some() && disabling_decision.reenable.is_some()); + // Disable 7 and enable 1 + assert_eq!(disabling_decision.disable.unwrap(), OFFENDER_VALIDATOR_IDX); + assert_eq!(disabling_decision.reenable.unwrap(), 0); + }); + } + + #[test] + fn do_not_reenable_higher_offenders() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![(0, MAX_OFFENDER_SEVERITY), (1, MAX_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + LOW_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_none() && disabling_decision.reenable.is_none()); + }); + } + + #[test] + fn reenable_lower_offenders() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![(0, LOW_OFFENDER_SEVERITY), (1, LOW_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_some() && disabling_decision.reenable.is_some()); + // Disable 7 and enable 1 + assert_eq!(disabling_decision.disable.unwrap(), OFFENDER_VALIDATOR_IDX); + assert_eq!(disabling_decision.reenable.unwrap(), 0); + }); + } + + #[test] + fn reenable_lower_offenders_unordered() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![(0, MAX_OFFENDER_SEVERITY), (1, LOW_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_some() && disabling_decision.reenable.is_some()); + // Disable 7 and enable 1 + assert_eq!(disabling_decision.disable.unwrap(), OFFENDER_VALIDATOR_IDX); + assert_eq!(disabling_decision.reenable.unwrap(), 1); + }); + } + + #[test] + fn update_severity() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = + vec![(OFFENDER_VALIDATOR_IDX, LOW_OFFENDER_SEVERITY), (0, MAX_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_some() && disabling_decision.reenable.is_none()); + // Disable 7 "again" AKA update their severity + assert_eq!(disabling_decision.disable.unwrap(), OFFENDER_VALIDATOR_IDX); + }); + } + + #[test] + fn update_cannot_lower_severity() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = + vec![(OFFENDER_VALIDATOR_IDX, MAX_OFFENDER_SEVERITY), (0, MAX_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + LOW_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_none() && disabling_decision.reenable.is_none()); + }); + } + + #[test] + fn no_accidental_reenablement_on_repeated_offence() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = + vec![(OFFENDER_VALIDATOR_IDX, MAX_OFFENDER_SEVERITY), (0, LOW_OFFENDER_SEVERITY)]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disabling_decision = + >::decision( + &OFFENDER_ID, + MAX_OFFENDER_SEVERITY, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disabling_decision.disable.is_none() && disabling_decision.reenable.is_none()); + }); + } +} + +#[test] +fn reenable_lower_offenders_mock() { + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); + + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_31 = Staking::eras_stakers(Staking::active_era().unwrap().index, &31); + + // offence with a low slash + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::from_percent(10)], + ); + on_offence_now( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(20)], + ); + + // it does NOT affect the nominator. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + + // both validators should be disabled + assert!(is_disabled(11)); + assert!(is_disabled(21)); + + // offence with a higher slash + on_offence_now( + &[OffenceDetails { offender: (31, exposure_31.clone()), reporters: vec![] }], + &[Perbill::from_percent(50)], + ); + + // First offender is no longer disabled + assert!(!is_disabled(11)); + // Mid offender is still disabled + assert!(is_disabled(21)); + // New offender is disabled + assert!(is_disabled(31)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(10), + slash_era: 1 + }, + Event::ValidatorDisabled { stash: 11 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 }, + Event::SlashReported { + validator: 21, + fraction: Perbill::from_percent(20), + slash_era: 1 + }, + Event::ValidatorDisabled { stash: 21 }, + Event::Slashed { staker: 21, amount: 200 }, + Event::Slashed { staker: 101, amount: 75 }, + Event::SlashReported { + validator: 31, + fraction: Perbill::from_percent(50), + slash_era: 1 + }, + Event::ValidatorDisabled { stash: 31 }, + Event::ValidatorReenabled { stash: 11 }, + Event::Slashed { staker: 31, amount: 250 }, + ] + ); + }); +} + +#[test] +fn do_not_reenable_higher_offenders_mock() { + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); + + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_31 = Staking::eras_stakers(Staking::active_era().unwrap().index, &31); + + // offence with a major slash + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::from_percent(50)], + ); + on_offence_now( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(50)], + ); + + // both validators should be disabled + assert!(is_disabled(11)); + assert!(is_disabled(21)); + + // offence with a minor slash + on_offence_now( + &[OffenceDetails { offender: (31, exposure_31.clone()), reporters: vec![] }], + &[Perbill::from_percent(10)], + ); + + // First and second offenders are still disabled + assert!(is_disabled(11)); + assert!(is_disabled(21)); + // New offender is not disabled as limit is reached and his prio is lower + assert!(!is_disabled(31)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(50), + slash_era: 1 + }, + Event::ValidatorDisabled { stash: 11 }, + Event::Slashed { staker: 11, amount: 500 }, + Event::Slashed { staker: 101, amount: 62 }, + Event::SlashReported { + validator: 21, + fraction: Perbill::from_percent(50), + slash_era: 1 + }, + Event::ValidatorDisabled { stash: 21 }, + Event::Slashed { staker: 21, amount: 500 }, + Event::Slashed { staker: 101, amount: 187 }, + Event::SlashReported { + validator: 31, + fraction: Perbill::from_percent(10), + slash_era: 1 + }, + Event::Slashed { staker: 31, amount: 50 }, + ] + ); + }); +} + +#[cfg(all(feature = "try-runtime", test))] +mod migration_tests { + use super::*; + use frame_support::traits::UncheckedOnRuntimeUpgrade; + use migrations::{v15, v16}; + + #[test] + fn migrate_v15_to_v16_with_try_runtime() { + ExtBuilder::default().validator_count(7).build_and_execute(|| { + // Initial setup: Create old `DisabledValidators` in the form of `Vec` + let old_disabled_validators = vec![1u32, 2u32]; + v15::DisabledValidators::::put(old_disabled_validators.clone()); + + // Run pre-upgrade checks + let pre_upgrade_result = v16::VersionUncheckedMigrateV15ToV16::::pre_upgrade(); + assert!(pre_upgrade_result.is_ok()); + let pre_upgrade_state = pre_upgrade_result.unwrap(); + + // Run the migration + v16::VersionUncheckedMigrateV15ToV16::::on_runtime_upgrade(); + + // Run post-upgrade checks + let post_upgrade_result = + v16::VersionUncheckedMigrateV15ToV16::::post_upgrade(pre_upgrade_state); + assert!(post_upgrade_result.is_ok()); + }); + } +} + +mod getters { + use crate::{ + mock::{self}, + pallet::pallet::{Invulnerables, MinimumValidatorCount, ValidatorCount}, + slashing, + tests::{Staking, Test}, + ActiveEra, ActiveEraInfo, BalanceOf, CanceledSlashPayout, ClaimedRewards, CurrentEra, + CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, ErasStakersClipped, + ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, ErasValidatorReward, ForceEra, + Forcing, Nominations, Nominators, Perbill, SlashRewardFraction, SlashingSpans, + ValidatorPrefs, Validators, + }; + use sp_staking::{EraIndex, Exposure, IndividualExposure, Page, SessionIndex}; + + #[test] + fn get_validator_count_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let v: u32 = 12; + ValidatorCount::::put(v); + + // when + let result = Staking::validator_count(); + + // then + assert_eq!(result, v); + }); + } + + #[test] + fn get_minimum_validator_count_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let v: u32 = 12; + MinimumValidatorCount::::put(v); + + // when + let result = Staking::minimum_validator_count(); + + // then + assert_eq!(result, v); + }); + } + + #[test] + fn get_invulnerables_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let v: Vec = vec![1, 2, 3]; + Invulnerables::::put(v.clone()); + + // when + let result = Staking::invulnerables(); + + // then + assert_eq!(result, v); + }); + } + + #[test] + fn get_validators_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let account_id: mock::AccountId = 1; + let validator_prefs = ValidatorPrefs::default(); + + Validators::::insert(account_id, validator_prefs.clone()); + + // when + let result = Staking::validators(&account_id); + + // then + assert_eq!(result, validator_prefs); + }); + } + + #[test] + fn get_nominators_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let account_id: mock::AccountId = 1; + let nominations: Nominations = Nominations { + targets: Default::default(), + submitted_in: Default::default(), + suppressed: false, + }; + + Nominators::::insert(account_id, nominations.clone()); + + // when + let result = Staking::nominators(account_id); + + // then + assert_eq!(result, Some(nominations)); + }); + } + + #[test] + fn get_current_era_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + CurrentEra::::put(era); + + // when + let result = Staking::current_era(); + + // then + assert_eq!(result, Some(era)); + }); + } + + #[test] + fn get_active_era_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era = ActiveEraInfo { index: 2, start: None }; + ActiveEra::::put(era); + + // when + let result: Option = Staking::active_era(); + + // then + if let Some(era_info) = result { + assert_eq!(era_info.index, 2); + assert_eq!(era_info.start, None); + } else { + panic!("Expected Some(era_info), got None"); + }; + }); + } + + #[test] + fn get_eras_start_session_index_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let session_index: SessionIndex = 14; + ErasStartSessionIndex::::insert(era, session_index); + + // when + let result = Staking::eras_start_session_index(era); + + // then + assert_eq!(result, Some(session_index)); + }); + } + + #[test] + fn get_eras_stakers_clipped_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let account_id: mock::AccountId = 1; + let exposure: Exposure> = Exposure { + total: 1125, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 125 }], + }; + ErasStakersClipped::::insert(era, account_id, exposure.clone()); + + // when + let result = Staking::eras_stakers_clipped(era, &account_id); + + // then + assert_eq!(result, exposure); + }); + } + + #[test] + fn get_claimed_rewards_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let account_id: mock::AccountId = 1; + let rewards = Vec::::new(); + ClaimedRewards::::insert(era, account_id, rewards.clone()); + + // when + let result = Staking::claimed_rewards(era, &account_id); + + // then + assert_eq!(result, rewards); + }); + } + + #[test] + fn get_eras_validator_prefs_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let account_id: mock::AccountId = 1; + let validator_prefs = ValidatorPrefs::default(); + + ErasValidatorPrefs::::insert(era, account_id, validator_prefs.clone()); + + // when + let result = Staking::eras_validator_prefs(era, &account_id); + + // then + assert_eq!(result, validator_prefs); + }); + } + + #[test] + fn get_eras_validator_reward_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let balance_of = BalanceOf::::default(); + + ErasValidatorReward::::insert(era, balance_of); + + // when + let result = Staking::eras_validator_reward(era); + + // then + assert_eq!(result, Some(balance_of)); + }); + } + + #[test] + fn get_eras_reward_points_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let reward_points = EraRewardPoints:: { + total: 1, + individual: vec![(11, 1)].into_iter().collect(), + }; + ErasRewardPoints::::insert(era, reward_points); + + // when + let result = Staking::eras_reward_points(era); + + // then + assert_eq!(result.total, 1); + }); + } + + #[test] + fn get_eras_total_stake_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let era: EraIndex = 12; + let balance_of = BalanceOf::::default(); + + ErasTotalStake::::insert(era, balance_of); + + // when + let result = Staking::eras_total_stake(era); + + // then + assert_eq!(result, balance_of); + }); + } + + #[test] + fn get_force_era_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let forcing = Forcing::NotForcing; + ForceEra::::put(forcing); + + // when + let result = Staking::force_era(); + + // then + assert_eq!(result, forcing); + }); + } + + #[test] + fn get_slash_reward_fraction_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let perbill = Perbill::one(); + SlashRewardFraction::::put(perbill); + + // when + let result = Staking::slash_reward_fraction(); + + // then + assert_eq!(result, perbill); + }); + } + + #[test] + fn get_canceled_payout_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let balance_of = BalanceOf::::default(); + CanceledSlashPayout::::put(balance_of); + + // when + let result = Staking::canceled_payout(); + + // then + assert_eq!(result, balance_of); + }); + } + + #[test] + fn get_slashing_spans_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let account_id: mock::AccountId = 1; + let spans = slashing::SlashingSpans::new(2); + SlashingSpans::::insert(account_id, spans); + + // when + let result: Option = Staking::slashing_spans(&account_id); + + // then + // simple check so as not to add extra macros to slashing::SlashingSpans struct + assert!(result.is_some()); + }); + } + + #[test] + fn get_current_planned_session_returns_value_from_storage() { + sp_io::TestExternalities::default().execute_with(|| { + // given + let session_index = SessionIndex::default(); + CurrentPlannedSession::::put(session_index); + + // when + let result = Staking::current_planned_session(); + + // then + assert_eq!(result, session_index); }); } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index cd4e7f973ce3..56f561679cfc 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -1584,4 +1584,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } -} +} \ No newline at end of file diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 8c82bc38da97..1f1f6fc5be3a 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -16,25 +16,25 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } -thousands = { optional = true, workspace = true } -zstd = { optional = true, workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } remote-externalities = { optional = true, workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } substrate-state-trie-migration-rpc = { optional = true, workspace = true, default-features = true } +thousands = { optional = true, workspace = true } +zstd = { optional = true, workspace = true } [dev-dependencies] -parking_lot = { workspace = true, default-features = true } -tokio = { features = ["macros"], workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } +tokio = { features = ["macros"], workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index 3fe5abb81031..61323b70b33d 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -249,13 +249,13 @@ pub mod pallet { if limits.item.is_zero() || limits.size.is_zero() { // handle this minor edge case, else we would call `migrate_tick` at least once. log!(warn, "limits are zero. stopping"); - return Ok(()) + return Ok(()); } while !self.exhausted(limits) && !self.finished() { if let Err(e) = self.migrate_tick() { log!(error, "migrate_until_exhaustion failed: {:?}", e); - return Err(e) + return Err(e); } } @@ -332,7 +332,7 @@ pub mod pallet { _ => { // defensive: there must be an ongoing top migration. frame_support::defensive!("cannot migrate child key."); - return Ok(()) + return Ok(()); }, }; @@ -374,7 +374,7 @@ pub mod pallet { Progress::Complete => { // defensive: there must be an ongoing top migration. frame_support::defensive!("cannot migrate top key."); - return Ok(()) + return Ok(()); }, }; @@ -669,7 +669,7 @@ pub mod pallet { // ensure that the migration witness data was correct. if real_size_upper < task.dyn_size { Self::slash(who, deposit)?; - return Ok(().into()) + return Ok(().into()); } Self::deposit_event(Event::::Migrated { @@ -957,6 +957,7 @@ pub mod pallet { mod benchmarks { use super::{pallet::Pallet as StateTrieMigration, *}; use alloc::vec; + use frame_benchmarking::v2::*; use frame_support::traits::fungible::{Inspect, Mutate}; // The size of the key seemingly makes no difference in the read/write time, so we make it @@ -970,8 +971,12 @@ mod benchmarks { stash } - frame_benchmarking::benchmarks! { - continue_migrate { + #[benchmarks] + mod inner_benchmarks { + use super::*; + + #[benchmark] + fn continue_migrate() -> Result<(), BenchmarkError> { // note that this benchmark should migrate nothing, as we only want the overhead weight // of the bookkeeping, and the migration cost itself is noted via the `dynamic_weight` // function. @@ -980,116 +985,151 @@ mod benchmarks { let stash = set_balance_for_deposit::(&caller, null.item); // Allow signed migrations. SignedMigrationMaxLimits::::put(MigrationLimits { size: 1024, item: 5 }); - }: _(frame_system::RawOrigin::Signed(caller.clone()), null, 0, StateTrieMigration::::migration_process()) - verify { + + #[extrinsic_call] + _( + frame_system::RawOrigin::Signed(caller.clone()), + null, + 0, + StateTrieMigration::::migration_process(), + ); + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); - assert_eq!(T::Currency::balance(&caller), stash) + assert_eq!(T::Currency::balance(&caller), stash); + + Ok(()) } - continue_migrate_wrong_witness { + #[benchmark] + fn continue_migrate_wrong_witness() -> Result<(), BenchmarkError> { let null = MigrationLimits::default(); let caller = frame_benchmarking::whitelisted_caller(); - let bad_witness = MigrationTask { progress_top: Progress::LastKey(vec![1u8].try_into().unwrap()), ..Default::default() }; - }: { - assert!( - StateTrieMigration::::continue_migrate( + let bad_witness = MigrationTask { + progress_top: Progress::LastKey(vec![1u8].try_into().unwrap()), + ..Default::default() + }; + #[block] + { + assert!(StateTrieMigration::::continue_migrate( frame_system::RawOrigin::Signed(caller).into(), null, 0, bad_witness, ) - .is_err() - ) - } - verify { - assert_eq!(StateTrieMigration::::migration_process(), Default::default()) + .is_err()); + } + + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); + + Ok(()) } - migrate_custom_top_success { + #[benchmark] + fn migrate_custom_top_success() -> Result<(), BenchmarkError> { let null = MigrationLimits::default(); let caller: T::AccountId = frame_benchmarking::whitelisted_caller(); let stash = set_balance_for_deposit::(&caller, null.item); - }: migrate_custom_top(frame_system::RawOrigin::Signed(caller.clone()), Default::default(), 0) - verify { + #[extrinsic_call] + migrate_custom_top( + frame_system::RawOrigin::Signed(caller.clone()), + Default::default(), + 0, + ); + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); - assert_eq!(T::Currency::balance(&caller), stash) + assert_eq!(T::Currency::balance(&caller), stash); + Ok(()) } - migrate_custom_top_fail { + #[benchmark] + fn migrate_custom_top_fail() -> Result<(), BenchmarkError> { let null = MigrationLimits::default(); let caller: T::AccountId = frame_benchmarking::whitelisted_caller(); let stash = set_balance_for_deposit::(&caller, null.item); // for tests, we need to make sure there is _something_ in storage that is being // migrated. - sp_io::storage::set(b"foo", vec![1u8;33].as_ref()); - }: { - assert!( - StateTrieMigration::::migrate_custom_top( + sp_io::storage::set(b"foo", vec![1u8; 33].as_ref()); + #[block] + { + assert!(StateTrieMigration::::migrate_custom_top( frame_system::RawOrigin::Signed(caller.clone()).into(), vec![b"foo".to_vec()], 1, - ).is_ok() - ); + ) + .is_ok()); + + frame_system::Pallet::::assert_last_event( + ::RuntimeEvent::from(crate::Event::Slashed { + who: caller.clone(), + amount: StateTrieMigration::::calculate_deposit_for(1u32), + }) + .into(), + ); + } - frame_system::Pallet::::assert_last_event( - ::RuntimeEvent::from(crate::Event::Slashed { - who: caller.clone(), - amount: StateTrieMigration::::calculate_deposit_for(1u32), - }).into(), - ); - } - verify { assert_eq!(StateTrieMigration::::migration_process(), Default::default()); // must have gotten slashed - assert!(T::Currency::balance(&caller) < stash) + assert!(T::Currency::balance(&caller) < stash); + + Ok(()) } - migrate_custom_child_success { + #[benchmark] + fn migrate_custom_child_success() -> Result<(), BenchmarkError> { let caller: T::AccountId = frame_benchmarking::whitelisted_caller(); let stash = set_balance_for_deposit::(&caller, 0); - }: migrate_custom_child( - frame_system::RawOrigin::Signed(caller.clone()), - StateTrieMigration::::childify(Default::default()), - Default::default(), - 0 - ) - verify { + + #[extrinsic_call] + migrate_custom_child( + frame_system::RawOrigin::Signed(caller.clone()), + StateTrieMigration::::childify(Default::default()), + Default::default(), + 0, + ); + assert_eq!(StateTrieMigration::::migration_process(), Default::default()); assert_eq!(T::Currency::balance(&caller), stash); + + Ok(()) } - migrate_custom_child_fail { + #[benchmark] + fn migrate_custom_child_fail() -> Result<(), BenchmarkError> { let caller: T::AccountId = frame_benchmarking::whitelisted_caller(); let stash = set_balance_for_deposit::(&caller, 1); // for tests, we need to make sure there is _something_ in storage that is being // migrated. - sp_io::default_child_storage::set(b"top", b"foo", vec![1u8;33].as_ref()); - }: { - assert!( - StateTrieMigration::::migrate_custom_child( + sp_io::default_child_storage::set(b"top", b"foo", vec![1u8; 33].as_ref()); + + #[block] + { + assert!(StateTrieMigration::::migrate_custom_child( frame_system::RawOrigin::Signed(caller.clone()).into(), StateTrieMigration::::childify("top"), vec![b"foo".to_vec()], 1, - ).is_ok() - ) - } - verify { + ) + .is_ok()); + } assert_eq!(StateTrieMigration::::migration_process(), Default::default()); // must have gotten slashed - assert!(T::Currency::balance(&caller) < stash) + assert!(T::Currency::balance(&caller) < stash); + Ok(()) } - process_top_key { - let v in 1 .. (4 * 1024 * 1024); - + #[benchmark] + fn process_top_key(v: Linear<1, { 4 * 1024 * 1024 }>) -> Result<(), BenchmarkError> { let value = alloc::vec![1u8; v as usize]; sp_io::storage::set(KEY, &value); - }: { - let data = sp_io::storage::get(KEY).unwrap(); - sp_io::storage::set(KEY, &data); - let _next = sp_io::storage::next_key(KEY); - assert_eq!(data, value); + #[block] + { + let data = sp_io::storage::get(KEY).unwrap(); + sp_io::storage::set(KEY, &data); + let _next = sp_io::storage::next_key(KEY); + assert_eq!(data, value); + } + + Ok(()) } impl_benchmark_test_suite!( @@ -1741,7 +1781,7 @@ pub(crate) mod remote_tests { let ((finished, weight), proof) = ext.execute_and_prove(|| { let weight = run_to_block::(now + One::one()).1; if StateTrieMigration::::migration_process().finished() { - return (true, weight) + return (true, weight); } duration += One::one(); now += One::one(); @@ -1768,7 +1808,7 @@ pub(crate) mod remote_tests { ext.commit_all().unwrap(); if finished { - break + break; } } diff --git a/substrate/frame/state-trie-migration/src/weights.rs b/substrate/frame/state-trie-migration/src/weights.rs index ddc9236f7af6..478960392bca 100644 --- a/substrate/frame/state-trie-migration/src/weights.rs +++ b/substrate/frame/state-trie-migration/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_state_trie_migration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -66,15 +66,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `StateTrieMigration::SignedMigrationMaxLimits` (r:1 w:0) /// Proof: `StateTrieMigration::SignedMigrationMaxLimits` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `StateTrieMigration::MigrationProcess` (r:1 w:1) /// Proof: `StateTrieMigration::MigrationProcess` (`max_values`: Some(1), `max_size`: Some(1042), added: 1537, mode: `MaxEncodedLen`) fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `3658` - // Minimum execution time: 18_293_000 picoseconds. - Weight::from_parts(18_577_000, 3658) + // Estimated: `3820` + // Minimum execution time: 19_111_000 picoseconds. + Weight::from_parts(19_611_000, 3820) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -84,53 +84,53 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 4_240_000 picoseconds. - Weight::from_parts(4_369_000, 1493) + // Minimum execution time: 4_751_000 picoseconds. + Weight::from_parts(5_052_000, 1493) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 11_909_000 picoseconds. - Weight::from_parts(12_453_000, 3658) + // Estimated: `3820` + // Minimum execution time: 11_907_000 picoseconds. + Weight::from_parts(12_264_000, 3820) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { // Proof Size summary in bytes: // Measured: `113` - // Estimated: `3658` - // Minimum execution time: 65_631_000 picoseconds. - Weight::from_parts(66_506_000, 3658) + // Estimated: `3820` + // Minimum execution time: 68_089_000 picoseconds. + Weight::from_parts(68_998_000, 3820) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn migrate_custom_child_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 12_208_000 picoseconds. - Weight::from_parts(12_690_000, 3658) + // Estimated: `3820` + // Minimum execution time: 12_021_000 picoseconds. + Weight::from_parts(12_466_000, 3820) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `3658` - // Minimum execution time: 66_988_000 picoseconds. - Weight::from_parts(68_616_000, 3658) + // Estimated: `3820` + // Minimum execution time: 69_553_000 picoseconds. + Weight::from_parts(71_125_000, 3820) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -139,12 +139,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `197 + v * (1 ±0)` - // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 5_365_000 picoseconds. - Weight::from_parts(5_460_000, 3662) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_150, 0).saturating_mul(v.into())) + // Measured: `192 + v * (1 ±0)` + // Estimated: `3657 + v * (1 ±0)` + // Minimum execution time: 5_418_000 picoseconds. + Weight::from_parts(5_526_000, 3657) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_914, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) @@ -156,15 +156,15 @@ impl WeightInfo for () { /// Storage: `StateTrieMigration::SignedMigrationMaxLimits` (r:1 w:0) /// Proof: `StateTrieMigration::SignedMigrationMaxLimits` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `StateTrieMigration::MigrationProcess` (r:1 w:1) /// Proof: `StateTrieMigration::MigrationProcess` (`max_values`: Some(1), `max_size`: Some(1042), added: 1537, mode: `MaxEncodedLen`) fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `3658` - // Minimum execution time: 18_293_000 picoseconds. - Weight::from_parts(18_577_000, 3658) + // Estimated: `3820` + // Minimum execution time: 19_111_000 picoseconds. + Weight::from_parts(19_611_000, 3820) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -174,53 +174,53 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 4_240_000 picoseconds. - Weight::from_parts(4_369_000, 1493) + // Minimum execution time: 4_751_000 picoseconds. + Weight::from_parts(5_052_000, 1493) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 11_909_000 picoseconds. - Weight::from_parts(12_453_000, 3658) + // Estimated: `3820` + // Minimum execution time: 11_907_000 picoseconds. + Weight::from_parts(12_264_000, 3820) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { // Proof Size summary in bytes: // Measured: `113` - // Estimated: `3658` - // Minimum execution time: 65_631_000 picoseconds. - Weight::from_parts(66_506_000, 3658) + // Estimated: `3820` + // Minimum execution time: 68_089_000 picoseconds. + Weight::from_parts(68_998_000, 3820) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) fn migrate_custom_child_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 12_208_000 picoseconds. - Weight::from_parts(12_690_000, 3658) + // Estimated: `3820` + // Minimum execution time: 12_021_000 picoseconds. + Weight::from_parts(12_466_000, 3820) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `3658` - // Minimum execution time: 66_988_000 picoseconds. - Weight::from_parts(68_616_000, 3658) + // Estimated: `3820` + // Minimum execution time: 69_553_000 picoseconds. + Weight::from_parts(71_125_000, 3820) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -229,12 +229,12 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 4194304]`. fn process_top_key(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `197 + v * (1 ±0)` - // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 5_365_000 picoseconds. - Weight::from_parts(5_460_000, 3662) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_150, 0).saturating_mul(v.into())) + // Measured: `192 + v * (1 ±0)` + // Estimated: `3657 + v * (1 ±0)` + // Minimum execution time: 5_418_000 picoseconds. + Weight::from_parts(5_526_000, 3657) + // Standard Error: 17 + .saturating_add(Weight::from_parts(1_914, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index e601881cd720..b1449fa24416 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -16,15 +16,15 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -sp-statement-store = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-api = { workspace = true } -sp-runtime = { workspace = true } -sp-io = { workspace = true } sp-core = { workspace = true } -log = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-statement-store = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 9b362019b29b..e2096bf0668a 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -18,9 +18,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/sudo/src/benchmarking.rs b/substrate/frame/sudo/src/benchmarking.rs index ff34cc3a7003..cf96562a30cf 100644 --- a/substrate/frame/sudo/src/benchmarking.rs +++ b/substrate/frame/sudo/src/benchmarking.rs @@ -110,7 +110,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok( + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok( Default::default() )) .unwrap() diff --git a/substrate/frame/sudo/src/extension.rs b/substrate/frame/sudo/src/extension.rs index 573de45ba32d..d2669de79e54 100644 --- a/substrate/frame/sudo/src/extension.rs +++ b/substrate/frame/sudo/src/extension.rs @@ -18,7 +18,7 @@ use crate::{Config, Key}; use codec::{Decode, Encode}; use core::{fmt, marker::PhantomData}; -use frame_support::{dispatch::DispatchInfo, ensure}; +use frame_support::{dispatch::DispatchInfo, ensure, pallet_prelude::TransactionSource}; use scale_info::TypeInfo; use sp_runtime::{ impl_tx_ext_default, @@ -94,6 +94,7 @@ where _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> Result< ( ValidTransaction, diff --git a/substrate/frame/sudo/src/weights.rs b/substrate/frame/sudo/src/weights.rs index ac5557e68a63..1b3bdbaaf42c 100644 --- a/substrate/frame/sudo/src/weights.rs +++ b/substrate/frame/sudo/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_sudo` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -65,10 +65,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn set_key() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 9_486_000 picoseconds. - Weight::from_parts(9_663_000, 1517) + // Minimum execution time: 10_426_000 picoseconds. + Weight::from_parts(10_822_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -76,30 +76,30 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 10_501_000 picoseconds. - Weight::from_parts(10_729_000, 1517) + // Minimum execution time: 11_218_000 picoseconds. + Weight::from_parts(11_501_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:0) /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo_as() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 10_742_000 picoseconds. - Weight::from_parts(11_003_000, 1517) + // Minimum execution time: 11_161_000 picoseconds. + Weight::from_parts(11_618_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:1) /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn remove_key() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 8_837_000 picoseconds. - Weight::from_parts(9_127_000, 1517) + // Minimum execution time: 9_617_000 picoseconds. + Weight::from_parts(10_092_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -107,10 +107,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn check_only_sudo_account() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 3_416_000 picoseconds. - Weight::from_parts(3_645_000, 1517) + // Minimum execution time: 4_903_000 picoseconds. + Weight::from_parts(5_046_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } } @@ -121,10 +121,10 @@ impl WeightInfo for () { /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn set_key() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 9_486_000 picoseconds. - Weight::from_parts(9_663_000, 1517) + // Minimum execution time: 10_426_000 picoseconds. + Weight::from_parts(10_822_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -132,30 +132,30 @@ impl WeightInfo for () { /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 10_501_000 picoseconds. - Weight::from_parts(10_729_000, 1517) + // Minimum execution time: 11_218_000 picoseconds. + Weight::from_parts(11_501_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:0) /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn sudo_as() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 10_742_000 picoseconds. - Weight::from_parts(11_003_000, 1517) + // Minimum execution time: 11_161_000 picoseconds. + Weight::from_parts(11_618_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:1) /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn remove_key() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 8_837_000 picoseconds. - Weight::from_parts(9_127_000, 1517) + // Minimum execution time: 9_617_000 picoseconds. + Weight::from_parts(10_092_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -163,10 +163,10 @@ impl WeightInfo for () { /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) fn check_only_sudo_account() -> Weight { // Proof Size summary in bytes: - // Measured: `165` + // Measured: `198` // Estimated: `1517` - // Minimum execution time: 3_416_000 picoseconds. - Weight::from_parts(3_645_000, 1517) + // Minimum execution time: 4_903_000 picoseconds. + Weight::from_parts(5_046_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index d7da034b3492..1f4fdd5d46cd 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -18,60 +18,59 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { workspace = true } binary-merkle-tree.workspace = true -serde = { features = ["alloc", "derive"], workspace = true } +bitflags = { workspace = true } codec = { features = [ "derive", "max-encoded-len", ], workspace = true } -scale-info = { features = [ - "derive", -], workspace = true } +docify = { workspace = true } +environmental = { workspace = true } frame-metadata = { features = [ "current", + "unstable", +], workspace = true } +frame-support-procedural = { workspace = true } +impl-trait-for-tuples = { workspace = true } +k256 = { features = ["ecdsa"], workspace = true } +log = { workspace = true } +macro_magic = { workspace = true } +paste = { workspace = true, default-features = true } +scale-info = { features = [ + "derive", ], workspace = true } +serde = { features = ["alloc", "derive"], workspace = true } +serde_json = { features = ["alloc"], workspace = true } +smallvec = { workspace = true, default-features = true } sp-api = { features = [ "frame-metadata", ], workspace = true } -sp-std = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { features = [ - "serde", -], workspace = true } -sp-tracing = { workspace = true } -sp-core = { workspace = true } sp-arithmetic = { workspace = true } -sp-inherents = { workspace = true } -sp-staking = { workspace = true } -sp-weights = { workspace = true } +sp-core = { workspace = true } +sp-crypto-hashing-proc-macro = { workspace = true, default-features = true } sp-debug-derive = { workspace = true } +sp-genesis-builder = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true } sp-metadata-ir = { workspace = true } -sp-trie = { workspace = true } -tt-call = { workspace = true } -macro_magic = { workspace = true } -frame-support-procedural = { workspace = true } -paste = { workspace = true, default-features = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-staking = { workspace = true } sp-state-machine = { optional = true, workspace = true } -bitflags = { workspace = true } -impl-trait-for-tuples = { workspace = true } -smallvec = { workspace = true, default-features = true } -log = { workspace = true } -sp-crypto-hashing-proc-macro = { workspace = true, default-features = true } -k256 = { features = ["ecdsa"], workspace = true } -environmental = { workspace = true } -sp-genesis-builder = { workspace = true } -serde_json = { features = ["alloc"], workspace = true } -docify = { workspace = true } +sp-std = { workspace = true } +sp-tracing = { workspace = true } +sp-trie = { workspace = true } +sp-weights = { workspace = true } static_assertions = { workspace = true, default-features = true } +tt-call = { workspace = true } aquamarine = { workspace = true } [dev-dependencies] +Inflector = { workspace = true } assert_matches = { workspace = true } -pretty_assertions = { workspace = true } -sp-timestamp = { workspace = true } frame-system = { workspace = true, default-features = true } +pretty_assertions = { workspace = true } sp-crypto-hashing = { workspace = true, default-features = true } -Inflector = { workspace = true } +sp-timestamp = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 51790062b2c2..624562187617 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -18,36 +18,36 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -derive-syn-parse = { workspace = true } -docify = { workspace = true } Inflector = { workspace = true } cfg-expr = { workspace = true } -itertools = { workspace = true } -proc-macro2 = { workspace = true } -quote = { workspace = true } -syn = { features = ["full", "parsing", "visit-mut"], workspace = true } +derive-syn-parse = { workspace = true } +docify = { workspace = true } +expander = { workspace = true } frame-support-procedural-tools = { workspace = true, default-features = true } +itertools = { workspace = true } macro_magic = { features = ["proc_support"], workspace = true } proc-macro-warning = { workspace = true } -expander = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } sp-crypto-hashing = { workspace = true } +syn = { features = ["full", "parsing", "visit-mut"], workspace = true } [dev-dependencies] codec = { features = [ "derive", "max-encoded-len", ], workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pretty_assertions = { workspace = true } regex = { workspace = true } -sp-metadata-ir = { workspace = true } scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } +sp-metadata-ir = { workspace = true } sp-runtime = { features = [ "serde", ], workspace = true } -frame-system = { workspace = true } -frame-support = { workspace = true } -pretty_assertions = { workspace = true } static_assertions = { workspace = true } [features] diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index c12fc20bc8b8..0b3bd5168865 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -113,11 +113,13 @@ pub fn expand_runtime_metadata( <#extrinsic as #scrate::traits::SignedTransactionBuilder>::Extension >(); + use #scrate::__private::metadata_ir::InternalImplRuntimeApis; + #scrate::__private::metadata_ir::MetadataIR { pallets: #scrate::__private::vec![ #(#pallets),* ], extrinsic: #scrate::__private::metadata_ir::ExtrinsicMetadataIR { ty, - version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION, + versions: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSIONS.into_iter().map(|ref_version| *ref_version).collect(), address_ty, call_ty, signature_ty, diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 17042c248780..087faf37252d 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -466,7 +466,6 @@ fn construct_runtime_final_expansion( // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` // when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!` // is called. - #[doc(hidden)] trait InternalConstructRuntime { #[inline(always)] @@ -477,6 +476,8 @@ fn construct_runtime_final_expansion( #[doc(hidden)] impl InternalConstructRuntime for &#name {} + use #scrate::__private::metadata_ir::InternalImplRuntimeApis; + #outer_event #outer_error diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs index 52f57cd2cd8b..1397b7266a18 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs @@ -21,7 +21,7 @@ use crate::{ }; use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; -use syn::{punctuated::Punctuated, token, Error}; +use syn::{punctuated::Punctuated, spanned::Spanned, token, Error}; impl Pallet { pub fn try_from( @@ -78,7 +78,18 @@ impl Pallet { }) .collect(); - let cfg_pattern = vec![]; + let cfg_pattern = item + .attrs + .iter() + .filter(|attr| attr.path().segments.first().map_or(false, |s| s.ident == "cfg")) + .map(|attr| { + attr.parse_args_with(|input: syn::parse::ParseStream| { + let input = input.parse::()?; + cfg_expr::Expression::parse(&input.to_string()) + .map_err(|e| syn::Error::new(attr.span(), e.to_string())) + }) + }) + .collect::>>()?; let docs = get_doc_literals(&item.attrs); diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index e61e17e8ac75..cbb2fde9e816 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -15,8 +15,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +frame-support-procedural-tools-derive = { workspace = true, default-features = true } proc-macro-crate = { workspace = true } proc-macro2 = { workspace = true } quote = { workspace = true } syn = { features = ["extra-traits", "full", "visit"], workspace = true } -frame-support-procedural-tools-derive = { workspace = true, default-features = true } diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 3678f958980a..483a3dce77f6 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -1403,7 +1403,7 @@ mod extension_weight_tests { let mut info = call.get_dispatch_info(); assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); info.extension_weight = ext.weight(&call); - let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); let res = call.dispatch(Some(0).into()); let mut post_info = res.unwrap(); assert!(post_info.actual_weight.is_none()); @@ -1430,7 +1430,7 @@ mod extension_weight_tests { assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); info.extension_weight = ext.weight(&call); let post_info = - ext.dispatch_transaction(Some(0).into(), call, &info, 0).unwrap().unwrap(); + ext.dispatch_transaction(Some(0).into(), call, &info, 0, 0).unwrap().unwrap(); // 1000 call weight + 50 + 200 + 0 assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1250, 0))); }); @@ -1449,7 +1449,7 @@ mod extension_weight_tests { assert_eq!(info.call_weight, Weight::from_parts(1000, 0)); info.extension_weight = ext.weight(&call); assert_eq!(info.total_weight(), Weight::from_parts(1600, 0)); - let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); let res = call.clone().dispatch(Some(0).into()); let mut post_info = res.unwrap(); // 500 actual call weight @@ -1469,7 +1469,7 @@ mod extension_weight_tests { // Second testcase let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200)); - let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); let res = call.clone().dispatch(Some(0).into()); let mut post_info = res.unwrap(); // 500 actual call weight @@ -1489,7 +1489,7 @@ mod extension_weight_tests { // Third testcase let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200)); - let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); let res = call.clone().dispatch(Some(0).into()); let mut post_info = res.unwrap(); // 500 actual call weight @@ -1509,7 +1509,7 @@ mod extension_weight_tests { // Fourth testcase let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300)); - let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); let res = call.clone().dispatch(Some(0).into()); let mut post_info = res.unwrap(); // 500 actual call weight diff --git a/substrate/frame/support/src/generate_genesis_config.rs b/substrate/frame/support/src/generate_genesis_config.rs index fc21e76c7427..283840d70c7c 100644 --- a/substrate/frame/support/src/generate_genesis_config.rs +++ b/substrate/frame/support/src/generate_genesis_config.rs @@ -23,41 +23,44 @@ use alloc::{borrow::Cow, format, string::String}; /// Represents the initialization method of a field within a struct. /// -/// This enum provides information about how it was initialized and the field name (as a `String`). +/// This enum provides information about how it was initialized. /// /// Intended to be used in `build_struct_json_patch` macro. #[derive(Debug)] -pub enum InitializedField<'a> { +pub enum InitilizationType { /// The field was partially initialized (e.g., specific fields within the struct were set /// manually). - Partial(Cow<'a, str>), - /// The field was fully initialized (e.g., using `new()` or `default()` like methods). - Full(Cow<'a, str>), + Partial, + /// The field was fully initialized (e.g., using `new()` or `default()` like methods + Full, } +/// This struct provides information about how the struct field was initialized and the field name +/// (as a `&str`). +/// +/// Intended to be used in `build_struct_json_patch` macro. +#[derive(Debug)] +pub struct InitializedField<'a>(InitilizationType, Cow<'a, str>); + impl<'a> InitializedField<'a> { /// Returns a name of the field. pub fn get_name(&'a self) -> &'a str { - match self { - Self::Partial(s) | Self::Full(s) => s, - } + &self.1 } /// Injects a prefix to the field name. pub fn add_prefix(&mut self, prefix: &str) { - match self { - Self::Partial(s) | Self::Full(s) => *s = format!("{prefix}.{s}").into(), - }; + self.1 = format!("{prefix}.{}", self.1).into() } /// Creates new partial field instiance. pub fn partial(s: &'a str) -> Self { - Self::Partial(s.into()) + Self(InitilizationType::Partial, s.into()) } /// Creates new full field instiance. pub fn full(s: &'a str) -> Self { - Self::Full(s.into()) + Self(InitilizationType::Full, s.into()) } } @@ -73,9 +76,15 @@ impl PartialEq for InitializedField<'_> { .map(|c| c.to_ascii_uppercase()) .eq(camel_chars.map(|c| c.to_ascii_uppercase())) } - match self { - InitializedField::Partial(field_name) | InitializedField::Full(field_name) => - field_name == other || compare_keys(field_name.chars(), other.chars()), + *self.1 == *other || compare_keys(self.1.chars(), other.chars()) + } +} + +impl<'a> From<(InitilizationType, &'a str)> for InitializedField<'a> { + fn from(value: (InitilizationType, &'a str)) -> Self { + match value.0 { + InitilizationType::Full => InitializedField::full(value.1), + InitilizationType::Partial => InitializedField::partial(value.1), } } } @@ -104,8 +113,8 @@ pub fn retain_initialized_fields( let current_key = if current_root.is_empty() { key.clone() } else { format!("{current_root}.{key}") }; match keys_to_retain.iter().find(|key| **key == current_key) { - Some(InitializedField::Full(_)) => true, - Some(InitializedField::Partial(_)) => { + Some(InitializedField(InitilizationType::Full, _)) => true, + Some(InitializedField(InitilizationType::Partial, _)) => { retain_initialized_fields(value, keys_to_retain, current_key.clone()); true }, @@ -208,89 +217,154 @@ pub fn retain_initialized_fields( #[macro_export] macro_rules! build_struct_json_patch { ( - $($struct_type:ident)::+ { $($tail:tt)* } + $($struct_type:ident)::+ { $($body:tt)* } ) => { { - let mut keys = $crate::__private::Vec::<$crate::generate_genesis_config::InitializedField>::default(); + let mut __keys = $crate::__private::Vec::<$crate::generate_genesis_config::InitializedField>::default(); #[allow(clippy::needless_update)] - let struct_instance = $crate::build_struct_json_patch!($($struct_type)::+, keys @ { $($tail)* }); - let mut json_value = - $crate::__private::serde_json::to_value(struct_instance).expect("serialization to json should work. qed"); - $crate::generate_genesis_config::retain_initialized_fields(&mut json_value, &keys, Default::default()); - json_value + let __struct_instance = $crate::build_struct_json_patch!($($struct_type)::+, __keys @ { $($body)* }).0; + let mut __json_value = + $crate::__private::serde_json::to_value(__struct_instance).expect("serialization to json should work. qed"); + $crate::generate_genesis_config::retain_initialized_fields(&mut __json_value, &__keys, Default::default()); + __json_value } }; - ($($struct_type:ident)::+, $all_keys:ident @ { $($tail:tt)* }) => { - $($struct_type)::+ { - ..$crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($tail)*) + ($($struct_type:ident)::+, $all_keys:ident @ { $($body:tt)* }) => { + { + let __value = $crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($body)*); + ( + $($struct_type)::+ { ..__value.0 }, + __value.1 + ) } }; - ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $($type:ident)::+ { $keyi:ident : $value:tt } ) => { - $($struct_type)::+ { - $key: { - $all_keys.push($crate::generate_genesis_config::InitializedField::partial(stringify!($key))); - $all_keys.push( - $crate::generate_genesis_config::InitializedField::full(concat!(stringify!($key), ".", stringify!($keyi))) - ); - $($type)::+ { - $keyi:$value, - ..Default::default() - } + ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $($type:ident)::+ { $($body:tt)* } ) => { + ( + $($struct_type)::+ { + $key: { + let mut __inner_keys = + $crate::__private::Vec::<$crate::generate_genesis_config::InitializedField>::default(); + let __value = $crate::build_struct_json_patch!($($type)::+, __inner_keys @ { $($body)* }); + for i in __inner_keys.iter_mut() { + i.add_prefix(stringify!($key)); + }; + $all_keys.push((__value.1,stringify!($key)).into()); + $all_keys.extend(__inner_keys); + __value.0 + }, + ..Default::default() }, - ..Default::default() + $crate::generate_genesis_config::InitilizationType::Partial + ) + }; + ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $($type:ident)::+ { $($body:tt)* }, $($tail:tt)*) => { + { + let mut __initialization_type; + ( + $($struct_type)::+ { + $key : { + let mut __inner_keys = + $crate::__private::Vec::<$crate::generate_genesis_config::InitializedField>::default(); + let __value = $crate::build_struct_json_patch!($($type)::+, __inner_keys @ { $($body)* }); + $all_keys.push((__value.1,stringify!($key)).into()); + + for i in __inner_keys.iter_mut() { + i.add_prefix(stringify!($key)); + }; + $all_keys.extend(__inner_keys); + __value.0 + }, + .. { + let (__value, __tmp) = + $crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($tail)*); + __initialization_type = __tmp; + __value + } + }, + __initialization_type + ) } }; - ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $($type:ident)::+ { $($body:tt)* } ) => { - $($struct_type)::+ { - $key: { - $all_keys.push($crate::generate_genesis_config::InitializedField::partial(stringify!($key))); - let mut inner_keys = $crate::__private::Vec::<$crate::generate_genesis_config::InitializedField>::default(); - let value = $crate::build_struct_json_patch!($($type)::+, inner_keys @ { $($body)* }); - for i in inner_keys.iter_mut() { - i.add_prefix(stringify!($key)); - }; - $all_keys.extend(inner_keys); - value - }, - ..Default::default() + ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $value:expr, $($tail:tt)* ) => { + { + let mut __initialization_type; + ( + $($struct_type)::+ { + $key: { + $all_keys.push($crate::generate_genesis_config::InitializedField::full( + stringify!($key)) + ); + $value + }, + .. { + let (__value, __tmp) = + $crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($tail)*); + __initialization_type = __tmp; + __value + } + }, + __initialization_type + ) } }; - ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $($type:ident)::+ { $($body:tt)* }, $($tail:tt)* ) => { - $($struct_type)::+ { - $key : { - $all_keys.push($crate::generate_genesis_config::InitializedField::partial(stringify!($key))); - let mut inner_keys = $crate::__private::Vec::<$crate::generate_genesis_config::InitializedField>::default(); - let value = $crate::build_struct_json_patch!($($type)::+, inner_keys @ { $($body)* }); - for i in inner_keys.iter_mut() { - i.add_prefix(stringify!($key)); - }; - $all_keys.extend(inner_keys); - value + ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $value:expr ) => { + ( + $($struct_type)::+ { + $key: { + $all_keys.push($crate::generate_genesis_config::InitializedField::full(stringify!($key))); + $value + }, + ..Default::default() }, - .. $crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($tail)*) + $crate::generate_genesis_config::InitilizationType::Partial + ) + }; + // field init shorthand + ($($struct_type:ident)::+, $all_keys:ident @ $key:ident, $($tail:tt)* ) => { + { + let __update = $crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($tail)*); + ( + $($struct_type)::+ { + $key: { + $all_keys.push($crate::generate_genesis_config::InitializedField::full( + stringify!($key)) + ); + $key + }, + ..__update.0 + }, + __update.1 + ) } }; - ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $value:expr, $($tail:tt)* ) => { - $($struct_type)::+ { - $key: { - $all_keys.push($crate::generate_genesis_config::InitializedField::full(stringify!($key))); - $value + ($($struct_type:ident)::+, $all_keys:ident @ $key:ident ) => { + ( + $($struct_type)::+ { + $key: { + $all_keys.push($crate::generate_genesis_config::InitializedField::full(stringify!($key))); + $key + }, + ..Default::default() }, - ..$crate::build_struct_json_patch!($($struct_type)::+, $all_keys @ $($tail)*) - } + $crate::generate_genesis_config::InitilizationType::Partial + ) }; - ($($struct_type:ident)::+, $all_keys:ident @ $key:ident: $value:expr ) => { - $($struct_type)::+ { - $key: { - $all_keys.push($crate::generate_genesis_config::InitializedField::full(stringify!($key))); - $value + // update struct + ($($struct_type:ident)::+, $all_keys:ident @ ..$update:expr ) => { + ( + $($struct_type)::+ { + ..$update }, - ..Default::default() - } + $crate::generate_genesis_config::InitilizationType::Full + ) }; - ($($struct_type:ident)::+, $all_keys:ident @ $(,)?) => { - $($struct_type)::+ { ..Default::default() } + ( + $($struct_type)::+ { + ..Default::default() + }, + $crate::generate_genesis_config::InitilizationType::Partial + ) }; } @@ -401,11 +475,8 @@ mod test { macro_rules! test { ($($struct:ident)::+ { $($v:tt)* }, { $($j:tt)* } ) => {{ - println!("--"); let expected = serde_json::json!({ $($j)* }); - println!("json: {}", serde_json::to_string_pretty(&expected).unwrap()); let value = build_struct_json_patch!($($struct)::+ { $($v)* }); - println!("gc: {}", serde_json::to_string_pretty(&value).unwrap()); assert_eq!(value, expected); }}; } @@ -415,6 +486,7 @@ mod test { let t = 5; const C: u32 = 5; test!(TestStruct { b: 5 }, { "b": 5 }); + test!(TestStruct { b: 5, }, { "b": 5 }); #[allow(unused_braces)] { test!(TestStruct { b: { 4 + 34 } } , { "b": 38 }); @@ -705,6 +777,324 @@ mod test { ); } + #[test] + fn test_generate_config_macro_field_init_shorthand() { + { + let x = 5; + test!(TestStruct { s: S { x } }, { "s": { "x": 5 } }); + } + { + let s = nested_mod::InsideMod { a: 34, b: 8 }; + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + s, + a: 32, + } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32, "s": { "a": 34, "b": 8} } + } + ); + } + { + let s = nested_mod::InsideMod { a: 34, b: 8 }; + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + a: 32, + s, + } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32, "s": { "a": 34, "b": 8} } + } + ); + } + } + + #[test] + fn test_generate_config_macro_struct_update() { + { + let s = S { x: 5 }; + test!(TestStruct { s: S { ..s } }, { "s": { "x": 5 } }); + } + { + mod nested { + use super::*; + pub fn function() -> S { + S { x: 5 } + } + } + test!(TestStruct { s: S { ..nested::function() } }, { "s": { "x": 5 } }); + } + { + let s = nested_mod::InsideMod { a: 34, b: 8 }; + let s1 = nested_mod::InsideMod { a: 34, b: 8 }; + test!( + TestStruct { + t: nested_mod::InsideMod { ..s1 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + s, + a: 32, + } + }, + { + "t" : { "a": 34, "b": 8 }, + "u" : { "a": 32, "s": { "a": 34, "b": 8} } + } + ); + } + { + let i3 = nested_mod::nested_mod2::nested_mod3::InsideMod3 { + a: 1, + b: 2, + s: nested_mod::InsideMod { a: 55, b: 88 }, + }; + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + a: 32, + ..i3 + } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32, "b": 2, "s": { "a": 55, "b": 88} } + } + ); + } + { + let s = nested_mod::InsideMod { a: 34, b: 8 }; + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + a: 32, + s: nested_mod::InsideMod { + b: 66, + ..s + } + } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32, "s": { "a": 34, "b": 66} } + } + ); + } + { + let s = nested_mod::InsideMod { a: 34, b: 8 }; + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + s: nested_mod::InsideMod { + b: 66, + ..s + }, + a: 32 + } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32, "s": { "a": 34, "b": 66} } + } + ); + } + } + + #[test] + fn test_generate_config_macro_with_execution_order() { + #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq)] + struct X { + x: Vec, + x2: Vec, + y2: Y, + } + #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq)] + struct Y { + y: Vec, + } + #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq)] + struct Z { + a: u32, + x: X, + y: Y, + } + { + let v = vec![1, 2, 3]; + test!(Z { a: 0, x: X { x: v }, }, { + "a": 0, "x": { "x": [1,2,3] } + }); + } + { + let v = vec![1, 2, 3]; + test!(Z { a: 3, x: X { x: v.clone() }, y: Y { y: v } }, { + "a": 3, "x": { "x": [1,2,3] }, "y": { "y": [1,2,3] } + }); + } + { + let v = vec![1, 2, 3]; + test!(Z { a: 3, x: X { y2: Y { y: v.clone() }, x: v.clone() }, y: Y { y: v } }, { + "a": 3, "x": { "x": [1,2,3], "y2":{ "y":[1,2,3] } }, "y": { "y": [1,2,3] } + }); + } + { + let v = vec![1, 2, 3]; + test!(Z { a: 3, y: Y { y: v.clone() }, x: X { y2: Y { y: v.clone() }, x: v }, }, { + "a": 3, "x": { "x": [1,2,3], "y2":{ "y":[1,2,3] } }, "y": { "y": [1,2,3] } + }); + } + { + let v = vec![1, 2, 3]; + test!( + Z { + y: Y { + y: v.clone() + }, + x: X { + y2: Y { + y: v.clone() + }, + x: v.clone(), + x2: v.clone() + }, + }, + { + "x": { + "x": [1,2,3], + "x2": [1,2,3], + "y2": { + "y":[1,2,3] + } + }, + "y": { + "y": [1,2,3] + } + }); + } + { + let v = vec![1, 2, 3]; + test!( + Z { + y: Y { + y: v.clone() + }, + x: X { + y2: Y { + y: v.clone() + }, + x: v + }, + }, + { + "x": { + "x": [1,2,3], + "y2": { + "y":[1,2,3] + } + }, + "y": { + "y": [1,2,3] + } + }); + } + { + let mut v = vec![0, 1, 2]; + let f = |vec: &mut Vec| -> Vec { + vec.iter_mut().for_each(|x| *x += 1); + vec.clone() + }; + let z = Z { + a: 0, + y: Y { y: f(&mut v) }, + x: X { y2: Y { y: f(&mut v) }, x: f(&mut v), x2: vec![] }, + }; + let z_expected = Z { + a: 0, + y: Y { y: vec![1, 2, 3] }, + x: X { y2: Y { y: vec![2, 3, 4] }, x: vec![3, 4, 5], x2: vec![] }, + }; + assert_eq!(z, z_expected); + v = vec![0, 1, 2]; + println!("{z:?}"); + test!( + Z { + y: Y { + y: f(&mut v) + }, + x: X { + y2: Y { + y: f(&mut v) + }, + x: f(&mut v) + }, + }, + { + "y": { + "y": [1,2,3] + }, + "x": { + "y2": { + "y":[2,3,4] + }, + "x": [3,4,5], + }, + }); + } + { + let mut v = vec![0, 1, 2]; + let f = |vec: &mut Vec| -> Vec { + vec.iter_mut().for_each(|x| *x += 1); + vec.clone() + }; + let z = Z { + a: 0, + y: Y { y: f(&mut v) }, + x: X { y2: Y { y: f(&mut v) }, x: f(&mut v), x2: f(&mut v) }, + }; + let z_expected = Z { + a: 0, + y: Y { y: vec![1, 2, 3] }, + x: X { y2: Y { y: vec![2, 3, 4] }, x: vec![3, 4, 5], x2: vec![4, 5, 6] }, + }; + assert_eq!(z, z_expected); + v = vec![0, 1, 2]; + println!("{z:?}"); + test!( + Z { + y: Y { + y: f(&mut v) + }, + x: X { + y2: Y { + y: f(&mut v) + }, + x: f(&mut v), + x2: f(&mut v) + }, + }, + { + "y": { + "y": [1,2,3] + }, + "x": { + "y2": { + "y":[2,3,4] + }, + "x": [3,4,5], + "x2": [4,5,6], + }, + }); + } + } + #[test] fn test_generate_config_macro_with_nested_mods() { test!( @@ -797,7 +1187,6 @@ mod retain_keys_test { ( $s:literal ) => { let field = InitializedField::full($s); let cc = inflector::cases::camelcase::to_camel_case($s); - println!("field: {:?}, cc: {}", field, cc); assert_eq!(field,cc); } ; ( &[ $f:literal $(, $r:literal)* ]) => { @@ -808,7 +1197,6 @@ mod retain_keys_test { .map(|s| inflector::cases::camelcase::to_camel_case(s)) .collect::>() .join("."); - println!("field: {:?}, cc: {}", field, cc); assert_eq!(field,cc); } ; ); diff --git a/substrate/frame/support/src/genesis_builder_helper.rs b/substrate/frame/support/src/genesis_builder_helper.rs index 662ea2cb1862..38b339eb9329 100644 --- a/substrate/frame/support/src/genesis_builder_helper.rs +++ b/substrate/frame/support/src/genesis_builder_helper.rs @@ -21,16 +21,15 @@ extern crate alloc; -use alloc::vec::Vec; +use alloc::{format, vec::Vec}; use frame_support::traits::BuildGenesisConfig; use sp_genesis_builder::{PresetId, Result as BuildResult}; -use sp_runtime::format_runtime_string; /// Build `GenesisConfig` from a JSON blob not using any defaults and store it in the storage. For /// more info refer to [`sp_genesis_builder::GenesisBuilder::build_state`]. pub fn build_state(json: Vec) -> BuildResult { - let gc = serde_json::from_slice::(&json) - .map_err(|e| format_runtime_string!("Invalid JSON blob: {}", e))?; + let gc = + serde_json::from_slice::(&json).map_err(|e| format!("Invalid JSON blob: {}", e))?; ::build(&gc); Ok(()) } @@ -41,7 +40,7 @@ pub fn build_state(json: Vec) -> BuildResult { /// to [`sp_genesis_builder::GenesisBuilder::get_preset`]. pub fn get_preset( name: &Option, - preset_for_name: impl FnOnce(&sp_genesis_builder::PresetId) -> Option>, + preset_for_name: impl FnOnce(&PresetId) -> Option>, ) -> Option> where GC: BuildGenesisConfig + Default, diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 2e7ea0a07d7d..c64987b17d35 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -904,8 +904,9 @@ pub mod pallet_prelude { StorageList, }, traits::{ - BuildGenesisConfig, ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, - IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, Task, TypedGet, + BuildGenesisConfig, ConstU32, ConstUint, EnsureOrigin, Get, GetDefault, + GetStorageVersion, Hooks, IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, + Task, TypedGet, }, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, PartialEqNoBound, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, @@ -1882,11 +1883,16 @@ pub mod pallet_macros { /// } /// ``` /// - /// Please note that this only works for signed dispatchables and requires a signed + /// Please note that this only works for signed dispatchables and requires a transaction /// extension such as [`pallet_skip_feeless_payment::SkipCheckIfFeeless`] to wrap the /// existing payment extension. Else, this is completely ignored and the dispatchable is /// still charged. /// + /// Also this will not allow accountless caller to send a transaction if some transaction + /// extension such as `frame_system::CheckNonce` is used. + /// Extensions such as `frame_system::CheckNonce` require a funded account to validate + /// the transaction. + /// /// ### Macro expansion /// /// The macro implements the [`pallet_skip_feeless_payment::CheckIfFeeless`] trait on the diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 635036d488df..728426cc84c7 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -57,13 +57,13 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter mod misc; pub use misc::{ defensive_prelude::{self, *}, - AccountTouch, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, - ConstU16, ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating, - DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, - ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, InherentBuilder, - IsInherent, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, - PrivilegeCmp, SameOrOther, SignedTransactionBuilder, Time, TryCollect, TryDrop, TypedGet, - UnixTime, VariantCount, VariantCountOf, WrapperKeepOpaque, WrapperOpaque, + AccountTouch, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstInt, + ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, ConstUint, DefensiveMax, DefensiveMin, + DefensiveSaturating, DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, + EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, + InherentBuilder, IsInherent, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, + OnNewAccount, PrivilegeCmp, SameOrOther, SignedTransactionBuilder, Time, TryCollect, TryDrop, + TypedGet, UnixTime, VariantCount, VariantCountOf, WrapperKeepOpaque, WrapperOpaque, }; #[allow(deprecated)] pub use misc::{PreimageProvider, PreimageRecipient}; @@ -110,7 +110,7 @@ pub use dispatch::{ }; mod voting; -pub use voting::{ClassCountOf, PollStatus, Polling, VoteTally}; +pub use voting::{ClassCountOf, NoOpPoll, PollStatus, Polling, VoteTally}; mod preimages; pub use preimages::{Bounded, BoundedInline, FetchResult, QueryPreimage, StorePreimage}; diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index a914b3a914c1..0dc3abdce956 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -28,8 +28,8 @@ use sp_core::bounded::bounded_vec::TruncateFrom; use core::cmp::Ordering; #[doc(hidden)] pub use sp_runtime::traits::{ - ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, - ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, + ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstInt, ConstU128, ConstU16, + ConstU32, ConstU64, ConstU8, ConstUint, Get, GetDefault, TryCollect, TypedGet, }; use sp_runtime::{traits::Block as BlockT, DispatchError}; diff --git a/substrate/frame/support/src/traits/voting.rs b/substrate/frame/support/src/traits/voting.rs index 958ef5dce6c1..697134e4ca47 100644 --- a/substrate/frame/support/src/traits/voting.rs +++ b/substrate/frame/support/src/traits/voting.rs @@ -19,7 +19,7 @@ //! votes. use crate::dispatch::Parameter; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use codec::{HasCompact, MaxEncodedLen}; use sp_arithmetic::Perbill; use sp_runtime::{traits::Member, DispatchError}; @@ -126,3 +126,49 @@ pub trait Polling { (Self::classes().into_iter().next().expect("Always one class"), u32::max_value()) } } + +/// NoOp polling is required if pallet-referenda functionality not needed. +pub struct NoOpPoll; +impl Polling for NoOpPoll { + type Index = u8; + type Votes = u32; + type Class = u16; + type Moment = u64; + + fn classes() -> Vec { + vec![] + } + + fn as_ongoing(_index: Self::Index) -> Option<(Tally, Self::Class)> { + None + } + + fn access_poll( + _index: Self::Index, + f: impl FnOnce(PollStatus<&mut Tally, Self::Moment, Self::Class>) -> R, + ) -> R { + f(PollStatus::None) + } + + fn try_access_poll( + _index: Self::Index, + f: impl FnOnce(PollStatus<&mut Tally, Self::Moment, Self::Class>) -> Result, + ) -> Result { + f(PollStatus::None) + } + + #[cfg(feature = "runtime-benchmarks")] + fn create_ongoing(_class: Self::Class) -> Result { + Err(()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn end_ongoing(_index: Self::Index, _approved: bool) -> Result<(), ()> { + Err(()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn max_ongoing() -> (Self::Class, u32) { + (0, 0) + } +} diff --git a/substrate/frame/support/src/weights/block_weights.rs b/substrate/frame/support/src/weights/block_weights.rs index 38f2ba3f023d..b4c12aa5d421 100644 --- a/substrate/frame/support/src/weights/block_weights.rs +++ b/substrate/frame/support/src/weights/block_weights.rs @@ -16,8 +16,8 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08 (Y/M/D) -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! DATE: 2024-11-08 (Y/M/D) +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` @@ -39,21 +39,21 @@ use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { - /// Time to execute an empty block. + /// Weight of executing an empty block. /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 440_235, 661_535 - /// Average: 453_383 - /// Median: 449_925 - /// Std-Dev: 22021.99 + /// Min, Max: 419_969, 685_012 + /// Average: 431_614 + /// Median: 427_388 + /// Std-Dev: 26437.34 /// /// Percentiles nanoseconds: - /// 99th: 474_045 - /// 95th: 466_455 - /// 75th: 455_056 + /// 99th: 456_205 + /// 95th: 443_420 + /// 75th: 431_833 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(453_383), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(431_614), 0); } #[cfg(test)] diff --git a/substrate/frame/support/src/weights/extrinsic_weights.rs b/substrate/frame/support/src/weights/extrinsic_weights.rs index 75c7ffa60705..95d966a412d0 100644 --- a/substrate/frame/support/src/weights/extrinsic_weights.rs +++ b/substrate/frame/support/src/weights/extrinsic_weights.rs @@ -16,8 +16,8 @@ // limitations under the License. //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08 (Y/M/D) -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! DATE: 2024-11-08 (Y/M/D) +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` @@ -39,21 +39,21 @@ use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { - /// Time to execute a NO-OP extrinsic, for example `System::remark`. + /// Weight of executing a NO-OP extrinsic, for example `System::remark`. /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 106_559, 107_788 - /// Average: 107_074 - /// Median: 107_067 - /// Std-Dev: 242.67 + /// Min, Max: 107_464, 109_127 + /// Average: 108_157 + /// Median: 108_119 + /// Std-Dev: 353.52 /// /// Percentiles nanoseconds: - /// 99th: 107_675 - /// 95th: 107_513 - /// 75th: 107_225 + /// 99th: 109_041 + /// 95th: 108_748 + /// 75th: 108_405 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(107_074), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(108_157), 0); } #[cfg(test)] diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 2187ee22b395..ca122e6bd544 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -15,26 +15,26 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -static_assertions = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true } codec = { features = ["derive"], workspace = true } +frame-benchmarking = { workspace = true } +frame-executive = { workspace = true } +frame-metadata = { features = ["current", "unstable"], workspace = true } +frame-support = { features = ["experimental"], workspace = true } +frame-system = { workspace = true } +pretty_assertions = { workspace = true } +rustversion = { workspace = true } scale-info = { features = ["derive"], workspace = true } -frame-metadata = { features = ["current"], workspace = true } +serde = { features = ["derive"], workspace = true } sp-api = { workspace = true } sp-arithmetic = { workspace = true } +sp-core = { workspace = true } sp-io = { workspace = true } -sp-state-machine = { optional = true, workspace = true, default-features = true } -frame-support = { features = ["experimental"], workspace = true } -frame-benchmarking = { workspace = true } +sp-metadata-ir = { workspace = true } sp-runtime = { workspace = true } -sp-core = { workspace = true } +sp-state-machine = { optional = true, workspace = true, default-features = true } sp-version = { workspace = true } -sp-metadata-ir = { workspace = true } +static_assertions = { workspace = true, default-features = true } trybuild = { features = ["diff"], workspace = true } -pretty_assertions = { workspace = true } -rustversion = { workspace = true } -frame-system = { workspace = true } -frame-executive = { workspace = true } # The "std" feature for this pallet is never activated on purpose, in order to test construct_runtime error message test-pallet = { workspace = true } diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 9e0a7ff7c675..988135d64dbf 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } sp-version = { workspace = true } diff --git a/substrate/frame/support/test/compile_pass/src/lib.rs b/substrate/frame/support/test/compile_pass/src/lib.rs index 677ef4e94c89..31f3126b8dd5 100644 --- a/substrate/frame/support/test/compile_pass/src/lib.rs +++ b/substrate/frame/support/test/compile_pass/src/lib.rs @@ -21,20 +21,22 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{ConstU16, ConstU32, ConstU64, Everything}, }; use sp_core::{sr25519, H256}; use sp_runtime::{ - create_runtime_str, generic, + generic, traits::{BlakeTwo256, IdentityLookup, Verify}, }; use sp_version::RuntimeVersion; pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("frame-support-test-compile-pass"), - impl_name: create_runtime_str!("substrate-frame-support-test-compile-pass-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("frame-support-test-compile-pass"), + impl_name: alloc::borrow::Cow::Borrowed("substrate-frame-support-test-compile-pass-runtime"), authoring_version: 0, spec_version: 0, impl_version: 0, diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index f03377dc21eb..dc5558b1d4b8 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [features] 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 55b19ac1a652..726b09cf54c9 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 @@ -751,7 +751,7 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied = 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 + --> $CARGO/serde-1.0.214/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 diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index b0b83f772499..9df1f461bba2 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -53,6 +53,9 @@ parameter_types! { /// Latest stable metadata version used for testing. const LATEST_METADATA_VERSION: u32 = 15; +/// Unstable metadata version. +const UNSTABLE_METADATA_VERSION: u32 = u32::MAX; + pub struct SomeType1; impl From for u64 { fn from(_t: SomeType1) -> Self { @@ -799,20 +802,43 @@ where } } -frame_support::construct_runtime!( - pub struct Runtime { - // Exclude part `Storage` in order not to check its metadata in tests. - System: frame_system exclude_parts { Pallet, Storage }, - Example: pallet, - Example2: pallet2 exclude_parts { Call }, - #[cfg(feature = "frame-feature-testing")] - Example3: pallet3, - Example4: pallet4 use_parts { Call }, +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; - #[cfg(feature = "frame-feature-testing-2")] - Example5: pallet5, - } -); + #[runtime::pallet_index(0)] + pub type System = frame_system + Call + Event; + + #[runtime::pallet_index(1)] + pub type Example = pallet; + + #[runtime::pallet_index(2)] + #[runtime::disable_call] + pub type Example2 = pallet2; + + #[cfg(feature = "frame-feature-testing")] + #[runtime::pallet_index(3)] + pub type Example3 = pallet3; + + #[runtime::pallet_index(4)] + pub type Example4 = pallet4; + + #[cfg(feature = "frame-feature-testing-2")] + #[runtime::pallet_index(5)] + pub type Example5 = pallet5; +} // Test that the part `RuntimeCall` is excluded from Example2 and included in Example4. fn _ensure_call_is_correctly_excluded_and_included(call: RuntimeCall) { @@ -1847,6 +1873,16 @@ fn metadata() { error: None, docs: vec![" Test that the supertrait check works when we pass some parameter to the `frame_system::Config`."], }, + PalletMetadata { + index: 4, + name: "Example4", + storage: None, + calls: Some(meta_type::>().into()), + event: None, + constants: vec![], + error: None, + docs: vec![], + }, #[cfg(feature = "frame-feature-testing-2")] PalletMetadata { index: 5, @@ -1944,7 +1980,10 @@ fn metadata_at_version() { #[test] fn metadata_versions() { - assert_eq!(vec![14, LATEST_METADATA_VERSION], Runtime::metadata_versions()); + assert_eq!( + vec![14, LATEST_METADATA_VERSION, UNSTABLE_METADATA_VERSION], + Runtime::metadata_versions() + ); } #[test] diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index 81377210eb43..a098643abb91 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -80,34 +80,39 @@ sp_api::decl_runtime_apis! { } } -sp_api::impl_runtime_apis! { - impl self::Api for Runtime { - fn test(_data: u64) { - unimplemented!() - } +// Module to emulate having the implementation in a different file. +mod apis { + use super::{Block, BlockT, Runtime}; - fn something_with_block(_: Block) -> Block { - unimplemented!() - } + sp_api::impl_runtime_apis! { + impl crate::Api for Runtime { + fn test(_data: u64) { + unimplemented!() + } - fn function_with_two_args(_: u64, _: Block) { - unimplemented!() - } + fn something_with_block(_: Block) -> Block { + unimplemented!() + } - fn same_name() {} + fn function_with_two_args(_: u64, _: Block) { + unimplemented!() + } - fn wild_card(_: u32) {} - } + fn same_name() {} - impl sp_api::Core for Runtime { - fn version() -> sp_version::RuntimeVersion { - unimplemented!() - } - fn execute_block(_: Block) { - unimplemented!() + fn wild_card(_: u32) {} } - fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - unimplemented!() + + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + unimplemented!() + } } } } @@ -178,7 +183,7 @@ fn runtime_metadata() { RuntimeApiMethodMetadataIR { name: "wild_card", inputs: vec![RuntimeApiMethodParamMetadataIR:: { - name: "_", + name: "__runtime_api_generated_name_0__", ty: meta_type::(), }], output: meta_type::<()>(), diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 38349c7edbd9..1340b2c55c53 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -18,17 +18,17 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] cfg-if = { workspace = true } codec = { features = ["derive"], workspace = true } +docify = { workspace = true } +frame-support = { workspace = true } log = { workspace = true } scale-info = { features = ["derive", "serde"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } -frame-support = { workspace = true } sp-core = { features = ["serde"], workspace = true } sp-io = { workspace = true } sp-runtime = { features = ["serde"], workspace = true } sp-std = { workspace = true } sp-version = { features = ["serde"], workspace = true } sp-weights = { features = ["serde"], workspace = true } -docify = { workspace = true } [dev-dependencies] criterion = { workspace = true, default-features = true } diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index d9b5e7083bd2..e9aac6e519f3 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -17,16 +17,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } [dev-dependencies] -sp-io = { workspace = true, default-features = true } sp-externalities = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } [features] diff --git a/substrate/frame/system/benchmarking/src/extensions.rs b/substrate/frame/system/benchmarking/src/extensions.rs index 3c6626030e22..01e4687bc4bc 100644 --- a/substrate/frame/system/benchmarking/src/extensions.rs +++ b/substrate/frame/system/benchmarking/src/extensions.rs @@ -23,6 +23,7 @@ use alloc::vec; use frame_benchmarking::{account, v2::*, BenchmarkError}; use frame_support::{ dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, + pallet_prelude::Zero, weights::Weight, }; use frame_system::{ @@ -53,11 +54,14 @@ mod benchmarks { let caller = account("caller", 0, 0); let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() }; let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + frame_benchmarking::benchmarking::add_to_whitelist( + frame_system::BlockHash::::hashed_key_for(BlockNumberFor::::zero()).into(), + ); #[block] { CheckGenesis::::new() - .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) .unwrap() .unwrap(); } @@ -81,10 +85,13 @@ mod benchmarks { ..Default::default() }; let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + frame_benchmarking::benchmarking::add_to_whitelist( + frame_system::BlockHash::::hashed_key_for(prev_block).into(), + ); #[block] { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) .unwrap() .unwrap(); } @@ -109,10 +116,13 @@ mod benchmarks { ..Default::default() }; let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + frame_benchmarking::benchmarking::add_to_whitelist( + frame_system::BlockHash::::hashed_key_for(BlockNumberFor::::zero()).into(), + ); #[block] { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) .unwrap() .unwrap(); } @@ -129,7 +139,7 @@ mod benchmarks { #[block] { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) .unwrap() .unwrap(); } @@ -151,7 +161,7 @@ mod benchmarks { #[block] { - ext.test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, len, |_| { + ext.test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, len, 0, |_| { Ok(().into()) }) .unwrap() @@ -173,7 +183,7 @@ mod benchmarks { #[block] { CheckSpecVersion::::new() - .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) .unwrap() .unwrap(); } @@ -190,7 +200,7 @@ mod benchmarks { #[block] { CheckTxVersion::::new() - .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) .unwrap() .unwrap(); } @@ -230,7 +240,7 @@ mod benchmarks { #[block] { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(post_info)) + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(post_info)) .unwrap() .unwrap(); } diff --git a/substrate/frame/system/rpc/runtime-api/Cargo.toml b/substrate/frame/system/rpc/runtime-api/Cargo.toml index 8e968a536756..3fd1985619bd 100644 --- a/substrate/frame/system/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/system/rpc/runtime-api/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -sp-api = { workspace = true } docify = { workspace = true } +sp-api = { workspace = true } [features] default = ["std"] diff --git a/substrate/frame/system/src/extensions/check_mortality.rs b/substrate/frame/system/src/extensions/check_mortality.rs index 7da5521f353d..e2c22a07a3fe 100644 --- a/substrate/frame/system/src/extensions/check_mortality.rs +++ b/substrate/frame/system/src/extensions/check_mortality.rs @@ -17,6 +17,7 @@ use crate::{pallet_prelude::BlockNumberFor, BlockHash, Config, Pallet}; use codec::{Decode, Encode}; +use frame_support::pallet_prelude::TransactionSource; use scale_info::TypeInfo; use sp_runtime::{ generic::Era, @@ -91,6 +92,7 @@ impl TransactionExtension for CheckMort _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { let current_u64 = >::block_number().saturated_into::(); let valid_till = self.0.death(current_u64); @@ -115,7 +117,9 @@ mod tests { weights::Weight, }; use sp_core::H256; - use sp_runtime::traits::DispatchTransaction; + use sp_runtime::{ + traits::DispatchTransaction, transaction_validity::TransactionSource::External, + }; #[test] fn signed_ext_check_era_should_work() { @@ -151,7 +155,10 @@ mod tests { >::insert(16, H256::repeat_byte(1)); assert_eq!( - ext.validate_only(Some(1).into(), CALL, &normal, len).unwrap().0.longevity, + ext.validate_only(Some(1).into(), CALL, &normal, len, External, 0) + .unwrap() + .0 + .longevity, 15 ); }) diff --git a/substrate/frame/system/src/extensions/check_non_zero_sender.rs b/substrate/frame/system/src/extensions/check_non_zero_sender.rs index ec8c12b790d2..577e2b324fca 100644 --- a/substrate/frame/system/src/extensions/check_non_zero_sender.rs +++ b/substrate/frame/system/src/extensions/check_non_zero_sender.rs @@ -18,7 +18,7 @@ use crate::Config; use codec::{Decode, Encode}; use core::marker::PhantomData; -use frame_support::{traits::OriginTrait, DefaultNoBound}; +use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, DefaultNoBound}; use scale_info::TypeInfo; use sp_runtime::{ impl_tx_ext_default, @@ -68,6 +68,7 @@ impl TransactionExtension for CheckNonZ _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> sp_runtime::traits::ValidateResult { if let Some(who) = origin.as_signer() { if who.using_encoded(|d| d.iter().all(|x| *x == 0)) { @@ -86,7 +87,7 @@ mod tests { use frame_support::{assert_ok, dispatch::DispatchInfo}; use sp_runtime::{ traits::{AsTransactionAuthorizedOrigin, DispatchTransaction}, - transaction_validity::TransactionValidityError, + transaction_validity::{TransactionSource::External, TransactionValidityError}, }; #[test] @@ -96,7 +97,7 @@ mod tests { let len = 0_usize; assert_eq!( CheckNonZeroSender::::new() - .validate_only(Some(0).into(), CALL, &info, len) + .validate_only(Some(0).into(), CALL, &info, len, External, 0) .unwrap_err(), TransactionValidityError::from(InvalidTransaction::BadSigner) ); @@ -104,7 +105,9 @@ mod tests { Some(1).into(), CALL, &info, - len + len, + External, + 0, )); }) } @@ -115,7 +118,7 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; let (_, _, origin) = CheckNonZeroSender::::new() - .validate(None.into(), CALL, &info, len, (), CALL) + .validate(None.into(), CALL, &info, len, (), CALL, External) .unwrap(); assert!(!origin.is_transaction_authorized()); }) diff --git a/substrate/frame/system/src/extensions/check_nonce.rs b/substrate/frame/system/src/extensions/check_nonce.rs index d96d2c2c0662..004ec08a26f2 100644 --- a/substrate/frame/system/src/extensions/check_nonce.rs +++ b/substrate/frame/system/src/extensions/check_nonce.rs @@ -18,7 +18,9 @@ use crate::Config; use alloc::vec; use codec::{Decode, Encode}; -use frame_support::{dispatch::DispatchInfo, RuntimeDebugNoBound}; +use frame_support::{ + dispatch::DispatchInfo, pallet_prelude::TransactionSource, RuntimeDebugNoBound, +}; use scale_info::TypeInfo; use sp_runtime::{ traits::{ @@ -108,6 +110,7 @@ where _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { let Some(who) = origin.as_system_origin_signer() else { return Ok((Default::default(), Val::Refund(self.weight(call)), origin)) @@ -182,7 +185,10 @@ mod tests { use frame_support::{ assert_ok, assert_storage_noop, dispatch::GetDispatchInfo, traits::OriginTrait, }; - use sp_runtime::traits::{AsTransactionAuthorizedOrigin, DispatchTransaction}; + use sp_runtime::{ + traits::{AsTransactionAuthorizedOrigin, DispatchTransaction}, + transaction_validity::TransactionSource::External, + }; #[test] fn signed_ext_check_nonce_works() { @@ -203,13 +209,13 @@ mod tests { assert_storage_noop!({ assert_eq!( CheckNonce::(0u64.into()) - .validate_only(Some(1).into(), CALL, &info, len) + .validate_only(Some(1).into(), CALL, &info, len, External, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Stale) ); assert_eq!( CheckNonce::(0u64.into()) - .validate_and_prepare(Some(1).into(), CALL, &info, len) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Stale) ); @@ -219,24 +225,29 @@ mod tests { Some(1).into(), CALL, &info, - len + len, + External, + 0, )); assert_ok!(CheckNonce::(1u64.into()).validate_and_prepare( Some(1).into(), CALL, &info, - len + len, + 0, )); // future assert_ok!(CheckNonce::(5u64.into()).validate_only( Some(1).into(), CALL, &info, - len + len, + External, + 0, )); assert_eq!( CheckNonce::(5u64.into()) - .validate_and_prepare(Some(1).into(), CALL, &info, len) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Future) ); @@ -272,13 +283,13 @@ mod tests { assert_storage_noop!({ assert_eq!( CheckNonce::(1u64.into()) - .validate_only(Some(1).into(), CALL, &info, len) + .validate_only(Some(1).into(), CALL, &info, len, External, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Payment) ); assert_eq!( CheckNonce::(1u64.into()) - .validate_and_prepare(Some(1).into(), CALL, &info, len) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Payment) ); @@ -288,26 +299,32 @@ mod tests { Some(2).into(), CALL, &info, - len + len, + External, + 0, )); assert_ok!(CheckNonce::(1u64.into()).validate_and_prepare( Some(2).into(), CALL, &info, - len + len, + 0, )); // Non-zero sufficients assert_ok!(CheckNonce::(1u64.into()).validate_only( Some(3).into(), CALL, &info, - len + len, + External, + 0, )); assert_ok!(CheckNonce::(1u64.into()).validate_and_prepare( Some(3).into(), CALL, &info, - len + len, + 0, )); }) } @@ -318,7 +335,7 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; let (_, val, origin) = CheckNonce::(1u64.into()) - .validate(None.into(), CALL, &info, len, (), CALL) + .validate(None.into(), CALL, &info, len, (), CALL, External) .unwrap(); assert!(!origin.is_transaction_authorized()); assert_ok!(CheckNonce::(1u64.into()).prepare(val, &origin, CALL, &info, len)); @@ -342,7 +359,7 @@ mod tests { let len = 0_usize; // run the validation step let (_, val, origin) = CheckNonce::(1u64.into()) - .validate(Some(1).into(), CALL, &info, len, (), CALL) + .validate(Some(1).into(), CALL, &info, len, (), CALL, External) .unwrap(); // mutate `AccountData` for the caller crate::Account::::mutate(1, |info| { @@ -376,7 +393,7 @@ mod tests { let len = CALL.encoded_size(); let origin = crate::RawOrigin::Root.into(); - let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len).unwrap(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); assert!(origin.as_system_ref().unwrap().is_root()); diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 131057f54a78..ee91478b90f3 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -19,6 +19,7 @@ use crate::{limits::BlockWeights, Config, Pallet, LOG_TARGET}; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, PostDispatchInfo}, + pallet_prelude::TransactionSource, traits::Get, }; use scale_info::TypeInfo; @@ -254,6 +255,7 @@ where len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { let (validity, next_len) = Self::do_validate(info, len)?; Ok((validity, next_len, origin)) @@ -546,7 +548,7 @@ mod tests { // will not fit. assert_eq!( CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &normal, len) + .validate_and_prepare(Some(1).into(), CALL, &normal, len, 0) .unwrap_err(), InvalidTransaction::ExhaustsResources.into() ); @@ -555,7 +557,8 @@ mod tests { Some(1).into(), CALL, &op, - len + len, + 0, )); // likewise for length limit. @@ -563,7 +566,7 @@ mod tests { AllExtrinsicsLen::::put(normal_length_limit()); assert_eq!( CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &normal, len) + .validate_and_prepare(Some(1).into(), CALL, &normal, len, 0) .unwrap_err(), InvalidTransaction::ExhaustsResources.into() ); @@ -571,7 +574,8 @@ mod tests { Some(1).into(), CALL, &op, - len + len, + 0, )); }) } @@ -588,6 +592,7 @@ mod tests { CALL, tx, s, + 0, ); if f { assert!(r.is_err()) @@ -638,6 +643,7 @@ mod tests { CALL, i, len, + 0, ); if f { assert!(r.is_err()) @@ -673,7 +679,7 @@ mod tests { }); let pre = CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &info, len) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) .unwrap() .0; assert_eq!( @@ -712,7 +718,7 @@ mod tests { }); let pre = CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &info, len) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) .unwrap() .0; assert_eq!( @@ -751,7 +757,8 @@ mod tests { Some(1).into(), CALL, &free, - len + len, + 0, )); assert_eq!( System::block_weight().total(), diff --git a/substrate/frame/system/src/extensions/weights.rs b/substrate/frame/system/src/extensions/weights.rs index 1c0136ae7802..b3c296899be5 100644 --- a/substrate/frame/system/src/extensions/weights.rs +++ b/substrate/frame/system/src/extensions/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `frame_system_extensions` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -68,38 +68,38 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn check_genesis() -> Weight { // Proof Size summary in bytes: - // Measured: `54` + // Measured: `30` // Estimated: `3509` - // Minimum execution time: 3_876_000 picoseconds. - Weight::from_parts(4_160_000, 3509) + // Minimum execution time: 3_388_000 picoseconds. + Weight::from_parts(3_577_000, 3509) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn check_mortality_mortal_transaction() -> Weight { // Proof Size summary in bytes: - // Measured: `92` + // Measured: `68` // Estimated: `3509` - // Minimum execution time: 6_296_000 picoseconds. - Weight::from_parts(6_523_000, 3509) + // Minimum execution time: 6_442_000 picoseconds. + Weight::from_parts(6_703_000, 3509) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn check_mortality_immortal_transaction() -> Weight { // Proof Size summary in bytes: - // Measured: `92` + // Measured: `68` // Estimated: `3509` - // Minimum execution time: 6_296_000 picoseconds. - Weight::from_parts(6_523_000, 3509) + // Minimum execution time: 6_357_000 picoseconds. + Weight::from_parts(6_605_000, 3509) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn check_non_zero_sender() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 449_000 picoseconds. - Weight::from_parts(527_000, 0) + // Minimum execution time: 457_000 picoseconds. + Weight::from_parts(570_000, 0) } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -107,8 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 5_689_000 picoseconds. - Weight::from_parts(6_000_000, 3593) + // Minimum execution time: 6_936_000 picoseconds. + Weight::from_parts(7_261_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,26 +116,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 399_000 picoseconds. - Weight::from_parts(461_000, 0) + // Minimum execution time: 336_000 picoseconds. + Weight::from_parts(430_000, 0) } fn check_tx_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 390_000 picoseconds. - Weight::from_parts(439_000, 0) + // Minimum execution time: 348_000 picoseconds. + Weight::from_parts(455_000, 0) } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn check_weight() -> Weight { // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 4_375_000 picoseconds. - Weight::from_parts(4_747_000, 1489) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_887_000 picoseconds. + Weight::from_parts(3_006_000, 0) } } @@ -145,38 +141,38 @@ impl WeightInfo for () { /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn check_genesis() -> Weight { // Proof Size summary in bytes: - // Measured: `54` + // Measured: `30` // Estimated: `3509` - // Minimum execution time: 3_876_000 picoseconds. - Weight::from_parts(4_160_000, 3509) + // Minimum execution time: 3_388_000 picoseconds. + Weight::from_parts(3_577_000, 3509) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn check_mortality_mortal_transaction() -> Weight { // Proof Size summary in bytes: - // Measured: `92` + // Measured: `68` // Estimated: `3509` - // Minimum execution time: 6_296_000 picoseconds. - Weight::from_parts(6_523_000, 3509) + // Minimum execution time: 6_442_000 picoseconds. + Weight::from_parts(6_703_000, 3509) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) fn check_mortality_immortal_transaction() -> Weight { // Proof Size summary in bytes: - // Measured: `92` + // Measured: `68` // Estimated: `3509` - // Minimum execution time: 6_296_000 picoseconds. - Weight::from_parts(6_523_000, 3509) + // Minimum execution time: 6_357_000 picoseconds. + Weight::from_parts(6_605_000, 3509) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn check_non_zero_sender() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 449_000 picoseconds. - Weight::from_parts(527_000, 0) + // Minimum execution time: 457_000 picoseconds. + Weight::from_parts(570_000, 0) } /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -184,8 +180,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 5_689_000 picoseconds. - Weight::from_parts(6_000_000, 3593) + // Minimum execution time: 6_936_000 picoseconds. + Weight::from_parts(7_261_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -193,25 +189,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 399_000 picoseconds. - Weight::from_parts(461_000, 0) + // Minimum execution time: 336_000 picoseconds. + Weight::from_parts(430_000, 0) } fn check_tx_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 390_000 picoseconds. - Weight::from_parts(439_000, 0) + // Minimum execution time: 348_000 picoseconds. + Weight::from_parts(455_000, 0) } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn check_weight() -> Weight { // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 4_375_000 picoseconds. - Weight::from_parts(4_747_000, 1489) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_887_000 picoseconds. + Weight::from_parts(3_006_000, 0) } } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 02d61921741c..862fb4cf9faf 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -99,7 +99,7 @@ extern crate alloc; -use alloc::{boxed::Box, vec, vec::Vec}; +use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec}; use core::{fmt::Debug, marker::PhantomData}; use pallet_prelude::{BlockNumberFor, HeaderFor}; #[cfg(feature = "std")] @@ -130,7 +130,8 @@ use frame_support::traits::BuildGenesisConfig; use frame_support::{ dispatch::{ extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, - DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, PostDispatchInfo, + DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, PerDispatchClass, + PostDispatchInfo, }, ensure, impl_ensure_origin_with_arg_ignoring_arg, migrations::MultiStepMigrator, @@ -310,7 +311,7 @@ pub mod pallet { type Hash = sp_core::hash::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; - type Lookup = sp_runtime::traits::IdentityLookup; + type Lookup = sp_runtime::traits::IdentityLookup; type MaxConsumers = frame_support::traits::ConstU32<16>; type AccountData = (); type OnNewAccount = (); @@ -507,6 +508,7 @@ pub mod pallet { type RuntimeCall: Parameter + Dispatchable + Debug + + GetDispatchInfo + From>; /// The aggregated `RuntimeTask` type. @@ -971,6 +973,7 @@ pub mod pallet { /// Digest of the current block, also part of the block header. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::unbounded] #[pallet::getter(fn digest)] pub(super) type Digest = StorageValue<_, generic::Digest, ValueQuery>; @@ -1159,24 +1162,24 @@ pub struct AccountInfo { /// Stores the `spec_version` and `spec_name` of when the last runtime upgrade /// happened. -#[derive(sp_runtime::RuntimeDebug, Encode, Decode, TypeInfo)] +#[derive(RuntimeDebug, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct LastRuntimeUpgradeInfo { pub spec_version: codec::Compact, - pub spec_name: sp_runtime::RuntimeString, + pub spec_name: Cow<'static, str>, } impl LastRuntimeUpgradeInfo { /// Returns if the runtime was upgraded in comparison of `self` and `current`. /// /// Checks if either the `spec_version` increased or the `spec_name` changed. - pub fn was_upgraded(&self, current: &sp_version::RuntimeVersion) -> bool { + pub fn was_upgraded(&self, current: &RuntimeVersion) -> bool { current.spec_version > self.spec_version.0 || current.spec_name != self.spec_name } } -impl From for LastRuntimeUpgradeInfo { - fn from(version: sp_version::RuntimeVersion) -> Self { +impl From for LastRuntimeUpgradeInfo { + fn from(version: RuntimeVersion) -> Self { Self { spec_version: version.spec_version.into(), spec_name: version.spec_name } } } diff --git a/substrate/frame/system/src/mock.rs b/substrate/frame/system/src/mock.rs index f43ffe3c87ee..80bc75973d19 100644 --- a/substrate/frame/system/src/mock.rs +++ b/substrate/frame/system/src/mock.rs @@ -33,8 +33,8 @@ const MAX_BLOCK_WEIGHT: Weight = Weight::from_parts(1024, u64::MAX); parameter_types! { pub Version: RuntimeVersion = RuntimeVersion { - spec_name: sp_version::create_runtime_str!("test"), - impl_name: sp_version::create_runtime_str!("system-test"), + spec_name: alloc::borrow::Cow::Borrowed("test"), + impl_name: alloc::borrow::Cow::Borrowed("system-test"), authoring_version: 1, spec_version: 1, impl_version: 1, diff --git a/substrate/frame/system/src/weights.rs b/substrate/frame/system/src/weights.rs index fca14e452657..8450e0e7fb94 100644 --- a/substrate/frame/system/src/weights.rs +++ b/substrate/frame/system/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -70,8 +70,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_078_000 picoseconds. - Weight::from_parts(1_137_744, 0) + // Minimum execution time: 2_093_000 picoseconds. + Weight::from_parts(2_169_000, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) } @@ -80,38 +80,33 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_980_000 picoseconds. - Weight::from_parts(2_562_415, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_391, 0).saturating_mul(b.into())) + // Minimum execution time: 5_750_000 picoseconds. + Weight::from_parts(23_611_490, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_613, 0).saturating_mul(b.into())) } - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `1485` - // Minimum execution time: 3_834_000 picoseconds. - Weight::from_parts(4_109_000, 1485) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Estimated: `0` + // Minimum execution time: 3_465_000 picoseconds. + Weight::from_parts(3_616_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `67035` - // Minimum execution time: 81_326_496_000 picoseconds. - Weight::from_parts(81_880_651_000, 67035) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Minimum execution time: 90_830_152_000 picoseconds. + Weight::from_parts(96_270_304_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -120,10 +115,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_059_000 picoseconds. - Weight::from_parts(2_192_000, 0) - // Standard Error: 720 - .saturating_add(Weight::from_parts(742_610, 0).saturating_mul(i.into())) + // Minimum execution time: 2_147_000 picoseconds. + Weight::from_parts(2_239_000, 0) + // Standard Error: 2_137 + .saturating_add(Weight::from_parts(748_304, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -133,10 +128,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_038_000 picoseconds. - Weight::from_parts(2_159_000, 0) - // Standard Error: 774 - .saturating_add(Weight::from_parts(569_424, 0).saturating_mul(i.into())) + // Minimum execution time: 2_053_000 picoseconds. + Weight::from_parts(2_188_000, 0) + // Standard Error: 878 + .saturating_add(Weight::from_parts(560_728, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -144,12 +139,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `127 + p * (69 ±0)` + // Measured: `120 + p * (69 ±0)` // Estimated: `134 + p * (70 ±0)` - // Minimum execution time: 3_990_000 picoseconds. - Weight::from_parts(4_172_000, 134) - // Standard Error: 1_485 - .saturating_add(Weight::from_parts(1_227_281, 0).saturating_mul(p.into())) + // Minimum execution time: 4_244_000 picoseconds. + Weight::from_parts(4_397_000, 134) + // Standard Error: 1_410 + .saturating_add(Weight::from_parts(1_307_089, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -160,26 +155,24 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_851_000 picoseconds. - Weight::from_parts(9_643_000, 0) + // Minimum execution time: 10_037_000 picoseconds. + Weight::from_parts(16_335_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `System::AuthorizedUpgrade` (r:1 w:1) /// Proof: `System::AuthorizedUpgrade` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn apply_authorized_upgrade() -> Weight { // Proof Size summary in bytes: // Measured: `164` // Estimated: `67035` - // Minimum execution time: 86_295_879_000 picoseconds. - Weight::from_parts(87_636_595_000, 67035) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 95_970_737_000 picoseconds. + Weight::from_parts(98_826_505_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -190,8 +183,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_078_000 picoseconds. - Weight::from_parts(1_137_744, 0) + // Minimum execution time: 2_093_000 picoseconds. + Weight::from_parts(2_169_000, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) } @@ -200,38 +193,33 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_980_000 picoseconds. - Weight::from_parts(2_562_415, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_391, 0).saturating_mul(b.into())) + // Minimum execution time: 5_750_000 picoseconds. + Weight::from_parts(23_611_490, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_613, 0).saturating_mul(b.into())) } - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `1485` - // Minimum execution time: 3_834_000 picoseconds. - Weight::from_parts(4_109_000, 1485) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Estimated: `0` + // Minimum execution time: 3_465_000 picoseconds. + Weight::from_parts(3_616_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `67035` - // Minimum execution time: 81_326_496_000 picoseconds. - Weight::from_parts(81_880_651_000, 67035) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Minimum execution time: 90_830_152_000 picoseconds. + Weight::from_parts(96_270_304_000, 67035) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -240,10 +228,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_059_000 picoseconds. - Weight::from_parts(2_192_000, 0) - // Standard Error: 720 - .saturating_add(Weight::from_parts(742_610, 0).saturating_mul(i.into())) + // Minimum execution time: 2_147_000 picoseconds. + Weight::from_parts(2_239_000, 0) + // Standard Error: 2_137 + .saturating_add(Weight::from_parts(748_304, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -253,10 +241,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_038_000 picoseconds. - Weight::from_parts(2_159_000, 0) - // Standard Error: 774 - .saturating_add(Weight::from_parts(569_424, 0).saturating_mul(i.into())) + // Minimum execution time: 2_053_000 picoseconds. + Weight::from_parts(2_188_000, 0) + // Standard Error: 878 + .saturating_add(Weight::from_parts(560_728, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -264,12 +252,12 @@ impl WeightInfo for () { /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `127 + p * (69 ±0)` + // Measured: `120 + p * (69 ±0)` // Estimated: `134 + p * (70 ±0)` - // Minimum execution time: 3_990_000 picoseconds. - Weight::from_parts(4_172_000, 134) - // Standard Error: 1_485 - .saturating_add(Weight::from_parts(1_227_281, 0).saturating_mul(p.into())) + // Minimum execution time: 4_244_000 picoseconds. + Weight::from_parts(4_397_000, 134) + // Standard Error: 1_410 + .saturating_add(Weight::from_parts(1_307_089, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -280,25 +268,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_851_000 picoseconds. - Weight::from_parts(9_643_000, 0) + // Minimum execution time: 10_037_000 picoseconds. + Weight::from_parts(16_335_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `System::AuthorizedUpgrade` (r:1 w:1) /// Proof: `System::AuthorizedUpgrade` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn apply_authorized_upgrade() -> Weight { // Proof Size summary in bytes: // Measured: `164` // Estimated: `67035` - // Minimum execution time: 86_295_879_000 picoseconds. - Weight::from_parts(87_636_595_000, 67035) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 95_970_737_000 picoseconds. + Weight::from_parts(98_826_505_000, 67035) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index 0eff0530c7e2..75788aef348a 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -18,11 +18,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive", "max-encoded-len"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-inherents = { workspace = true } sp-io = { optional = true, workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/timestamp/src/lib.rs b/substrate/frame/timestamp/src/lib.rs index 78e2939e65b9..5cb6c859c417 100644 --- a/substrate/frame/timestamp/src/lib.rs +++ b/substrate/frame/timestamp/src/lib.rs @@ -161,7 +161,7 @@ pub mod pallet { impl DefaultConfig for TestDefaultConfig { type Moment = u64; type OnTimestampSet = (); - type MinimumPeriod = frame_support::traits::ConstU64<1>; + type MinimumPeriod = ConstUint<1>; type WeightInfo = (); } } diff --git a/substrate/frame/timestamp/src/weights.rs b/substrate/frame/timestamp/src/weights.rs index 9f2cbf7ccd12..9f16a82653a9 100644 --- a/substrate/frame/timestamp/src/weights.rs +++ b/substrate/frame/timestamp/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -66,8 +66,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `345` // Estimated: `1493` - // Minimum execution time: 8_356_000 picoseconds. - Weight::from_parts(8_684_000, 1493) + // Minimum execution time: 10_176_000 picoseconds. + Weight::from_parts(10_560_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `194` // Estimated: `0` - // Minimum execution time: 3_886_000 picoseconds. - Weight::from_parts(4_118_000, 0) + // Minimum execution time: 4_915_000 picoseconds. + Weight::from_parts(5_192_000, 0) } } @@ -90,8 +90,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `345` // Estimated: `1493` - // Minimum execution time: 8_356_000 picoseconds. - Weight::from_parts(8_684_000, 1493) + // Minimum execution time: 10_176_000 picoseconds. + Weight::from_parts(10_560_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -99,7 +99,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `194` // Estimated: `0` - // Minimum execution time: 3_886_000 picoseconds. - Weight::from_parts(4_118_000, 0) + // Minimum execution time: 4_915_000 picoseconds. + Weight::from_parts(5_192_000, 0) } } diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 7c7a2d6aa909..6b5b89e7a197 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -17,13 +17,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-treasury = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index f6f130b7e261..530efb708e41 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -209,6 +209,7 @@ fn last_event() -> TipEvent { } #[test] +#[allow(deprecated)] fn genesis_config_works() { build_and_execute(|| { assert_eq!(Treasury::pot(), 0); diff --git a/substrate/frame/tips/src/weights.rs b/substrate/frame/tips/src/weights.rs index 7e1bba3c73e7..e9805e9cc9bf 100644 --- a/substrate/frame/tips/src/weights.rs +++ b/substrate/frame/tips/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_tips` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -71,10 +71,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `3469` - // Minimum execution time: 26_549_000 picoseconds. - Weight::from_parts(27_804_619, 3469) - // Standard Error: 173 - .saturating_add(Weight::from_parts(1_718, 0).saturating_mul(r.into())) + // Minimum execution time: 26_606_000 picoseconds. + Weight::from_parts(27_619_942, 3469) + // Standard Error: 179 + .saturating_add(Weight::from_parts(2_750, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -86,8 +86,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `221` // Estimated: `3686` - // Minimum execution time: 25_430_000 picoseconds. - Weight::from_parts(26_056_000, 3686) + // Minimum execution time: 29_286_000 picoseconds. + Weight::from_parts(30_230_000, 3686) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -101,14 +101,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `526 + t * (64 ±0)` - // Estimated: `3991 + t * (64 ±0)` - // Minimum execution time: 17_309_000 picoseconds. - Weight::from_parts(17_493_185, 3991) - // Standard Error: 126 - .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(r.into())) - // Standard Error: 3_011 - .saturating_add(Weight::from_parts(88_592, 0).saturating_mul(t.into())) + // Measured: `623 + t * (64 ±0)` + // Estimated: `4088 + t * (64 ±0)` + // Minimum execution time: 21_690_000 picoseconds. + Weight::from_parts(22_347_457, 4088) + // Standard Error: 125 + .saturating_add(Weight::from_parts(2_332, 0).saturating_mul(r.into())) + // Standard Error: 2_974 + .saturating_add(Weight::from_parts(20_772, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) @@ -120,12 +120,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `747 + t * (112 ±0)` - // Estimated: `4212 + t * (112 ±0)` - // Minimum execution time: 14_148_000 picoseconds. - Weight::from_parts(14_434_268, 4212) - // Standard Error: 4_666 - .saturating_add(Weight::from_parts(210_867, 0).saturating_mul(t.into())) + // Measured: `844 + t * (112 ±0)` + // Estimated: `4309 + t * (112 ±0)` + // Minimum execution time: 20_588_000 picoseconds. + Weight::from_parts(21_241_034, 4309) + // Standard Error: 2_448 + .saturating_add(Weight::from_parts(133_643, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) @@ -141,29 +141,27 @@ impl WeightInfo for SubstrateWeight { /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `786 + t * (112 ±0)` - // Estimated: `4242 + t * (112 ±0)` - // Minimum execution time: 56_060_000 picoseconds. - Weight::from_parts(57_913_972, 4242) - // Standard Error: 11_691 - .saturating_add(Weight::from_parts(229_579, 0).saturating_mul(t.into())) + // Measured: `896 + t * (112 ±0)` + // Estimated: `4353 + t * (111 ±0)` + // Minimum execution time: 60_824_000 picoseconds. + Weight::from_parts(63_233_742, 4353) + // Standard Error: 9_841 + .saturating_add(Weight::from_parts(77_920, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 111).saturating_mul(t.into())) } /// Storage: `Tips::Tips` (r:1 w:1) /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Tips::Reasons` (r:0 w:1) /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `t` is `[1, 13]`. - fn slash_tip(t: u32, ) -> Weight { + fn slash_tip(_t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `269` // Estimated: `3734` - // Minimum execution time: 12_034_000 picoseconds. - Weight::from_parts(12_934_534, 3734) - // Standard Error: 2_420 - .saturating_add(Weight::from_parts(4_167, 0).saturating_mul(t.into())) + // Minimum execution time: 13_281_000 picoseconds. + Weight::from_parts(14_089_409, 3734) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -180,10 +178,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4` // Estimated: `3469` - // Minimum execution time: 26_549_000 picoseconds. - Weight::from_parts(27_804_619, 3469) - // Standard Error: 173 - .saturating_add(Weight::from_parts(1_718, 0).saturating_mul(r.into())) + // Minimum execution time: 26_606_000 picoseconds. + Weight::from_parts(27_619_942, 3469) + // Standard Error: 179 + .saturating_add(Weight::from_parts(2_750, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -195,8 +193,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `221` // Estimated: `3686` - // Minimum execution time: 25_430_000 picoseconds. - Weight::from_parts(26_056_000, 3686) + // Minimum execution time: 29_286_000 picoseconds. + Weight::from_parts(30_230_000, 3686) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -210,14 +208,14 @@ impl WeightInfo for () { /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `526 + t * (64 ±0)` - // Estimated: `3991 + t * (64 ±0)` - // Minimum execution time: 17_309_000 picoseconds. - Weight::from_parts(17_493_185, 3991) - // Standard Error: 126 - .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(r.into())) - // Standard Error: 3_011 - .saturating_add(Weight::from_parts(88_592, 0).saturating_mul(t.into())) + // Measured: `623 + t * (64 ±0)` + // Estimated: `4088 + t * (64 ±0)` + // Minimum execution time: 21_690_000 picoseconds. + Weight::from_parts(22_347_457, 4088) + // Standard Error: 125 + .saturating_add(Weight::from_parts(2_332, 0).saturating_mul(r.into())) + // Standard Error: 2_974 + .saturating_add(Weight::from_parts(20_772, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) @@ -229,12 +227,12 @@ impl WeightInfo for () { /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `747 + t * (112 ±0)` - // Estimated: `4212 + t * (112 ±0)` - // Minimum execution time: 14_148_000 picoseconds. - Weight::from_parts(14_434_268, 4212) - // Standard Error: 4_666 - .saturating_add(Weight::from_parts(210_867, 0).saturating_mul(t.into())) + // Measured: `844 + t * (112 ±0)` + // Estimated: `4309 + t * (112 ±0)` + // Minimum execution time: 20_588_000 picoseconds. + Weight::from_parts(21_241_034, 4309) + // Standard Error: 2_448 + .saturating_add(Weight::from_parts(133_643, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) @@ -250,29 +248,27 @@ impl WeightInfo for () { /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `786 + t * (112 ±0)` - // Estimated: `4242 + t * (112 ±0)` - // Minimum execution time: 56_060_000 picoseconds. - Weight::from_parts(57_913_972, 4242) - // Standard Error: 11_691 - .saturating_add(Weight::from_parts(229_579, 0).saturating_mul(t.into())) + // Measured: `896 + t * (112 ±0)` + // Estimated: `4353 + t * (111 ±0)` + // Minimum execution time: 60_824_000 picoseconds. + Weight::from_parts(63_233_742, 4353) + // Standard Error: 9_841 + .saturating_add(Weight::from_parts(77_920, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 111).saturating_mul(t.into())) } /// Storage: `Tips::Tips` (r:1 w:1) /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Tips::Reasons` (r:0 w:1) /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `t` is `[1, 13]`. - fn slash_tip(t: u32, ) -> Weight { + fn slash_tip(_t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `269` // Estimated: `3734` - // Minimum execution time: 12_034_000 picoseconds. - Weight::from_parts(12_934_534, 3734) - // Standard Error: 2_420 - .saturating_add(Weight::from_parts(4_167, 0).saturating_mul(t.into())) + // Minimum execution time: 13_281_000 picoseconds. + Weight::from_parts(14_089_409, 3734) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index afa03ceb12eb..2639bda18b6c 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -19,18 +19,18 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } [dev-dependencies] -serde_json = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 7c98d157f6ff..147859fdb26a 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -17,21 +17,21 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies -sp-runtime = { workspace = true } +codec = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-asset-conversion = { workspace = true } pallet-transaction-payment = { workspace = true } -codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] +pallet-assets = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-storage = { workspace = true } -pallet-assets = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs index 97eff03d849d..eb2635694e9c 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs @@ -59,7 +59,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) .unwrap() .is_ok()); } @@ -86,7 +86,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) .unwrap() .is_ok()); } @@ -115,7 +115,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, |_| Ok( + .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, 0, |_| Ok( post_info )) .unwrap() diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs index 787f6b122e86..d6721c46422b 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs @@ -47,6 +47,7 @@ extern crate alloc; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, + pallet_prelude::TransactionSource, traits::IsType, DefaultNoBound, }; @@ -308,6 +309,7 @@ where len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { let Some(who) = origin.as_system_origin_signer() else { return Ok((ValidTransaction::default(), Val::NoCharge, origin)) diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs index 4312aa9a452f..6ce4652fd42f 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs @@ -168,7 +168,7 @@ fn transaction_payment_in_native_possible() { let mut info = info_from_weight(WEIGHT_5); let ext = ChargeAssetTxPayment::::from(0, None); info.extension_weight = ext.weight(CALL); - let (pre, _) = ext.validate_and_prepare(Some(1).into(), CALL, &info, len).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(1).into(), CALL, &info, len, 0).unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 15 - 10); @@ -185,7 +185,7 @@ fn transaction_payment_in_native_possible() { let ext = ChargeAssetTxPayment::::from(5 /* tipped */, None); let extension_weight = ext.weight(CALL); info.extension_weight = extension_weight; - let (pre, _) = ext.validate_and_prepare(Some(2).into(), CALL, &info, len).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(2).into(), CALL, &info, len, 0).unwrap(); let initial_balance_for_2 = 20 * balance_factor; assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 15 - 5); @@ -255,7 +255,13 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, caller), balance); let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(WEIGHT_5), + len, + 0, + ) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -313,7 +319,13 @@ fn transaction_payment_in_asset_fails_if_no_pool_for_that_asset() { let len = 10; let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len); + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(WEIGHT_5), + len, + 0, + ); // As there is no pool in the dex set up for this asset, conversion should fail. assert!(pre.is_err()); @@ -364,7 +376,13 @@ fn transaction_payment_without_fee() { let fee_in_asset = input_quote.unwrap(); let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(WEIGHT_5), + len, + 0, + ) .unwrap(); // assert that native balance is not used @@ -445,7 +463,8 @@ fn asset_transaction_payment_with_tip_and_refund() { let mut info = info_from_weight(WEIGHT_100); let ext = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())); info.extension_weight = ext.weight(CALL); - let (pre, _) = ext.validate_and_prepare(Some(caller).into(), CALL, &info, len).unwrap(); + let (pre, _) = + ext.validate_and_prepare(Some(caller).into(), CALL, &info, len, 0).unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); let final_weight = 50; @@ -539,7 +558,13 @@ fn payment_from_account_with_only_assets() { assert_eq!(fee_in_asset, 201); let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(WEIGHT_5), + len, + 0, + ) .unwrap(); // check that fee was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); @@ -595,7 +620,13 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { // there will be no conversion when the fee is zero { let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_pays(Pays::No), + len, + 0, + ) .unwrap(); // `Pays::No` implies there are no fees assert_eq!(Assets::balance(asset_id, caller), balance); @@ -626,6 +657,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { CALL, &info_from_weight(Weight::from_parts(weight, 0)), len, + 0, ) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); @@ -676,7 +708,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { assert!(fee > 0); let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len, 0) .unwrap(); // `Pays::No` implies no pre-dispatch fees @@ -730,7 +762,8 @@ fn fee_with_native_asset_passed_with_id() { let mut info = info_from_weight(WEIGHT_100); info.extension_weight = extension_weight; - let (pre, _) = ext.validate_and_prepare(Some(caller).into(), CALL, &info, len).unwrap(); + let (pre, _) = + ext.validate_and_prepare(Some(caller).into(), CALL, &info, len, 0).unwrap(); assert_eq!(Balances::free_balance(caller), caller_balance - initial_fee); let final_weight = 50; @@ -809,7 +842,7 @@ fn transfer_add_and_remove_account() { let mut info = info_from_weight(WEIGHT_100); info.extension_weight = extension_weight; let (pre, _) = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())) - .validate_and_prepare(Some(caller).into(), CALL, &info, len) + .validate_and_prepare(Some(caller).into(), CALL, &info, len, 0) .unwrap(); assert_eq!(Assets::balance(asset_id, &caller), balance - fee_in_asset); @@ -869,7 +902,7 @@ fn no_fee_and_no_weight_for_other_origins() { let len = CALL.encoded_size(); let origin = frame_system::RawOrigin::Root.into(); - let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len).unwrap(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); assert!(origin.as_system_ref().unwrap().is_root()); diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs index f95e49f80730..587a399634b7 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_asset_conversion_tx_payment` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -63,42 +63,33 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 628_000 picoseconds. - Weight::from_parts(694_000, 0) + // Minimum execution time: 735_000 picoseconds. + Weight::from_parts(805_000, 0) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn charge_asset_tx_payment_native() -> Weight { // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 34_410_000 picoseconds. - Weight::from_parts(35_263_000, 1733) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 45_111_000 picoseconds. + Weight::from_parts(45_685_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:2 w:2) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn charge_asset_tx_payment_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `888` + // Measured: `711` // Estimated: `6208` - // Minimum execution time: 112_432_000 picoseconds. - Weight::from_parts(113_992_000, 6208) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Minimum execution time: 164_069_000 picoseconds. + Weight::from_parts(166_667_000, 6208) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } } @@ -109,42 +100,33 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 628_000 picoseconds. - Weight::from_parts(694_000, 0) + // Minimum execution time: 735_000 picoseconds. + Weight::from_parts(805_000, 0) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn charge_asset_tx_payment_native() -> Weight { // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 34_410_000 picoseconds. - Weight::from_parts(35_263_000, 1733) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 45_111_000 picoseconds. + Weight::from_parts(45_685_000, 3593) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:2 w:2) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn charge_asset_tx_payment_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `888` + // Measured: `711` // Estimated: `6208` - // Minimum execution time: 112_432_000 picoseconds. - Weight::from_parts(113_992_000, 6208) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Minimum execution time: 164_069_000 picoseconds. + Weight::from_parts(166_667_000, 6208) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 89fe5bfe7a42..2924860c5201 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -21,10 +21,10 @@ sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-transaction-payment = { workspace = true } -frame-benchmarking = { optional = true, workspace = true } # Other dependencies codec = { features = ["derive"], workspace = true } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs index 25902bf452b2..e4340cc6a152 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs @@ -59,7 +59,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) .unwrap() .is_ok()); } @@ -87,7 +87,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) .unwrap() .is_ok()); } @@ -119,7 +119,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, |_| Ok( + .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, 0, |_| Ok( post_info )) .unwrap() diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs index 25aa272ba01b..dd752989c366 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -38,7 +38,7 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, - pallet_prelude::Weight, + pallet_prelude::{TransactionSource, Weight}, traits::{ tokens::{ fungibles::{Balanced, Credit, Inspect}, @@ -324,6 +324,7 @@ where len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> Result< (ValidTransaction, Self::Val, ::RuntimeOrigin), TransactionValidityError, diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs index cd694c3e81a7..6de2e8e7da55 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -122,7 +122,7 @@ fn transaction_payment_in_native_possible() { let mut info = info_from_weight(Weight::from_parts(5, 0)); let ext = ChargeAssetTxPayment::::from(0, None); info.extension_weight = ext.weight(CALL); - let (pre, _) = ext.validate_and_prepare(Some(1).into(), CALL, &info, len).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(1).into(), CALL, &info, len, 0).unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 15 - 10); @@ -138,7 +138,7 @@ fn transaction_payment_in_native_possible() { let mut info = info_from_weight(Weight::from_parts(100, 0)); let ext = ChargeAssetTxPayment::::from(5 /* tipped */, None); info.extension_weight = ext.weight(CALL); - let (pre, _) = ext.validate_and_prepare(Some(2).into(), CALL, &info, len).unwrap(); + let (pre, _) = ext.validate_and_prepare(Some(2).into(), CALL, &info, len, 0).unwrap(); let initial_balance_for_2 = 20 * balance_factor; assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 15 - 5); @@ -204,6 +204,7 @@ fn transaction_payment_in_asset_possible() { CALL, &info_from_weight(Weight::from_parts(weight, 0)), len, + 0, ) .unwrap(); // assert that native balance is not used @@ -274,6 +275,7 @@ fn transaction_payment_without_fee() { CALL, &info_from_weight(Weight::from_parts(weight, 0)), len, + 0, ) .unwrap(); // assert that native balance is not used @@ -334,7 +336,8 @@ fn asset_transaction_payment_with_tip_and_refund() { min_balance / ExistentialDeposit::get(); let mut info = info_from_weight(Weight::from_parts(weight, 0)); info.extension_weight = ext_weight; - let (pre, _) = ext.validate_and_prepare(Some(caller).into(), CALL, &info, len).unwrap(); + let (pre, _) = + ext.validate_and_prepare(Some(caller).into(), CALL, &info, len, 0).unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Withdrawn { @@ -409,6 +412,7 @@ fn payment_from_account_with_only_assets() { CALL, &info_from_weight(Weight::from_parts(weight, 0)), len, + 0, ) .unwrap(); assert_eq!(Balances::free_balance(caller), 0); @@ -445,7 +449,8 @@ fn payment_only_with_existing_sufficient_asset() { Some(caller).into(), CALL, &info_from_weight(Weight::from_parts(weight, 0)), - len + len, + 0, ) .is_err()); @@ -464,7 +469,8 @@ fn payment_only_with_existing_sufficient_asset() { Some(caller).into(), CALL, &info_from_weight(Weight::from_parts(weight, 0)), - len + len, + 0, ) .is_err()); }); @@ -504,7 +510,13 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { assert_eq!(fee, 0); { let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_pays(Pays::No), + len, + 0, + ) .unwrap(); // `Pays::No` still implies no fees assert_eq!(Assets::balance(asset_id, caller), balance); @@ -524,6 +536,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { CALL, &info_from_weight(Weight::from_parts(weight, 0)), len, + 0, ) .unwrap(); // check that at least one coin was charged in the given asset @@ -573,7 +586,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // calculated fee is greater than 0 assert!(fee > 0); let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len, 0) .unwrap(); // `Pays::No` implies no pre-dispatch fees assert_eq!(Assets::balance(asset_id, caller), balance); @@ -613,7 +626,7 @@ fn no_fee_and_no_weight_for_other_origins() { let len = CALL.encoded_size(); let origin = frame_system::RawOrigin::Root.into(); - let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len).unwrap(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); assert!(origin.as_system_ref().unwrap().is_root()); diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs index d6ac648cefd4..dd907f6fcbb7 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs @@ -39,6 +39,7 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::{CheckIfFeeless, DispatchResult}, + pallet_prelude::TransactionSource, traits::{IsType, OriginTrait}, weights::Weight, }; @@ -147,12 +148,20 @@ where len: usize, self_implicit: S::Implicit, inherited_implication: &impl Encode, + source: TransactionSource, ) -> ValidateResult { if call.is_feeless(&origin) { Ok((Default::default(), Skip(origin.caller().clone()), origin)) } else { - let (x, y, z) = - self.0.validate(origin, call, info, len, self_implicit, inherited_implication)?; + let (x, y, z) = self.0.validate( + origin, + call, + info, + len, + self_implicit, + inherited_implication, + source, + )?; Ok((x, Apply(y), z)) } } diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs index 83f7b7dfe2b5..cff232a0cae3 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs @@ -60,6 +60,7 @@ impl TransactionExtension for DummyExtension { _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { ValidateCount::mutate(|c| *c += 1); Ok((ValidTransaction::default(), (), origin)) diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs index 666844c883bd..b6ecbf9d5764 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs @@ -18,19 +18,19 @@ use crate::mock::{ pallet_dummy::Call, DummyExtension, PrepareCount, Runtime, RuntimeCall, ValidateCount, }; use frame_support::dispatch::DispatchInfo; -use sp_runtime::traits::DispatchTransaction; +use sp_runtime::{traits::DispatchTransaction, transaction_validity::TransactionSource}; #[test] fn skip_feeless_payment_works() { let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); assert_eq!(PrepareCount::get(), 1); let call = RuntimeCall::DummyPallet(Call::::aux { data: 0 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); assert_eq!(PrepareCount::get(), 1); } @@ -41,14 +41,28 @@ fn validate_works() { let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_only(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_only( + Some(0).into(), + &call, + &DispatchInfo::default(), + 0, + TransactionSource::External, + 0, + ) .unwrap(); assert_eq!(ValidateCount::get(), 1); assert_eq!(PrepareCount::get(), 0); let call = RuntimeCall::DummyPallet(Call::::aux { data: 0 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_only(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_only( + Some(0).into(), + &call, + &DispatchInfo::default(), + 0, + TransactionSource::External, + 0, + ) .unwrap(); assert_eq!(ValidateCount::get(), 1); assert_eq!(PrepareCount::get(), 0); @@ -60,14 +74,14 @@ fn validate_prepare_works() { let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); assert_eq!(ValidateCount::get(), 1); assert_eq!(PrepareCount::get(), 1); let call = RuntimeCall::DummyPallet(Call::::aux { data: 0 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); assert_eq!(ValidateCount::get(), 1); assert_eq!(PrepareCount::get(), 1); @@ -75,7 +89,7 @@ fn validate_prepare_works() { // Changes from previous prepare calls persist. let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); assert_eq!(ValidateCount::get(), 2); assert_eq!(PrepareCount::get(), 2); diff --git a/substrate/frame/transaction-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/src/benchmarking.rs index c5f87fb8c12c..eba4c0964ce7 100644 --- a/substrate/frame/transaction-payment/src/benchmarking.rs +++ b/substrate/frame/transaction-payment/src/benchmarking.rs @@ -68,7 +68,7 @@ mod benchmarks { #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 10, |_| Ok( + .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 10, 0, |_| Ok( post_info )) .unwrap() diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index 711189be8d07..216697beac69 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -54,6 +54,7 @@ use frame_support::{ dispatch::{ DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo, }, + pallet_prelude::TransactionSource, traits::{Defensive, EstimateCallFee, Get}, weights::{Weight, WeightToFee}, RuntimeDebugNoBound, @@ -402,6 +403,7 @@ pub mod pallet { } #[pallet::storage] + #[pallet::whitelist_storage] pub type NextFeeMultiplier = StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>; @@ -916,6 +918,7 @@ where len: usize, _: (), _implication: &impl Encode, + _source: TransactionSource, ) -> Result< (ValidTransaction, Self::Val, ::RuntimeOrigin), TransactionValidityError, diff --git a/substrate/frame/transaction-payment/src/payment.rs b/substrate/frame/transaction-payment/src/payment.rs index 4b39cd3fe53b..b8a047fee3e6 100644 --- a/substrate/frame/transaction-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/src/payment.rs @@ -155,14 +155,15 @@ where if let Some(paid) = already_withdrawn { // Calculate how much refund we should return let refund_amount = paid.peek().saturating_sub(corrected_fee); - // refund to the the account that paid the fees if it exists. otherwise, don't refind - // anything. - let refund_imbalance = if F::total_balance(who) > F::Balance::zero() { - F::deposit(who, refund_amount, Precision::BestEffort) - .unwrap_or_else(|_| Debt::::zero()) - } else { - Debt::::zero() - }; + // Refund to the the account that paid the fees if it exists & refund is non-zero. + // Otherwise, don't refund anything. + let refund_imbalance = + if refund_amount > Zero::zero() && F::total_balance(who) > F::Balance::zero() { + F::deposit(who, refund_amount, Precision::BestEffort) + .unwrap_or_else(|_| Debt::::zero()) + } else { + Debt::::zero() + }; // merge the imbalance caused by paying the fees and refunding parts of it again. let adjusted_paid: Credit = paid .offset(refund_imbalance) diff --git a/substrate/frame/transaction-payment/src/tests.rs b/substrate/frame/transaction-payment/src/tests.rs index e8f5ab99529f..bde1bf64728e 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -23,7 +23,7 @@ use codec::Encode; use sp_runtime::{ generic::UncheckedExtrinsic, traits::{DispatchTransaction, One}, - transaction_validity::InvalidTransaction, + transaction_validity::{InvalidTransaction, TransactionSource::External}, BuildStorage, }; @@ -144,7 +144,7 @@ fn transaction_extension_transaction_payment_work() { let ext = Ext::from(0); let ext_weight = ext.weight(CALL); info.extension_weight = ext_weight; - ext.test_run(Some(1).into(), CALL, &info, 10, |_| { + ext.test_run(Some(1).into(), CALL, &info, 10, 0, |_| { assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10 - 10); Ok(default_post_info()) }) @@ -159,7 +159,7 @@ fn transaction_extension_transaction_payment_work() { let mut info = info_from_weight(Weight::from_parts(100, 0)); info.extension_weight = ext_weight; Ext::from(5 /* tipped */) - .test_run(Some(2).into(), CALL, &info, 10, |_| { + .test_run(Some(2).into(), CALL, &info, 10, 0, |_| { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 10 - 5); Ok(post_info_from_weight(Weight::from_parts(50, 0))) }) @@ -186,7 +186,7 @@ fn transaction_extension_transaction_payment_multiplied_refund_works() { let ext = Ext::from(5 /* tipped */); let ext_weight = ext.weight(CALL); info.extension_weight = ext_weight; - ext.test_run(origin, CALL, &info, len, |_| { + ext.test_run(origin, CALL, &info, len, 0, |_| { // 5 base fee, 10 byte fee, 3/2 * (100 call weight fee + 10 ext weight fee), 5 // tip assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 165 - 5); @@ -206,7 +206,7 @@ fn transaction_extension_transaction_payment_is_bounded() { ExtBuilder::default().balance_factor(1000).byte_fee(0).build().execute_with(|| { // maximum weight possible let info = info_from_weight(Weight::MAX); - assert_ok!(Ext::from(0).validate_and_prepare(Some(1).into(), CALL, &info, 10)); + assert_ok!(Ext::from(0).validate_and_prepare(Some(1).into(), CALL, &info, 10, 0)); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), @@ -235,7 +235,7 @@ fn transaction_extension_allows_free_transactions() { class: DispatchClass::Operational, pays_fee: Pays::No, }; - assert_ok!(Ext::from(0).validate_only(Some(1).into(), CALL, &op_tx, len)); + assert_ok!(Ext::from(0).validate_only(Some(1).into(), CALL, &op_tx, len, External, 0)); // like a InsecureFreeNormal let free_tx = DispatchInfo { @@ -245,7 +245,9 @@ fn transaction_extension_allows_free_transactions() { pays_fee: Pays::Yes, }; assert_eq!( - Ext::from(0).validate_only(Some(1).into(), CALL, &free_tx, len).unwrap_err(), + Ext::from(0) + .validate_only(Some(1).into(), CALL, &free_tx, len, External, 0) + .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Payment), ); }); @@ -262,7 +264,7 @@ fn transaction_ext_length_fee_is_also_updated_per_congestion() { NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); let len = 10; let info = info_from_weight(Weight::from_parts(3, 0)); - assert_ok!(Ext::from(10).validate_and_prepare(Some(1).into(), CALL, &info, len)); + assert_ok!(Ext::from(10).validate_and_prepare(Some(1).into(), CALL, &info, len, 0)); assert_eq!( Balances::free_balance(1), 100 // original @@ -524,7 +526,7 @@ fn refund_does_not_recreate_account() { System::set_block_number(10); let info = info_from_weight(Weight::from_parts(100, 0)); Ext::from(5 /* tipped */) - .test_run(Some(2).into(), CALL, &info, 10, |origin| { + .test_run(Some(2).into(), CALL, &info, 10, 0, |origin| { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); // kill the account between pre and post dispatch @@ -562,7 +564,7 @@ fn actual_weight_higher_than_max_refunds_nothing() { .execute_with(|| { let info = info_from_weight(Weight::from_parts(100, 0)); Ext::from(5 /* tipped */) - .test_run(Some(2).into(), CALL, &info, 10, |_| { + .test_run(Some(2).into(), CALL, &info, 10, 0, |_| { assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); Ok(post_info_from_weight(Weight::from_parts(101, 0))) }) @@ -589,7 +591,7 @@ fn zero_transfer_on_free_transaction() { }; let user = 69; Ext::from(0) - .test_run(Some(user).into(), CALL, &info, 10, |_| { + .test_run(Some(user).into(), CALL, &info, 10, 0, |_| { assert_eq!(Balances::total_balance(&user), 0); Ok(default_post_info()) }) @@ -626,7 +628,7 @@ fn refund_consistent_with_actual_weight() { NextFeeMultiplier::::put(Multiplier::saturating_from_rational(5, 4)); let actual_post_info = ext - .test_run(Some(2).into(), CALL, &info, len, |_| Ok(post_info)) + .test_run(Some(2).into(), CALL, &info, len, 0, |_| Ok(post_info)) .unwrap() .unwrap(); post_info @@ -659,11 +661,19 @@ fn should_alter_operational_priority() { }; let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + let priority = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) + .unwrap() + .0 + .priority; assert_eq!(priority, 60); let ext = Ext::from(2 * tip); - let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + let priority = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) + .unwrap() + .0 + .priority; assert_eq!(priority, 110); }); @@ -676,11 +686,19 @@ fn should_alter_operational_priority() { }; let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + let priority = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) + .unwrap() + .0 + .priority; assert_eq!(priority, 5810); let ext = Ext::from(2 * tip); - let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + let priority = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) + .unwrap() + .0 + .priority; assert_eq!(priority, 6110); }); } @@ -698,7 +716,11 @@ fn no_tip_has_some_priority() { pays_fee: Pays::Yes, }; let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + let priority = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) + .unwrap() + .0 + .priority; assert_eq!(priority, 10); }); @@ -710,7 +732,11 @@ fn no_tip_has_some_priority() { pays_fee: Pays::Yes, }; let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + let priority = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) + .unwrap() + .0 + .priority; assert_eq!(priority, 5510); }); } @@ -729,7 +755,12 @@ fn higher_tip_have_higher_priority() { pays_fee: Pays::Yes, }; let ext = Ext::from(tip); - pri1 = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + + pri1 = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) + .unwrap() + .0 + .priority; }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { @@ -740,7 +771,11 @@ fn higher_tip_have_higher_priority() { pays_fee: Pays::Yes, }; let ext = Ext::from(tip); - pri2 = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + pri2 = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) + .unwrap() + .0 + .priority; }); (pri1, pri2) @@ -772,7 +807,7 @@ fn post_info_can_change_pays_fee() { NextFeeMultiplier::::put(Multiplier::saturating_from_rational(5, 4)); let post_info = ChargeTransactionPayment::::from(tip) - .test_run(Some(2).into(), CALL, &info, len, |_| Ok(post_info)) + .test_run(Some(2).into(), CALL, &info, len, 0, |_| Ok(post_info)) .unwrap() .unwrap(); @@ -820,7 +855,7 @@ fn no_fee_and_no_weight_for_other_origins() { let len = CALL.encoded_size(); let origin = frame_system::RawOrigin::Root.into(); - let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len).unwrap(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); assert!(origin.as_system_ref().unwrap().is_root()); @@ -842,3 +877,40 @@ fn no_fee_and_no_weight_for_other_origins() { assert_eq!(post_info.actual_weight, Some(info.call_weight)); }) } + +#[test] +fn fungible_adapter_no_zero_refund_action() { + type FungibleAdapterT = payment::FungibleAdapter; + + ExtBuilder::default().balance_factor(10).build().execute_with(|| { + System::set_block_number(10); + + let dummy_acc = 1; + let (actual_fee, no_tip) = (10, 0); + let already_paid = >::withdraw_fee( + &dummy_acc, + CALL, + &CALL.get_dispatch_info(), + actual_fee, + no_tip, + ).expect("Account must have enough funds."); + + // Correction action with no expected side effect. + assert!(>::correct_and_deposit_fee( + &dummy_acc, + &CALL.get_dispatch_info(), + &default_post_info(), + actual_fee, + no_tip, + already_paid, + ).is_ok()); + + // Ensure no zero amount deposit event is emitted. + let events = System::events(); + assert!(!events + .iter() + .any(|record| matches!(record.event, RuntimeEvent::Balances(pallet_balances::Event::Deposit { amount, .. }) if amount.is_zero())), + "No zero amount deposit amount event should be emitted.", + ); + }); +} diff --git a/substrate/frame/transaction-payment/src/weights.rs b/substrate/frame/transaction-payment/src/weights.rs index bcffb2eb331a..59d5cac7a2b7 100644 --- a/substrate/frame/transaction-payment/src/weights.rs +++ b/substrate/frame/transaction-payment/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_transaction_payment` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -57,36 +57,30 @@ pub trait WeightInfo { /// Weights for `pallet_transaction_payment` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn charge_transaction_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 40_506_000 picoseconds. - Weight::from_parts(41_647_000, 1733) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 39_528_000 picoseconds. + Weight::from_parts(40_073_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn charge_transaction_payment() -> Weight { // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 40_506_000 picoseconds. - Weight::from_parts(41_647_000, 1733) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 39_528_000 picoseconds. + Weight::from_parts(40_073_000, 3593) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index f5d6bd1c364c..0ca38e9dd60d 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -18,17 +18,17 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { optional = true, workspace = true, default-features = true } codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } pallet-balances = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, workspace = true, default-features = true } sp-inherents = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-transaction-storage-proof = { workspace = true } -log = { workspace = true } [dev-dependencies] sp-core = { workspace = true } diff --git a/substrate/frame/transaction-storage/src/benchmarking.rs b/substrate/frame/transaction-storage/src/benchmarking.rs index f360e9847a1e..0b5b0dc99405 100644 --- a/substrate/frame/transaction-storage/src/benchmarking.rs +++ b/substrate/frame/transaction-storage/src/benchmarking.rs @@ -19,16 +19,14 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; +use crate::*; use alloc::{vec, vec::Vec}; -use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_support::traits::{Get, OnFinalize, OnInitialize}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, Pallet as System, RawOrigin}; use sp_runtime::traits::{Bounded, CheckedDiv, One, Zero}; use sp_transaction_storage_proof::TransactionStorageProof; -use crate::Pallet as TransactionStorage; - // Proof generated from max size storage: // ``` // let mut transactions = Vec::new(); @@ -122,39 +120,50 @@ pub fn run_to_block(n: frame_system::pallet_prelude::BlockNumberFor) { let caller: T::AccountId = whitelisted_caller(); let initial_balance = BalanceOf::::max_value().checked_div(&2u32.into()).unwrap(); T::Currency::set_balance(&caller, initial_balance); - }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize]); + assert!(!BlockTransactions::::get().is_empty()); assert_last_event::(Event::Stored { index: 0 }.into()); } - renew { + #[benchmark] + fn renew() -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let initial_balance = BalanceOf::::max_value().checked_div(&2u32.into()).unwrap(); T::Currency::set_balance(&caller, initial_balance); - TransactionStorage::::store( + Pallet::::store( RawOrigin::Signed(caller.clone()).into(), vec![0u8; T::MaxTransactionSize::get() as usize], )?; run_to_block::(1u32.into()); - }: _(RawOrigin::Signed(caller.clone()), BlockNumberFor::::zero(), 0) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), BlockNumberFor::::zero(), 0); + assert_last_event::(Event::Renewed { index: 0 }.into()); + + Ok(()) } - check_proof_max { + #[benchmark] + fn check_proof_max() -> Result<(), BenchmarkError> { run_to_block::(1u32.into()); let caller: T::AccountId = whitelisted_caller(); let initial_balance = BalanceOf::::max_value().checked_div(&2u32.into()).unwrap(); T::Currency::set_balance(&caller, initial_balance); - for _ in 0 .. T::MaxBlockTransactions::get() { - TransactionStorage::::store( + for _ in 0..T::MaxBlockTransactions::get() { + Pallet::::store( RawOrigin::Signed(caller.clone()).into(), vec![0u8; T::MaxTransactionSize::get() as usize], )?; @@ -162,10 +171,14 @@ benchmarks! { run_to_block::(StoragePeriod::::get() + BlockNumberFor::::one()); let encoded_proof = proof(); let proof = TransactionStorageProof::decode(&mut &*encoded_proof).unwrap(); - }: check_proof(RawOrigin::None, proof) - verify { + + #[extrinsic_call] + check_proof(RawOrigin::None, proof); + assert_last_event::(Event::ProofChecked.into()); + + Ok(()) } - impl_benchmark_test_suite!(TransactionStorage, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, mock::new_test_ext(), mock::Test); } diff --git a/substrate/frame/transaction-storage/src/weights.rs b/substrate/frame/transaction-storage/src/weights.rs index 4d51daa17b40..36681f0abd8b 100644 --- a/substrate/frame/transaction-storage/src/weights.rs +++ b/substrate/frame/transaction-storage/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_transaction_storage` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -64,7 +64,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 8388608]`. @@ -72,10 +72,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `242` // Estimated: `38351` - // Minimum execution time: 62_024_000 picoseconds. - Weight::from_parts(63_536_000, 38351) - // Standard Error: 13 - .saturating_add(Weight::from_parts(7_178, 0).saturating_mul(l.into())) + // Minimum execution time: 65_899_000 picoseconds. + Weight::from_parts(66_814_000, 38351) + // Standard Error: 7 + .saturating_add(Weight::from_parts(7_678, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -86,15 +86,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: // Measured: `430` // Estimated: `40351` - // Minimum execution time: 81_473_000 picoseconds. - Weight::from_parts(84_000_000, 40351) + // Minimum execution time: 87_876_000 picoseconds. + Weight::from_parts(91_976_000, 40351) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -112,8 +112,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `37211` // Estimated: `40351` - // Minimum execution time: 68_167_000 picoseconds. - Weight::from_parts(75_532_000, 40351) + // Minimum execution time: 78_423_000 picoseconds. + Weight::from_parts(82_423_000, 40351) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -126,7 +126,7 @@ impl WeightInfo for () { /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 8388608]`. @@ -134,10 +134,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `242` // Estimated: `38351` - // Minimum execution time: 62_024_000 picoseconds. - Weight::from_parts(63_536_000, 38351) - // Standard Error: 13 - .saturating_add(Weight::from_parts(7_178, 0).saturating_mul(l.into())) + // Minimum execution time: 65_899_000 picoseconds. + Weight::from_parts(66_814_000, 38351) + // Standard Error: 7 + .saturating_add(Weight::from_parts(7_678, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -148,15 +148,15 @@ impl WeightInfo for () { /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: // Measured: `430` // Estimated: `40351` - // Minimum execution time: 81_473_000 picoseconds. - Weight::from_parts(84_000_000, 40351) + // Minimum execution time: 87_876_000 picoseconds. + Weight::from_parts(91_976_000, 40351) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -174,8 +174,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `37211` // Estimated: `40351` - // Minimum execution time: 68_167_000 picoseconds. - Weight::from_parts(75_532_000, 40351) + // Minimum execution time: 78_423_000 picoseconds. + Weight::from_parts(82_423_000, 40351) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 93a3d9bea93d..c6f059f5fa03 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -21,21 +21,21 @@ codec = { features = [ "max-encoded-len", ], workspace = true } docify = { workspace = true } -impl-trait-for-tuples = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +impl-trait-for-tuples = { workspace = true } +log = { workspace = true } pallet-balances = { workspace = true } -sp-runtime = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["derive"], optional = true, workspace = true, default-features = true } sp-core = { optional = true, workspace = true } -log = { workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] -sp-io = { workspace = true, default-features = true } pallet-utility = { workspace = true, default-features = true } sp-core = { workspace = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index 650e5376fa4b..a11723a27b2c 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -78,6 +78,7 @@ fn create_approved_proposals, I: 'static>(n: u32) -> Result<(), &'s for i in 0..n { let (_, value, lookup) = setup_proposal::(i); + #[allow(deprecated)] if let Ok(origin) = &spender { Treasury::::spend_local(origin.clone(), value, lookup)?; } @@ -136,6 +137,7 @@ mod benchmarks { let (spend_exists, proposal_id) = if let Ok(origin) = T::SpendOrigin::try_successful_origin() { let (_, value, beneficiary_lookup) = setup_proposal::(SEED); + #[allow(deprecated)] Treasury::::spend_local(origin, value, beneficiary_lookup)?; let proposal_id = ProposalCount::::get() - 1; @@ -149,8 +151,8 @@ mod benchmarks { #[block] { - let res = - Treasury::::remove_approval(reject_origin as T::RuntimeOrigin, proposal_id); + #[allow(deprecated)] + let res = Treasury::::remove_approval(reject_origin as T::RuntimeOrigin, proposal_id); if spend_exists { assert_ok!(res); @@ -196,7 +198,7 @@ mod benchmarks { None, ); - let valid_from = frame_system::Pallet::::block_number(); + let valid_from = T::BlockNumberProvider::current_block_number(); let expire_at = valid_from.saturating_add(T::PayoutPeriod::get()); assert_last_event::( Event::AssetSpendApproved { diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index b21a36949357..281012ffb4c9 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -106,7 +106,7 @@ use frame_support::{ weights::Weight, BoundedVec, PalletId, }; -use frame_system::pallet_prelude::BlockNumberFor; +use frame_system::pallet_prelude::BlockNumberFor as SystemBlockNumberFor; pub use pallet::*; pub use weights::WeightInfo; @@ -122,6 +122,8 @@ pub type NegativeImbalanceOf = <>::Currency as Currenc >>::NegativeImbalance; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type BeneficiaryLookupOf = <>::BeneficiaryLookup as StaticLookup>::Source; +pub type BlockNumberFor = + <>::BlockNumberProvider as BlockNumberProvider>::BlockNumber; /// A trait to allow the Treasury Pallet to spend it's funds for other purposes. /// There is an expectation that the implementer of this trait will correctly manage @@ -202,7 +204,7 @@ pub mod pallet { pallet_prelude::*, traits::tokens::{ConversionFromAssetBalance, PaymentStatus}, }; - use frame_system::pallet_prelude::*; + use frame_system::pallet_prelude::{ensure_signed, OriginFor}; #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); @@ -221,7 +223,7 @@ pub mod pallet { /// Period between successive spends. #[pallet::constant] - type SpendPeriod: Get>; + type SpendPeriod: Get>; /// Percentage of spare funds (if any) that are burnt per spend period. #[pallet::constant] @@ -240,6 +242,9 @@ pub mod pallet { /// Runtime hooks to external pallet using treasury to compute spend funds. type SpendFunds: SpendFunds; + /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. + /// Refer to for migration to `spend`. + /// /// The maximum number of approvals that can wait in the spending queue. /// /// NOTE: This parameter is also used within the Bounties Pallet extension if enabled. @@ -274,20 +279,26 @@ pub mod pallet { /// The period during which an approved treasury spend has to be claimed. #[pallet::constant] - type PayoutPeriod: Get>; + type PayoutPeriod: Get>; /// Helper type for benchmarks. #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper: ArgumentsFactory; /// Provider for the block number. Normally this is the `frame_system` pallet. - type BlockNumberProvider: BlockNumberProvider>; + type BlockNumberProvider: BlockNumberProvider; } + /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. + /// Refer to for migration to `spend`. + /// /// Number of proposals that have been made. #[pallet::storage] pub type ProposalCount = StorageValue<_, ProposalIndex, ValueQuery>; + /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. + /// Refer to for migration to `spend`. + /// /// Proposals that have been made. #[pallet::storage] pub type Proposals, I: 'static = ()> = StorageMap< @@ -303,6 +314,9 @@ pub mod pallet { pub type Deactivated, I: 'static = ()> = StorageValue<_, BalanceOf, ValueQuery>; + /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. + /// Refer to for migration to `spend`. + /// /// Proposal indices that have been approved but not yet awarded. #[pallet::storage] pub type Approvals, I: 'static = ()> = @@ -323,7 +337,7 @@ pub mod pallet { T::AssetKind, AssetBalanceOf, T::Beneficiary, - BlockNumberFor, + BlockNumberFor, ::Id, >, OptionQuery, @@ -331,7 +345,7 @@ pub mod pallet { /// The blocknumber for the last triggered spend period. #[pallet::storage] - pub(crate) type LastSpendPeriod = StorageValue<_, BlockNumberFor, OptionQuery>; + pub(crate) type LastSpendPeriod = StorageValue<_, BlockNumberFor, OptionQuery>; #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] @@ -379,8 +393,8 @@ pub mod pallet { asset_kind: T::AssetKind, amount: AssetBalanceOf, beneficiary: T::Beneficiary, - valid_from: BlockNumberFor, - expire_at: BlockNumberFor, + valid_from: BlockNumberFor, + expire_at: BlockNumberFor, }, /// An approved spend was voided. AssetSpendVoided { index: SpendIndex }, @@ -422,10 +436,10 @@ pub mod pallet { } #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet { + impl, I: 'static> Hooks> for Pallet { /// ## Complexity /// - `O(A)` where `A` is the number of approvals - fn on_initialize(_do_not_use_local_block_number: BlockNumberFor) -> Weight { + fn on_initialize(_do_not_use_local_block_number: SystemBlockNumberFor) -> Weight { let block_number = T::BlockNumberProvider::current_block_number(); let pot = Self::pot(); let deactivated = Deactivated::::get(); @@ -446,7 +460,7 @@ pub mod pallet { // empty. .unwrap_or_else(|| Self::update_last_spend_period()); let blocks_since_last_spend_period = block_number.saturating_sub(last_spend_period); - let safe_spend_period = T::SpendPeriod::get().max(BlockNumberFor::::one()); + let safe_spend_period = T::SpendPeriod::get().max(BlockNumberFor::::one()); // Safe because of `max(1)` above. let (spend_periods_passed, extra_blocks) = ( @@ -454,7 +468,7 @@ pub mod pallet { blocks_since_last_spend_period % safe_spend_period, ); let new_last_spend_period = block_number.saturating_sub(extra_blocks); - if spend_periods_passed > BlockNumberFor::::zero() { + if spend_periods_passed > BlockNumberFor::::zero() { Self::spend_funds(spend_periods_passed, new_last_spend_period) } else { Weight::zero() @@ -462,7 +476,7 @@ pub mod pallet { } #[cfg(feature = "try-runtime")] - fn try_state(_: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + fn try_state(_: SystemBlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { Self::do_try_state()?; Ok(()) } @@ -494,6 +508,10 @@ pub mod pallet { /// Emits [`Event::SpendApproved`] if successful. #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::spend_local())] + #[deprecated( + note = "The `spend_local` call will be removed by May 2025. Migrate to the new flow and use the `spend` call." + )] + #[allow(deprecated)] pub fn spend_local( origin: OriginFor, #[pallet::compact] amount: BalanceOf, @@ -523,7 +541,9 @@ pub mod pallet { .unwrap_or(Ok(()))?; let beneficiary = T::Lookup::lookup(beneficiary)?; + #[allow(deprecated)] let proposal_index = ProposalCount::::get(); + #[allow(deprecated)] Approvals::::try_append(proposal_index) .map_err(|_| Error::::TooManyApprovals)?; let proposal = Proposal { @@ -532,7 +552,9 @@ pub mod pallet { beneficiary: beneficiary.clone(), bond: Default::default(), }; + #[allow(deprecated)] Proposals::::insert(proposal_index, proposal); + #[allow(deprecated)] ProposalCount::::put(proposal_index + 1); Self::deposit_event(Event::SpendApproved { proposal_index, amount, beneficiary }); @@ -562,12 +584,17 @@ pub mod pallet { /// in the first place. #[pallet::call_index(4)] #[pallet::weight((T::WeightInfo::remove_approval(), DispatchClass::Operational))] + #[deprecated( + note = "The `remove_approval` call will be removed by May 2025. It associated with the deprecated `spend_local` call." + )] + #[allow(deprecated)] pub fn remove_approval( origin: OriginFor, #[pallet::compact] proposal_id: ProposalIndex, ) -> DispatchResult { T::RejectOrigin::ensure_origin(origin)?; + #[allow(deprecated)] Approvals::::try_mutate(|v| -> DispatchResult { if let Some(index) = v.iter().position(|x| x == &proposal_id) { v.remove(index); @@ -613,7 +640,7 @@ pub mod pallet { asset_kind: Box, #[pallet::compact] amount: AssetBalanceOf, beneficiary: Box>, - valid_from: Option>, + valid_from: Option>, ) -> DispatchResult { let max_amount = T::SpendOrigin::ensure_origin(origin)?; let beneficiary = T::BeneficiaryLookup::lookup(*beneficiary)?; @@ -819,9 +846,9 @@ impl, I: 'static> Pallet { // Backfill the `LastSpendPeriod` storage, assuming that no configuration has changed // since introducing this code. Used specifically for a migration-less switch to populate // `LastSpendPeriod`. - fn update_last_spend_period() -> BlockNumberFor { + fn update_last_spend_period() -> BlockNumberFor { let block_number = T::BlockNumberProvider::current_block_number(); - let spend_period = T::SpendPeriod::get().max(BlockNumberFor::::one()); + let spend_period = T::SpendPeriod::get().max(BlockNumberFor::::one()); let time_since_last_spend = block_number % spend_period; // If it happens that this logic runs directly on a spend period block, we need to backdate // to the last spend period so a spend still occurs this block. @@ -836,24 +863,36 @@ impl, I: 'static> Pallet { } /// Public function to proposal_count storage. + #[deprecated( + note = "This function will be removed by May 2025. Configure pallet to use PayFromAccount for Paymaster type instead" + )] pub fn proposal_count() -> ProposalIndex { + #[allow(deprecated)] ProposalCount::::get() } /// Public function to proposals storage. + #[deprecated( + note = "This function will be removed by May 2025. Configure pallet to use PayFromAccount for Paymaster type instead" + )] pub fn proposals(index: ProposalIndex) -> Option>> { + #[allow(deprecated)] Proposals::::get(index) } /// Public function to approvals storage. + #[deprecated( + note = "This function will be removed by May 2025. Configure pallet to use PayFromAccount for Paymaster type instead" + )] + #[allow(deprecated)] pub fn approvals() -> BoundedVec { Approvals::::get() } /// Spend some money! returns number of approvals before spend. pub fn spend_funds( - spend_periods_passed: BlockNumberFor, - new_last_spend_period: BlockNumberFor, + spend_periods_passed: BlockNumberFor, + new_last_spend_period: BlockNumberFor, ) -> Weight { LastSpendPeriod::::put(new_last_spend_period); let mut total_weight = Weight::zero(); @@ -864,6 +903,7 @@ impl, I: 'static> Pallet { let mut missed_any = false; let mut imbalance = PositiveImbalanceOf::::zero(); + #[allow(deprecated)] let proposals_len = Approvals::::mutate(|v| { let proposals_approvals_len = v.len() as u32; v.retain(|&index| { diff --git a/substrate/frame/treasury/src/migration.rs b/substrate/frame/treasury/src/migration.rs index c0de4ce43108..7c8c587f1664 100644 --- a/substrate/frame/treasury/src/migration.rs +++ b/substrate/frame/treasury/src/migration.rs @@ -43,11 +43,13 @@ pub mod cleanup_proposals { { fn on_runtime_upgrade() -> frame_support::weights::Weight { let mut approval_index = BTreeSet::new(); + #[allow(deprecated)] for approval in Approvals::::get().iter() { approval_index.insert(*approval); } let mut proposals_processed = 0; + #[allow(deprecated)] for (proposal_index, p) in Proposals::::iter() { if !approval_index.contains(&proposal_index) { let err_amount = T::Currency::unreserve(&p.proposer, p.bond); diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index a99dd0dd4449..e9efb7c0956f 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -249,6 +249,7 @@ fn genesis_config_works() { #[test] fn spend_local_origin_permissioning_works() { + #[allow(deprecated)] ExtBuilder::default().build().execute_with(|| { assert_noop!(Treasury::spend_local(RuntimeOrigin::signed(1), 1, 1), BadOrigin); assert_noop!( @@ -273,6 +274,7 @@ fn spend_local_origin_permissioning_works() { #[docify::export] #[test] fn spend_local_origin_works() { + #[allow(deprecated)] ExtBuilder::default().build().execute_with(|| { // Check that accumulate works when we have Some value in Dummy already. Balances::make_free_balance_be(&Treasury::account_id(), 102); @@ -309,7 +311,10 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); + } go_to_block(1); assert_eq!(Balances::free_balance(3), 0); @@ -336,7 +341,10 @@ fn accepted_spend_proposal_enacted_on_spend_period() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); + } go_to_block(2); assert_eq!(Balances::free_balance(3), 100); @@ -350,7 +358,10 @@ fn pot_underflow_should_not_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 150, 3)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 150, 3)); + } go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -370,13 +381,19 @@ fn treasury_account_doesnt_get_deleted() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), treasury_balance, 3)); + >::on_initialize(2); + assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), treasury_balance, 3)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), treasury_balance, 3)); - go_to_block(2); - assert_eq!(Treasury::pot(), 100); // Pot hasn't changed + go_to_block(2); + assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), Treasury::pot(), 3)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), Treasury::pot(), 3)); + } go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -399,8 +416,11 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 99, 3)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 99, 3)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); + } go_to_block(2); @@ -439,6 +459,7 @@ fn genesis_funding_works() { #[test] fn max_approvals_limited() { + #[allow(deprecated)] ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), u64::MAX); Balances::make_free_balance_be(&0, u64::MAX); @@ -457,6 +478,7 @@ fn max_approvals_limited() { #[test] fn remove_already_removed_approval_fails() { + #[allow(deprecated)] ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -796,7 +818,10 @@ fn try_state_proposals_invariant_1_works() { ExtBuilder::default().build().execute_with(|| { use frame_support::pallet_prelude::DispatchError::Other; // Add a proposal and approve using `spend_local` - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); + } assert_eq!(Proposals::::iter().count(), 1); assert_eq!(ProposalCount::::get(), 1); @@ -816,8 +841,11 @@ fn try_state_proposals_invariant_1_works() { fn try_state_proposals_invariant_2_works() { ExtBuilder::default().build().execute_with(|| { use frame_support::pallet_prelude::DispatchError::Other; - // Add a proposal and approve using `spend_local` - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); + #[allow(deprecated)] + { + // Add a proposal and approve using `spend_local` + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); + } assert_eq!(Proposals::::iter().count(), 1); assert_eq!(Approvals::::get().len(), 1); @@ -846,7 +874,10 @@ fn try_state_proposals_invariant_3_works() { ExtBuilder::default().build().execute_with(|| { use frame_support::pallet_prelude::DispatchError::Other; // Add a proposal and approve using `spend_local` - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 10, 3)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 10, 3)); + } assert_eq!(Proposals::::iter().count(), 1); assert_eq!(Approvals::::get().len(), 1); @@ -952,13 +983,16 @@ fn multiple_spend_periods_work() { // 100 will be spent, 1024 will be the burn amount, 1 for ED Balances::make_free_balance_be(&Treasury::account_id(), 100 + 1024 + 1); // approve spend of total amount 100 to beneficiary `6`. - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(11), 10, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(12), 20, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(13), 50, 6)); + #[allow(deprecated)] + { + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(11), 10, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(12), 20, 6)); + assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(13), 50, 6)); + } // free balance of `6` is zero, spend period has not passed. go_to_block(1); assert_eq!(Balances::free_balance(6), 0); diff --git a/substrate/frame/treasury/src/weights.rs b/substrate/frame/treasury/src/weights.rs index 8c9c6eb1d0fb..f5063eb881c4 100644 --- a/substrate/frame/treasury/src/weights.rs +++ b/substrate/frame/treasury/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_treasury` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -73,64 +73,55 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1887` - // Minimum execution time: 11_910_000 picoseconds. - Weight::from_parts(12_681_000, 1887) + // Minimum execution time: 11_807_000 picoseconds. + Weight::from_parts(12_313_000, 1887) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) fn remove_approval() -> Weight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `1887` - // Minimum execution time: 6_372_000 picoseconds. - Weight::from_parts(6_567_000, 1887) + // Minimum execution time: 7_217_000 picoseconds. + Weight::from_parts(7_516_000, 1887) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Treasury::Deactivated` (r:1 w:1) /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:99 w:99) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:198 w:198) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::LastSpendPeriod` (r:1 w:1) + /// Proof: `Treasury::LastSpendPeriod` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `451 + p * (251 ±0)` - // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 33_150_000 picoseconds. - Weight::from_parts(41_451_020, 1887) - // Standard Error: 19_018 - .saturating_add(Weight::from_parts(34_410_759, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) + // Measured: `170` + // Estimated: `1501` + // Minimum execution time: 10_929_000 picoseconds. + Weight::from_parts(13_737_454, 1501) + // Standard Error: 790 + .saturating_add(Weight::from_parts(33_673, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) /// Storage: `Treasury::SpendCount` (r:1 w:1) /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Treasury::Spends` (r:0 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) fn spend() -> Weight { // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `3501` - // Minimum execution time: 14_233_000 picoseconds. - Weight::from_parts(14_842_000, 3501) + // Measured: `141` + // Estimated: `3502` + // Minimum execution time: 16_082_000 picoseconds. + Weight::from_parts(16_542_000, 3502) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:2 w:2) @@ -139,32 +130,32 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `709` + // Measured: `710` // Estimated: `6208` - // Minimum execution time: 58_857_000 picoseconds. - Weight::from_parts(61_291_000, 6208) + // Minimum execution time: 64_180_000 picoseconds. + Weight::from_parts(65_783_000, 6208) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 12_116_000 picoseconds. - Weight::from_parts(12_480_000, 3538) + // Measured: `199` + // Estimated: `3539` + // Minimum execution time: 13_379_000 picoseconds. + Weight::from_parts(13_751_000, 3539) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 10_834_000 picoseconds. - Weight::from_parts(11_427_000, 3538) + // Measured: `199` + // Estimated: `3539` + // Minimum execution time: 12_014_000 picoseconds. + Weight::from_parts(12_423_000, 3539) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -182,64 +173,55 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1887` - // Minimum execution time: 11_910_000 picoseconds. - Weight::from_parts(12_681_000, 1887) + // Minimum execution time: 11_807_000 picoseconds. + Weight::from_parts(12_313_000, 1887) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) fn remove_approval() -> Weight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `1887` - // Minimum execution time: 6_372_000 picoseconds. - Weight::from_parts(6_567_000, 1887) + // Minimum execution time: 7_217_000 picoseconds. + Weight::from_parts(7_516_000, 1887) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Treasury::Deactivated` (r:1 w:1) /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:99 w:99) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:198 w:198) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::LastSpendPeriod` (r:1 w:1) + /// Proof: `Treasury::LastSpendPeriod` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `451 + p * (251 ±0)` - // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 33_150_000 picoseconds. - Weight::from_parts(41_451_020, 1887) - // Standard Error: 19_018 - .saturating_add(Weight::from_parts(34_410_759, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(p.into()))) - .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) + // Measured: `170` + // Estimated: `1501` + // Minimum execution time: 10_929_000 picoseconds. + Weight::from_parts(13_737_454, 1501) + // Standard Error: 790 + .saturating_add(Weight::from_parts(33_673, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) /// Storage: `Treasury::SpendCount` (r:1 w:1) /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Treasury::Spends` (r:0 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) fn spend() -> Weight { // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `3501` - // Minimum execution time: 14_233_000 picoseconds. - Weight::from_parts(14_842_000, 3501) + // Measured: `141` + // Estimated: `3502` + // Minimum execution time: 16_082_000 picoseconds. + Weight::from_parts(16_542_000, 3502) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:1 w:1) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:2 w:2) @@ -248,32 +230,32 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `709` + // Measured: `710` // Estimated: `6208` - // Minimum execution time: 58_857_000 picoseconds. - Weight::from_parts(61_291_000, 6208) + // Minimum execution time: 64_180_000 picoseconds. + Weight::from_parts(65_783_000, 6208) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 12_116_000 picoseconds. - Weight::from_parts(12_480_000, 3538) + // Measured: `199` + // Estimated: `3539` + // Minimum execution time: 13_379_000 picoseconds. + Weight::from_parts(13_751_000, 3539) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 10_834_000 picoseconds. - Weight::from_parts(11_427_000, 3538) + // Measured: `199` + // Estimated: `3539` + // Minimum execution time: 12_014_000 picoseconds. + Weight::from_parts(12_423_000, 3539) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 03c700ec053c..6298645fb2b3 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -20,18 +20,18 @@ docify = { workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } -scale-info = { features = ["derive"], workspace = true } -sp-runtime = { workspace = true } pallet-balances = { optional = true, workspace = true } -pallet-utility = { optional = true, workspace = true } pallet-proxy = { optional = true, workspace = true } +pallet-utility = { optional = true, workspace = true } +scale-info = { features = ["derive"], workspace = true } +sp-runtime = { workspace = true } [dev-dependencies] -sp-core = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } pallet-proxy = { workspace = true, default-features = true } +pallet-utility = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 84ce45e83528..fd9b3b552ccd 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -105,6 +105,7 @@ impl pallet_proxy::Config for Test { type MaxPending = ConstU32<2>; type AnnouncementDepositBase = ConstU64<1>; type AnnouncementDepositFactor = ConstU64<1>; + type BlockNumberProvider = frame_system::Pallet; } parameter_types! { diff --git a/substrate/frame/tx-pause/src/weights.rs b/substrate/frame/tx-pause/src/weights.rs index e7837e9ca89c..67e1390e9c7d 100644 --- a/substrate/frame/tx-pause/src/weights.rs +++ b/substrate/frame/tx-pause/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_tx_pause` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -64,8 +64,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3997` - // Minimum execution time: 12_218_000 picoseconds. - Weight::from_parts(12_542_000, 3997) + // Minimum execution time: 12_474_000 picoseconds. + Weight::from_parts(12_922_000, 3997) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `565` // Estimated: `3997` - // Minimum execution time: 18_314_000 picoseconds. - Weight::from_parts(18_990_000, 3997) + // Minimum execution time: 19_918_000 picoseconds. + Weight::from_parts(20_380_000, 3997) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -90,8 +90,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3997` - // Minimum execution time: 12_218_000 picoseconds. - Weight::from_parts(12_542_000, 3997) + // Minimum execution time: 12_474_000 picoseconds. + Weight::from_parts(12_922_000, 3997) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -101,8 +101,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `565` // Estimated: `3997` - // Minimum execution time: 18_314_000 picoseconds. - Weight::from_parts(18_990_000, 3997) + // Minimum execution time: 19_918_000 picoseconds. + Weight::from_parts(20_380_000, 3997) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index abd456d97556..135292fb4ecd 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -17,11 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/uniques/src/weights.rs b/substrate/frame/uniques/src/weights.rs index 5576c8921f9c..60c6f9316ec7 100644 --- a/substrate/frame/uniques/src/weights.rs +++ b/substrate/frame/uniques/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_uniques` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -88,10 +88,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `249` + // Measured: `282` // Estimated: `3643` - // Minimum execution time: 27_074_000 picoseconds. - Weight::from_parts(28_213_000, 3643) + // Minimum execution time: 31_956_000 picoseconds. + Weight::from_parts(33_104_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -101,10 +101,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `142` // Estimated: `3643` - // Minimum execution time: 12_034_000 picoseconds. - Weight::from_parts(12_669_000, 3643) + // Minimum execution time: 12_757_000 picoseconds. + Weight::from_parts(13_327_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -129,16 +129,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `418 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` + // Measured: `451 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` - // Minimum execution time: 2_928_174_000 picoseconds. - Weight::from_parts(2_970_367_000, 3643) - // Standard Error: 30_368 - .saturating_add(Weight::from_parts(7_336_699, 0).saturating_mul(n.into())) - // Standard Error: 30_368 - .saturating_add(Weight::from_parts(401_816, 0).saturating_mul(m.into())) - // Standard Error: 30_368 - .saturating_add(Weight::from_parts(346_952, 0).saturating_mul(a.into())) + // Minimum execution time: 3_236_461_000 picoseconds. + Weight::from_parts(3_291_013_000, 3643) + // Standard Error: 39_603 + .saturating_add(Weight::from_parts(8_285_170, 0).saturating_mul(n.into())) + // Standard Error: 39_603 + .saturating_add(Weight::from_parts(469_210, 0).saturating_mul(m.into())) + // Standard Error: 39_603 + .saturating_add(Weight::from_parts(546_865, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) @@ -161,10 +161,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 33_733_000 picoseconds. - Weight::from_parts(35_366_000, 3643) + // Minimum execution time: 39_056_000 picoseconds. + Weight::from_parts(40_157_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -178,10 +178,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 35_064_000 picoseconds. - Weight::from_parts(35_747_000, 3643) + // Minimum execution time: 39_462_000 picoseconds. + Weight::from_parts(41_368_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -195,10 +195,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 24_955_000 picoseconds. - Weight::from_parts(25_661_000, 3643) + // Minimum execution time: 30_639_000 picoseconds. + Weight::from_parts(31_523_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -209,12 +209,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `805 + i * (76 ±0)` + // Measured: `838 + i * (76 ±0)` // Estimated: `3643 + i * (2597 ±0)` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_490_000, 3643) - // Standard Error: 14_697 - .saturating_add(Weight::from_parts(15_720_495, 0).saturating_mul(i.into())) + // Minimum execution time: 16_920_000 picoseconds. + Weight::from_parts(17_096_000, 3643) + // Standard Error: 24_966 + .saturating_add(Weight::from_parts(18_491_945, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -227,10 +227,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_183_000 picoseconds. - Weight::from_parts(16_716_000, 3643) + // Minimum execution time: 21_752_000 picoseconds. + Weight::from_parts(22_743_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,10 +240,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_119_000 picoseconds. - Weight::from_parts(16_725_000, 3643) + // Minimum execution time: 21_892_000 picoseconds. + Weight::from_parts(22_583_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -251,10 +251,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 10_889_000 picoseconds. - Weight::from_parts(11_480_000, 3643) + // Minimum execution time: 15_920_000 picoseconds. + Weight::from_parts(16_470_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -262,10 +262,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 10_903_000 picoseconds. - Weight::from_parts(11_241_000, 3643) + // Minimum execution time: 15_489_000 picoseconds. + Weight::from_parts(16_232_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -279,10 +279,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `630` // Estimated: `3643` - // Minimum execution time: 24_942_000 picoseconds. - Weight::from_parts(25_715_000, 3643) + // Minimum execution time: 31_035_000 picoseconds. + Weight::from_parts(31_987_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -290,10 +290,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 11_488_000 picoseconds. - Weight::from_parts(11_752_000, 3643) + // Minimum execution time: 15_914_000 picoseconds. + Weight::from_parts(16_494_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -303,10 +303,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_item_status() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 14_721_000 picoseconds. - Weight::from_parts(15_187_000, 3643) + // Minimum execution time: 19_490_000 picoseconds. + Weight::from_parts(20_121_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -318,10 +318,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `626` + // Measured: `659` // Estimated: `3652` - // Minimum execution time: 36_665_000 picoseconds. - Weight::from_parts(37_587_000, 3652) + // Minimum execution time: 42_331_000 picoseconds. + Weight::from_parts(44_248_000, 3652) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -333,10 +333,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `823` + // Measured: `856` // Estimated: `3652` - // Minimum execution time: 35_066_000 picoseconds. - Weight::from_parts(36_380_000, 3652) + // Minimum execution time: 42_378_000 picoseconds. + Weight::from_parts(43_407_000, 3652) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -346,10 +346,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `415` + // Measured: `448` // Estimated: `3652` - // Minimum execution time: 27_060_000 picoseconds. - Weight::from_parts(27_813_000, 3652) + // Minimum execution time: 32_461_000 picoseconds. + Weight::from_parts(33_579_000, 3652) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -359,10 +359,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `626` + // Measured: `659` // Estimated: `3652` - // Minimum execution time: 27_776_000 picoseconds. - Weight::from_parts(28_582_000, 3652) + // Minimum execution time: 34_123_000 picoseconds. + Weight::from_parts(35_283_000, 3652) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -372,10 +372,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 27_636_000 picoseconds. - Weight::from_parts(29_118_000, 3643) + // Minimum execution time: 33_300_000 picoseconds. + Weight::from_parts(34_163_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -385,10 +385,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `540` + // Measured: `573` // Estimated: `3643` - // Minimum execution time: 28_246_000 picoseconds. - Weight::from_parts(29_059_000, 3643) + // Minimum execution time: 32_810_000 picoseconds. + Weight::from_parts(33_865_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -398,10 +398,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_793_000 picoseconds. - Weight::from_parts(17_396_000, 3643) + // Minimum execution time: 22_203_000 picoseconds. + Weight::from_parts(22_831_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -411,10 +411,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `528` + // Measured: `561` // Estimated: `3643` - // Minimum execution time: 16_726_000 picoseconds. - Weight::from_parts(17_357_000, 3643) + // Minimum execution time: 22_182_000 picoseconds. + Weight::from_parts(22_739_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -422,10 +422,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `142` // Estimated: `3517` - // Minimum execution time: 12_686_000 picoseconds. - Weight::from_parts(13_182_000, 3517) + // Minimum execution time: 13_384_000 picoseconds. + Weight::from_parts(13_850_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -435,10 +435,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 13_508_000 picoseconds. - Weight::from_parts(13_906_000, 3643) + // Minimum execution time: 18_516_000 picoseconds. + Weight::from_parts(19_043_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -448,10 +448,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `326` + // Measured: `359` // Estimated: `3587` - // Minimum execution time: 13_742_000 picoseconds. - Weight::from_parts(14_200_000, 3587) + // Minimum execution time: 18_536_000 picoseconds. + Weight::from_parts(19_118_000, 3587) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -465,10 +465,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `607` + // Measured: `640` // Estimated: `3643` - // Minimum execution time: 32_931_000 picoseconds. - Weight::from_parts(34_023_000, 3643) + // Minimum execution time: 38_751_000 picoseconds. + Weight::from_parts(39_570_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -482,10 +482,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `249` + // Measured: `282` // Estimated: `3643` - // Minimum execution time: 27_074_000 picoseconds. - Weight::from_parts(28_213_000, 3643) + // Minimum execution time: 31_956_000 picoseconds. + Weight::from_parts(33_104_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -495,10 +495,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_create() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `142` // Estimated: `3643` - // Minimum execution time: 12_034_000 picoseconds. - Weight::from_parts(12_669_000, 3643) + // Minimum execution time: 12_757_000 picoseconds. + Weight::from_parts(13_327_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -523,16 +523,16 @@ impl WeightInfo for () { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `418 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` + // Measured: `451 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` - // Minimum execution time: 2_928_174_000 picoseconds. - Weight::from_parts(2_970_367_000, 3643) - // Standard Error: 30_368 - .saturating_add(Weight::from_parts(7_336_699, 0).saturating_mul(n.into())) - // Standard Error: 30_368 - .saturating_add(Weight::from_parts(401_816, 0).saturating_mul(m.into())) - // Standard Error: 30_368 - .saturating_add(Weight::from_parts(346_952, 0).saturating_mul(a.into())) + // Minimum execution time: 3_236_461_000 picoseconds. + Weight::from_parts(3_291_013_000, 3643) + // Standard Error: 39_603 + .saturating_add(Weight::from_parts(8_285_170, 0).saturating_mul(n.into())) + // Standard Error: 39_603 + .saturating_add(Weight::from_parts(469_210, 0).saturating_mul(m.into())) + // Standard Error: 39_603 + .saturating_add(Weight::from_parts(546_865, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) @@ -555,10 +555,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 33_733_000 picoseconds. - Weight::from_parts(35_366_000, 3643) + // Minimum execution time: 39_056_000 picoseconds. + Weight::from_parts(40_157_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -572,10 +572,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 35_064_000 picoseconds. - Weight::from_parts(35_747_000, 3643) + // Minimum execution time: 39_462_000 picoseconds. + Weight::from_parts(41_368_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -589,10 +589,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 24_955_000 picoseconds. - Weight::from_parts(25_661_000, 3643) + // Minimum execution time: 30_639_000 picoseconds. + Weight::from_parts(31_523_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -603,12 +603,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `805 + i * (76 ±0)` + // Measured: `838 + i * (76 ±0)` // Estimated: `3643 + i * (2597 ±0)` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_490_000, 3643) - // Standard Error: 14_697 - .saturating_add(Weight::from_parts(15_720_495, 0).saturating_mul(i.into())) + // Minimum execution time: 16_920_000 picoseconds. + Weight::from_parts(17_096_000, 3643) + // Standard Error: 24_966 + .saturating_add(Weight::from_parts(18_491_945, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -621,10 +621,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_183_000 picoseconds. - Weight::from_parts(16_716_000, 3643) + // Minimum execution time: 21_752_000 picoseconds. + Weight::from_parts(22_743_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -634,10 +634,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_119_000 picoseconds. - Weight::from_parts(16_725_000, 3643) + // Minimum execution time: 21_892_000 picoseconds. + Weight::from_parts(22_583_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -645,10 +645,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 10_889_000 picoseconds. - Weight::from_parts(11_480_000, 3643) + // Minimum execution time: 15_920_000 picoseconds. + Weight::from_parts(16_470_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -656,10 +656,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 10_903_000 picoseconds. - Weight::from_parts(11_241_000, 3643) + // Minimum execution time: 15_489_000 picoseconds. + Weight::from_parts(16_232_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -673,10 +673,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `630` // Estimated: `3643` - // Minimum execution time: 24_942_000 picoseconds. - Weight::from_parts(25_715_000, 3643) + // Minimum execution time: 31_035_000 picoseconds. + Weight::from_parts(31_987_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -684,10 +684,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 11_488_000 picoseconds. - Weight::from_parts(11_752_000, 3643) + // Minimum execution time: 15_914_000 picoseconds. + Weight::from_parts(16_494_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -697,10 +697,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn force_item_status() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 14_721_000 picoseconds. - Weight::from_parts(15_187_000, 3643) + // Minimum execution time: 19_490_000 picoseconds. + Weight::from_parts(20_121_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -712,10 +712,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `626` + // Measured: `659` // Estimated: `3652` - // Minimum execution time: 36_665_000 picoseconds. - Weight::from_parts(37_587_000, 3652) + // Minimum execution time: 42_331_000 picoseconds. + Weight::from_parts(44_248_000, 3652) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -727,10 +727,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `823` + // Measured: `856` // Estimated: `3652` - // Minimum execution time: 35_066_000 picoseconds. - Weight::from_parts(36_380_000, 3652) + // Minimum execution time: 42_378_000 picoseconds. + Weight::from_parts(43_407_000, 3652) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -740,10 +740,10 @@ impl WeightInfo for () { /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `415` + // Measured: `448` // Estimated: `3652` - // Minimum execution time: 27_060_000 picoseconds. - Weight::from_parts(27_813_000, 3652) + // Minimum execution time: 32_461_000 picoseconds. + Weight::from_parts(33_579_000, 3652) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -753,10 +753,10 @@ impl WeightInfo for () { /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `626` + // Measured: `659` // Estimated: `3652` - // Minimum execution time: 27_776_000 picoseconds. - Weight::from_parts(28_582_000, 3652) + // Minimum execution time: 34_123_000 picoseconds. + Weight::from_parts(35_283_000, 3652) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -766,10 +766,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 27_636_000 picoseconds. - Weight::from_parts(29_118_000, 3643) + // Minimum execution time: 33_300_000 picoseconds. + Weight::from_parts(34_163_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -779,10 +779,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `540` + // Measured: `573` // Estimated: `3643` - // Minimum execution time: 28_246_000 picoseconds. - Weight::from_parts(29_059_000, 3643) + // Minimum execution time: 32_810_000 picoseconds. + Weight::from_parts(33_865_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -792,10 +792,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `495` + // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_793_000 picoseconds. - Weight::from_parts(17_396_000, 3643) + // Minimum execution time: 22_203_000 picoseconds. + Weight::from_parts(22_831_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -805,10 +805,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `528` + // Measured: `561` // Estimated: `3643` - // Minimum execution time: 16_726_000 picoseconds. - Weight::from_parts(17_357_000, 3643) + // Minimum execution time: 22_182_000 picoseconds. + Weight::from_parts(22_739_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -816,10 +816,10 @@ impl WeightInfo for () { /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `142` // Estimated: `3517` - // Minimum execution time: 12_686_000 picoseconds. - Weight::from_parts(13_182_000, 3517) + // Minimum execution time: 13_384_000 picoseconds. + Weight::from_parts(13_850_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -829,10 +829,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: - // Measured: `349` + // Measured: `382` // Estimated: `3643` - // Minimum execution time: 13_508_000 picoseconds. - Weight::from_parts(13_906_000, 3643) + // Minimum execution time: 18_516_000 picoseconds. + Weight::from_parts(19_043_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -842,10 +842,10 @@ impl WeightInfo for () { /// Proof: `Uniques::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `326` + // Measured: `359` // Estimated: `3587` - // Minimum execution time: 13_742_000 picoseconds. - Weight::from_parts(14_200_000, 3587) + // Minimum execution time: 18_536_000 picoseconds. + Weight::from_parts(19_118_000, 3587) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -859,10 +859,10 @@ impl WeightInfo for () { /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `607` + // Measured: `640` // Estimated: `3643` - // Minimum execution time: 32_931_000 picoseconds. - Weight::from_parts(34_023_000, 3643) + // Minimum execution time: 38_751_000 picoseconds. + Weight::from_parts(39_570_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index e2d35fc1699f..c9a4432648ea 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -17,18 +17,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } -pallet-root-testing = { workspace = true, default-features = true } pallet-collective = { workspace = true, default-features = true } +pallet-root-testing = { workspace = true, default-features = true } pallet-timestamp = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } diff --git a/substrate/frame/utility/src/weights.rs b/substrate/frame/utility/src/weights.rs index 502f85a3f178..8b31eb2ced85 100644 --- a/substrate/frame/utility/src/weights.rs +++ b/substrate/frame/utility/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -70,10 +70,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 5_312_000 picoseconds. - Weight::from_parts(2_694_370, 3997) - // Standard Error: 5_055 - .saturating_add(Weight::from_parts(5_005_941, 0).saturating_mul(c.into())) + // Minimum execution time: 4_830_000 picoseconds. + Weight::from_parts(19_388_813, 3997) + // Standard Error: 2_694 + .saturating_add(Weight::from_parts(4_591_113, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) @@ -84,8 +84,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 9_263_000 picoseconds. - Weight::from_parts(9_639_000, 3997) + // Minimum execution time: 10_474_000 picoseconds. + Weight::from_parts(10_896_000, 3997) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) @@ -97,18 +97,18 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 5_120_000 picoseconds. - Weight::from_parts(12_948_874, 3997) - // Standard Error: 4_643 - .saturating_add(Weight::from_parts(5_162_821, 0).saturating_mul(c.into())) + // Minimum execution time: 4_773_000 picoseconds. + Weight::from_parts(22_628_420, 3997) + // Standard Error: 2_405 + .saturating_add(Weight::from_parts(4_797_007, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_126_000 picoseconds. - Weight::from_parts(7_452_000, 0) + // Minimum execution time: 6_668_000 picoseconds. + Weight::from_parts(6_985_000, 0) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -119,10 +119,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 5_254_000 picoseconds. - Weight::from_parts(4_879_712, 3997) - // Standard Error: 4_988 - .saturating_add(Weight::from_parts(4_955_816, 0).saturating_mul(c.into())) + // Minimum execution time: 5_434_000 picoseconds. + Weight::from_parts(23_270_604, 3997) + // Standard Error: 2_511 + .saturating_add(Weight::from_parts(4_570_923, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } } @@ -138,10 +138,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 5_312_000 picoseconds. - Weight::from_parts(2_694_370, 3997) - // Standard Error: 5_055 - .saturating_add(Weight::from_parts(5_005_941, 0).saturating_mul(c.into())) + // Minimum execution time: 4_830_000 picoseconds. + Weight::from_parts(19_388_813, 3997) + // Standard Error: 2_694 + .saturating_add(Weight::from_parts(4_591_113, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) @@ -152,8 +152,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 9_263_000 picoseconds. - Weight::from_parts(9_639_000, 3997) + // Minimum execution time: 10_474_000 picoseconds. + Weight::from_parts(10_896_000, 3997) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) @@ -165,18 +165,18 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 5_120_000 picoseconds. - Weight::from_parts(12_948_874, 3997) - // Standard Error: 4_643 - .saturating_add(Weight::from_parts(5_162_821, 0).saturating_mul(c.into())) + // Minimum execution time: 4_773_000 picoseconds. + Weight::from_parts(22_628_420, 3997) + // Standard Error: 2_405 + .saturating_add(Weight::from_parts(4_797_007, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_126_000 picoseconds. - Weight::from_parts(7_452_000, 0) + // Minimum execution time: 6_668_000 picoseconds. + Weight::from_parts(6_985_000, 0) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -187,10 +187,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 5_254_000 picoseconds. - Weight::from_parts(4_879_712, 3997) - // Standard Error: 4_988 - .saturating_add(Weight::from_parts(4_955_816, 0).saturating_mul(c.into())) + // Minimum execution time: 5_434_000 picoseconds. + Weight::from_parts(23_270_604, 3997) + // Standard Error: 2_511 + .saturating_add(Weight::from_parts(4_570_923, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } } diff --git a/substrate/frame/verify-signature/Cargo.toml b/substrate/frame/verify-signature/Cargo.toml index 3c5fd5e65157..37cc6c0b3065 100644 --- a/substrate/frame/verify-signature/Cargo.toml +++ b/substrate/frame/verify-signature/Cargo.toml @@ -17,10 +17,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } @@ -28,8 +28,8 @@ sp-weights = { features = ["serde"], workspace = true } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } -pallet-root-testing = { workspace = true, default-features = true } pallet-collective = { workspace = true, default-features = true } +pallet-root-testing = { workspace = true, default-features = true } pallet-timestamp = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } diff --git a/substrate/frame/verify-signature/src/benchmarking.rs b/substrate/frame/verify-signature/src/benchmarking.rs index 2b592a4023ec..99e893e6f6ab 100644 --- a/substrate/frame/verify-signature/src/benchmarking.rs +++ b/substrate/frame/verify-signature/src/benchmarking.rs @@ -27,10 +27,16 @@ use super::*; use crate::{extension::VerifySignature, Config, Pallet as VerifySignaturePallet}; use alloc::vec; use frame_benchmarking::{v2::*, BenchmarkError}; -use frame_support::dispatch::{DispatchInfo, GetDispatchInfo}; +use frame_support::{ + dispatch::{DispatchInfo, GetDispatchInfo}, + pallet_prelude::TransactionSource, +}; use frame_system::{Call as SystemCall, RawOrigin}; use sp_io::hashing::blake2_256; -use sp_runtime::traits::{AsTransactionAuthorizedOrigin, Dispatchable, TransactionExtension}; +use sp_runtime::{ + generic::ExtensionVersion, + traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable}, +}; pub trait BenchmarkHelper { fn create_signature(entropy: &[u8], msg: &[u8]) -> (Signature, Signer); @@ -48,14 +54,24 @@ mod benchmarks { fn verify_signature() -> Result<(), BenchmarkError> { let entropy = [42u8; 256]; let call: T::RuntimeCall = SystemCall::remark { remark: vec![] }.into(); + let ext_version: ExtensionVersion = 0; let info = call.get_dispatch_info(); - let msg = call.using_encoded(blake2_256).to_vec(); + let msg = (ext_version, &call).using_encoded(blake2_256).to_vec(); let (signature, signer) = T::BenchmarkHelper::create_signature(&entropy, &msg[..]); let ext = VerifySignature::::new_with_signature(signature, signer); #[block] { - assert!(ext.validate(RawOrigin::None.into(), &call, &info, 0, (), &call).is_ok()); + assert!(ext + .validate_only( + RawOrigin::None.into(), + &call, + &info, + 0, + TransactionSource::External, + ext_version + ) + .is_ok()); } Ok(()) diff --git a/substrate/frame/verify-signature/src/extension.rs b/substrate/frame/verify-signature/src/extension.rs index 4490a0a600bb..d48991e7a1da 100644 --- a/substrate/frame/verify-signature/src/extension.rs +++ b/substrate/frame/verify-signature/src/extension.rs @@ -20,7 +20,7 @@ use crate::{Config, WeightInfo}; use codec::{Decode, Encode}; -use frame_support::traits::OriginTrait; +use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait}; use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::{ @@ -113,6 +113,7 @@ where _len: usize, _: (), inherited_implication: &impl Encode, + _source: TransactionSource, ) -> Result< (ValidTransaction, Self::Val, ::RuntimeOrigin), TransactionValidityError, diff --git a/substrate/frame/verify-signature/src/tests.rs b/substrate/frame/verify-signature/src/tests.rs index 3e4c8db12fe2..63a310506eec 100644 --- a/substrate/frame/verify-signature/src/tests.rs +++ b/substrate/frame/verify-signature/src/tests.rs @@ -25,12 +25,13 @@ use extension::VerifySignature; use frame_support::{ derive_impl, dispatch::GetDispatchInfo, - pallet_prelude::{InvalidTransaction, TransactionValidityError}, + pallet_prelude::{InvalidTransaction, TransactionSource, TransactionValidityError}, traits::OriginTrait, }; use frame_system::Call as SystemCall; use sp_io::hashing::blake2_256; use sp_runtime::{ + generic::ExtensionVersion, testing::{TestSignature, UintAuthorityId}, traits::DispatchTransaction, }; @@ -80,15 +81,32 @@ pub fn new_test_ext() -> sp_io::TestExternalities { fn verification_works() { let who = 0; let call: RuntimeCall = SystemCall::remark { remark: vec![] }.into(); - let sig = TestSignature(0, call.using_encoded(blake2_256).to_vec()); + let ext_version: ExtensionVersion = 0; + let sig = TestSignature(0, (ext_version, &call).using_encoded(blake2_256).to_vec()); let info = call.get_dispatch_info(); let (_, _, origin) = VerifySignature::::new_with_signature(sig, who) - .validate_only(None.into(), &call, &info, 0) + .validate_only(None.into(), &call, &info, 0, TransactionSource::External, 0) .unwrap(); assert_eq!(origin.as_signer().unwrap(), &who) } +#[test] +fn bad_inherited_implication() { + let who = 0; + let call: RuntimeCall = SystemCall::remark { remark: vec![] }.into(); + // Inherited implication should include extension version byte. + let sig = TestSignature(0, call.using_encoded(blake2_256).to_vec()); + let info = call.get_dispatch_info(); + + assert_eq!( + VerifySignature::::new_with_signature(sig, who) + .validate_only(None.into(), &call, &info, 0, TransactionSource::External, 0) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::BadProof) + ); +} + #[test] fn bad_signature() { let who = 0; @@ -98,7 +116,7 @@ fn bad_signature() { assert_eq!( VerifySignature::::new_with_signature(sig, who) - .validate_only(None.into(), &call, &info, 0) + .validate_only(None.into(), &call, &info, 0, TransactionSource::External, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::BadProof) ); @@ -113,7 +131,7 @@ fn bad_starting_origin() { assert_eq!( VerifySignature::::new_with_signature(sig, who) - .validate_only(Some(42).into(), &call, &info, 0) + .validate_only(Some(42).into(), &call, &info, 0, TransactionSource::External, 0) .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::BadSigner) ); @@ -126,7 +144,7 @@ fn disabled_extension_works() { let info = call.get_dispatch_info(); let (_, _, origin) = VerifySignature::::new_disabled() - .validate_only(Some(who).into(), &call, &info, 0) + .validate_only(Some(who).into(), &call, &info, 0, TransactionSource::External, 0) .unwrap(); assert_eq!(origin.as_signer().unwrap(), &who) } diff --git a/substrate/frame/verify-signature/src/weights.rs b/substrate/frame/verify-signature/src/weights.rs index 2c1f0f795422..a8bfa9ea902d 100644 --- a/substrate/frame/verify-signature/src/weights.rs +++ b/substrate/frame/verify-signature/src/weights.rs @@ -18,22 +18,25 @@ //! Autogenerated weights for `pallet_verify_signature` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-09-24, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/debug/substrate-node +// ./target/production/substrate-node // benchmark // pallet -// --steps=2 -// --repeat=2 +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_verify_signature +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --pallet=pallet-verify-signature -// --chain=dev // --output=./substrate/frame/verify-signature/src/weights.rs // --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs @@ -58,8 +61,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 48_953_000 picoseconds. - Weight::from_parts(49_254_000, 0) + // Minimum execution time: 46_215_000 picoseconds. + Weight::from_parts(46_714_000, 0) } } @@ -69,7 +72,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 48_953_000 picoseconds. - Weight::from_parts(49_254_000, 0) + // Minimum execution time: 46_215_000 picoseconds. + Weight::from_parts(46_714_000, 0) } } diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index f896c3962eaa..882ce5f81373 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -19,11 +19,11 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = [ "derive", ], workspace = true } -log = { workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/vesting/src/weights.rs b/substrate/frame/vesting/src/weights.rs index efb8cbcc41c4..3ab161e822e8 100644 --- a/substrate/frame/vesting/src/weights.rs +++ b/substrate/frame/vesting/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_vesting` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -75,14 +75,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 32_202_000 picoseconds. - Weight::from_parts(31_586_520, 4764) - // Standard Error: 1_513 - .saturating_add(Weight::from_parts(67_257, 0).saturating_mul(l.into())) - // Standard Error: 2_693 - .saturating_add(Weight::from_parts(69_725, 0).saturating_mul(s.into())) + // Minimum execution time: 39_505_000 picoseconds. + Weight::from_parts(39_835_306, 4764) + // Standard Error: 1_394 + .saturating_add(Weight::from_parts(21_450, 0).saturating_mul(l.into())) + // Standard Error: 2_481 + .saturating_add(Weight::from_parts(70_901, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -96,14 +96,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_847_000 picoseconds. - Weight::from_parts(34_690_456, 4764) - // Standard Error: 1_681 - .saturating_add(Weight::from_parts(51_103, 0).saturating_mul(l.into())) - // Standard Error: 2_991 - .saturating_add(Weight::from_parts(55_094, 0).saturating_mul(s.into())) + // Minimum execution time: 40_781_000 picoseconds. + Weight::from_parts(40_777_528, 4764) + // Standard Error: 1_209 + .saturating_add(Weight::from_parts(35_116, 0).saturating_mul(l.into())) + // Standard Error: 2_151 + .saturating_add(Weight::from_parts(83_093, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -119,14 +119,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Measured: `517 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_027_000 picoseconds. - Weight::from_parts(33_353_168, 4764) - // Standard Error: 1_477 - .saturating_add(Weight::from_parts(72_605, 0).saturating_mul(l.into())) - // Standard Error: 2_629 - .saturating_add(Weight::from_parts(64_115, 0).saturating_mul(s.into())) + // Minimum execution time: 41_590_000 picoseconds. + Weight::from_parts(40_756_231, 4764) + // Standard Error: 1_420 + .saturating_add(Weight::from_parts(45_223, 0).saturating_mul(l.into())) + // Standard Error: 2_527 + .saturating_add(Weight::from_parts(102_603, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -142,14 +142,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Measured: `517 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_816_000 picoseconds. - Weight::from_parts(36_467_447, 4764) - // Standard Error: 1_689 - .saturating_add(Weight::from_parts(51_855, 0).saturating_mul(l.into())) - // Standard Error: 3_006 - .saturating_add(Weight::from_parts(58_233, 0).saturating_mul(s.into())) + // Minimum execution time: 43_490_000 picoseconds. + Weight::from_parts(43_900_384, 4764) + // Standard Error: 1_670 + .saturating_add(Weight::from_parts(31_084, 0).saturating_mul(l.into())) + // Standard Error: 2_971 + .saturating_add(Weight::from_parts(66_673, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -165,14 +165,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Measured: `588 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 70_906_000 picoseconds. - Weight::from_parts(72_663_428, 4764) - // Standard Error: 2_877 - .saturating_add(Weight::from_parts(81_242, 0).saturating_mul(l.into())) - // Standard Error: 5_118 - .saturating_add(Weight::from_parts(103_344, 0).saturating_mul(s.into())) + // Minimum execution time: 76_194_000 picoseconds. + Weight::from_parts(77_923_603, 4764) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(50_161, 0).saturating_mul(l.into())) + // Standard Error: 3_810 + .saturating_add(Weight::from_parts(97_415, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -188,14 +188,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `658 + l * (25 ±0) + s * (36 ±0)` + // Measured: `691 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 72_730_000 picoseconds. - Weight::from_parts(75_050_411, 6196) - // Standard Error: 2_748 - .saturating_add(Weight::from_parts(73_218, 0).saturating_mul(l.into())) - // Standard Error: 4_889 - .saturating_add(Weight::from_parts(112_868, 0).saturating_mul(s.into())) + // Minimum execution time: 78_333_000 picoseconds. + Weight::from_parts(80_199_350, 6196) + // Standard Error: 1_903 + .saturating_add(Weight::from_parts(46_798, 0).saturating_mul(l.into())) + // Standard Error: 3_385 + .saturating_add(Weight::from_parts(106_311, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -205,22 +205,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_698_000 picoseconds. - Weight::from_parts(34_504_324, 4764) - // Standard Error: 1_703 - .saturating_add(Weight::from_parts(56_321, 0).saturating_mul(l.into())) - // Standard Error: 3_145 - .saturating_add(Weight::from_parts(55_503, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 40_102_000 picoseconds. + Weight::from_parts(39_552_301, 4764) + // Standard Error: 1_309 + .saturating_add(Weight::from_parts(37_184, 0).saturating_mul(l.into())) + // Standard Error: 2_418 + .saturating_add(Weight::from_parts(91_621, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Vesting::Vesting` (r:1 w:1) /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) @@ -228,22 +226,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_951_000 picoseconds. - Weight::from_parts(37_020_649, 4764) - // Standard Error: 1_791 - .saturating_add(Weight::from_parts(65_437, 0).saturating_mul(l.into())) - // Standard Error: 3_308 - .saturating_add(Weight::from_parts(54_146, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 42_287_000 picoseconds. + Weight::from_parts(41_937_484, 4764) + // Standard Error: 1_306 + .saturating_add(Weight::from_parts(39_880, 0).saturating_mul(l.into())) + // Standard Error: 2_412 + .saturating_add(Weight::from_parts(85_247, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Vesting::Vesting` (r:1 w:1) /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) @@ -257,14 +253,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[2, 28]`. fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Measured: `588 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_849_000 picoseconds. - Weight::from_parts(38_488_577, 4764) - // Standard Error: 1_911 - .saturating_add(Weight::from_parts(72_338, 0).saturating_mul(l.into())) - // Standard Error: 3_529 - .saturating_add(Weight::from_parts(62_206, 0).saturating_mul(s.into())) + // Minimum execution time: 46_462_000 picoseconds. + Weight::from_parts(46_571_504, 4764) + // Standard Error: 1_298 + .saturating_add(Weight::from_parts(42_091, 0).saturating_mul(l.into())) + // Standard Error: 2_397 + .saturating_add(Weight::from_parts(77_382, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -282,14 +278,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 32_202_000 picoseconds. - Weight::from_parts(31_586_520, 4764) - // Standard Error: 1_513 - .saturating_add(Weight::from_parts(67_257, 0).saturating_mul(l.into())) - // Standard Error: 2_693 - .saturating_add(Weight::from_parts(69_725, 0).saturating_mul(s.into())) + // Minimum execution time: 39_505_000 picoseconds. + Weight::from_parts(39_835_306, 4764) + // Standard Error: 1_394 + .saturating_add(Weight::from_parts(21_450, 0).saturating_mul(l.into())) + // Standard Error: 2_481 + .saturating_add(Weight::from_parts(70_901, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -303,14 +299,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `381 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_847_000 picoseconds. - Weight::from_parts(34_690_456, 4764) - // Standard Error: 1_681 - .saturating_add(Weight::from_parts(51_103, 0).saturating_mul(l.into())) - // Standard Error: 2_991 - .saturating_add(Weight::from_parts(55_094, 0).saturating_mul(s.into())) + // Minimum execution time: 40_781_000 picoseconds. + Weight::from_parts(40_777_528, 4764) + // Standard Error: 1_209 + .saturating_add(Weight::from_parts(35_116, 0).saturating_mul(l.into())) + // Standard Error: 2_151 + .saturating_add(Weight::from_parts(83_093, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -326,14 +322,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Measured: `517 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_027_000 picoseconds. - Weight::from_parts(33_353_168, 4764) - // Standard Error: 1_477 - .saturating_add(Weight::from_parts(72_605, 0).saturating_mul(l.into())) - // Standard Error: 2_629 - .saturating_add(Weight::from_parts(64_115, 0).saturating_mul(s.into())) + // Minimum execution time: 41_590_000 picoseconds. + Weight::from_parts(40_756_231, 4764) + // Standard Error: 1_420 + .saturating_add(Weight::from_parts(45_223, 0).saturating_mul(l.into())) + // Standard Error: 2_527 + .saturating_add(Weight::from_parts(102_603, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -349,14 +345,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `484 + l * (25 ±0) + s * (36 ±0)` + // Measured: `517 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_816_000 picoseconds. - Weight::from_parts(36_467_447, 4764) - // Standard Error: 1_689 - .saturating_add(Weight::from_parts(51_855, 0).saturating_mul(l.into())) - // Standard Error: 3_006 - .saturating_add(Weight::from_parts(58_233, 0).saturating_mul(s.into())) + // Minimum execution time: 43_490_000 picoseconds. + Weight::from_parts(43_900_384, 4764) + // Standard Error: 1_670 + .saturating_add(Weight::from_parts(31_084, 0).saturating_mul(l.into())) + // Standard Error: 2_971 + .saturating_add(Weight::from_parts(66_673, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -372,14 +368,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Measured: `588 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 70_906_000 picoseconds. - Weight::from_parts(72_663_428, 4764) - // Standard Error: 2_877 - .saturating_add(Weight::from_parts(81_242, 0).saturating_mul(l.into())) - // Standard Error: 5_118 - .saturating_add(Weight::from_parts(103_344, 0).saturating_mul(s.into())) + // Minimum execution time: 76_194_000 picoseconds. + Weight::from_parts(77_923_603, 4764) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(50_161, 0).saturating_mul(l.into())) + // Standard Error: 3_810 + .saturating_add(Weight::from_parts(97_415, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -395,14 +391,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `658 + l * (25 ±0) + s * (36 ±0)` + // Measured: `691 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 72_730_000 picoseconds. - Weight::from_parts(75_050_411, 6196) - // Standard Error: 2_748 - .saturating_add(Weight::from_parts(73_218, 0).saturating_mul(l.into())) - // Standard Error: 4_889 - .saturating_add(Weight::from_parts(112_868, 0).saturating_mul(s.into())) + // Minimum execution time: 78_333_000 picoseconds. + Weight::from_parts(80_199_350, 6196) + // Standard Error: 1_903 + .saturating_add(Weight::from_parts(46_798, 0).saturating_mul(l.into())) + // Standard Error: 3_385 + .saturating_add(Weight::from_parts(106_311, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -412,22 +408,20 @@ impl WeightInfo for () { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_698_000 picoseconds. - Weight::from_parts(34_504_324, 4764) - // Standard Error: 1_703 - .saturating_add(Weight::from_parts(56_321, 0).saturating_mul(l.into())) - // Standard Error: 3_145 - .saturating_add(Weight::from_parts(55_503, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 40_102_000 picoseconds. + Weight::from_parts(39_552_301, 4764) + // Standard Error: 1_309 + .saturating_add(Weight::from_parts(37_184, 0).saturating_mul(l.into())) + // Standard Error: 2_418 + .saturating_add(Weight::from_parts(91_621, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Vesting::Vesting` (r:1 w:1) /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) @@ -435,22 +429,20 @@ impl WeightInfo for () { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + l * (25 ±0) + s * (36 ±0)` + // Measured: `414 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_951_000 picoseconds. - Weight::from_parts(37_020_649, 4764) - // Standard Error: 1_791 - .saturating_add(Weight::from_parts(65_437, 0).saturating_mul(l.into())) - // Standard Error: 3_308 - .saturating_add(Weight::from_parts(54_146, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 42_287_000 picoseconds. + Weight::from_parts(41_937_484, 4764) + // Standard Error: 1_306 + .saturating_add(Weight::from_parts(39_880, 0).saturating_mul(l.into())) + // Standard Error: 2_412 + .saturating_add(Weight::from_parts(85_247, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Vesting::Vesting` (r:1 w:1) /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) @@ -464,14 +456,14 @@ impl WeightInfo for () { /// The range of component `s` is `[2, 28]`. fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `555 + l * (25 ±0) + s * (36 ±0)` + // Measured: `588 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_849_000 picoseconds. - Weight::from_parts(38_488_577, 4764) - // Standard Error: 1_911 - .saturating_add(Weight::from_parts(72_338, 0).saturating_mul(l.into())) - // Standard Error: 3_529 - .saturating_add(Weight::from_parts(62_206, 0).saturating_mul(s.into())) + // Minimum execution time: 46_462_000 picoseconds. + Weight::from_parts(46_571_504, 4764) + // Standard Error: 1_298 + .saturating_add(Weight::from_parts(42_091, 0).saturating_mul(l.into())) + // Standard Error: 2_397 + .saturating_add(Weight::from_parts(77_382, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index a347174ed2eb..68ecc5d0d78e 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive", "max-encoded-len"], workspace = true } -scale-info = { features = ["derive"], workspace = true } frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/frame/whitelist/src/weights.rs b/substrate/frame/whitelist/src/weights.rs index 2e28d4fcf7e5..12a18a8f0107 100644 --- a/substrate/frame/whitelist/src/weights.rs +++ b/substrate/frame/whitelist/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_whitelist` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-11-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wiukf8gn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -68,10 +68,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn whitelist_call() -> Weight { // Proof Size summary in bytes: - // Measured: `317` + // Measured: `245` // Estimated: `3556` - // Minimum execution time: 19_521_000 picoseconds. - Weight::from_parts(20_136_000, 3556) + // Minimum execution time: 18_287_000 picoseconds. + Weight::from_parts(18_733_000, 3556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -83,10 +83,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `374` // Estimated: `3556` - // Minimum execution time: 18_530_000 picoseconds. - Weight::from_parts(19_004_000, 3556) + // Minimum execution time: 22_887_000 picoseconds. + Weight::from_parts(23_352_000, 3556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -101,12 +101,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522 + n * (1 ±0)` - // Estimated: `3986 + n * (1 ±0)` - // Minimum execution time: 29_721_000 picoseconds. - Weight::from_parts(30_140_000, 3986) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_179, 0).saturating_mul(n.into())) + // Measured: `450 + n * (1 ±0)` + // Estimated: `3914 + n * (1 ±0)` + // Minimum execution time: 33_692_000 picoseconds. + Weight::from_parts(34_105_000, 3914) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_800, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -120,12 +120,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `374` // Estimated: `3556` - // Minimum execution time: 22_608_000 picoseconds. - Weight::from_parts(23_682_511, 3556) + // Minimum execution time: 26_380_000 picoseconds. + Weight::from_parts(27_186_471, 3556) // Standard Error: 6 - .saturating_add(Weight::from_parts(1_420, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -141,10 +141,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn whitelist_call() -> Weight { // Proof Size summary in bytes: - // Measured: `317` + // Measured: `245` // Estimated: `3556` - // Minimum execution time: 19_521_000 picoseconds. - Weight::from_parts(20_136_000, 3556) + // Minimum execution time: 18_287_000 picoseconds. + Weight::from_parts(18_733_000, 3556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -156,10 +156,10 @@ impl WeightInfo for () { /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `374` // Estimated: `3556` - // Minimum execution time: 18_530_000 picoseconds. - Weight::from_parts(19_004_000, 3556) + // Minimum execution time: 22_887_000 picoseconds. + Weight::from_parts(23_352_000, 3556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -174,12 +174,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522 + n * (1 ±0)` - // Estimated: `3986 + n * (1 ±0)` - // Minimum execution time: 29_721_000 picoseconds. - Weight::from_parts(30_140_000, 3986) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_179, 0).saturating_mul(n.into())) + // Measured: `450 + n * (1 ±0)` + // Estimated: `3914 + n * (1 ±0)` + // Minimum execution time: 33_692_000 picoseconds. + Weight::from_parts(34_105_000, 3914) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_800, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -193,12 +193,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `374` // Estimated: `3556` - // Minimum execution time: 22_608_000 picoseconds. - Weight::from_parts(23_682_511, 3556) + // Minimum execution time: 26_380_000 picoseconds. + Weight::from_parts(27_186_471, 3556) // Standard Error: 6 - .saturating_add(Weight::from_parts(1_420, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index e0a4d06b2d81..7295adbc11ca 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -17,22 +17,22 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } +docify = { workspace = true } +hash-db = { optional = true, workspace = true, default-features = true } +log = { workspace = true } +scale-info = { features = [ + "derive", +], workspace = true } sp-api-proc-macro = { workspace = true } sp-core = { workspace = true } +sp-externalities = { optional = true, workspace = true } +sp-metadata-ir = { optional = true, workspace = true } sp-runtime = { workspace = true } sp-runtime-interface = { workspace = true } -sp-externalities = { optional = true, workspace = true } -sp-version = { workspace = true } sp-state-machine = { optional = true, workspace = true } sp-trie = { optional = true, workspace = true } -hash-db = { optional = true, workspace = true, default-features = true } +sp-version = { workspace = true } thiserror = { optional = true, workspace = true } -scale-info = { features = [ - "derive", -], workspace = true } -sp-metadata-ir = { optional = true, workspace = true } -log = { workspace = true } -docify = { workspace = true } [dev-dependencies] sp-test-primitives = { workspace = true } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 659307e7b0f8..2f414597fb74 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -quote = { workspace = true } -syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } -proc-macro2 = { workspace = true } +Inflector = { workspace = true } blake2 = { workspace = true } -proc-macro-crate = { workspace = true } expander = { workspace = true } -Inflector = { workspace = true } +proc-macro-crate = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { features = ["extra-traits", "fold", "full", "visit", "visit-mut"], workspace = true } [dev-dependencies] assert_matches = { workspace = true } diff --git a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs index cb213f2fd627..ddca1095a192 100644 --- a/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -32,6 +32,7 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; +use std::collections::{BTreeMap, HashMap}; use syn::{ fold::{self, Fold}, parse::{Error, Parse, ParseStream, Result}, @@ -43,8 +44,6 @@ use syn::{ TraitItem, TraitItemFn, }; -use std::collections::{BTreeMap, HashMap}; - /// The structure used for parsing the runtime api declarations. struct RuntimeApiDecls { decls: Vec, @@ -133,7 +132,7 @@ fn remove_supported_attributes(attrs: &mut Vec) -> HashMap<&'static s /// ``` fn generate_versioned_api_traits( api: ItemTrait, - methods: BTreeMap>, + methods: BTreeMap>, ) -> Vec { let mut result = Vec::::new(); for (version, _) in &methods { @@ -189,15 +188,12 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { extend_generics_with_block(&mut decl.generics); let mod_name = generate_runtime_mod_name_for_trait(&decl.ident); let found_attributes = remove_supported_attributes(&mut decl.attrs); - let api_version = - get_api_version(&found_attributes).map(|v| generate_runtime_api_version(v as u32))?; + let api_version = get_api_version(&found_attributes).map(generate_runtime_api_version)?; let id = generate_runtime_api_id(&decl.ident.to_string()); - let metadata = crate::runtime_metadata::generate_decl_runtime_metadata(&decl); - let trait_api_version = get_api_version(&found_attributes)?; - let mut methods_by_version: BTreeMap> = BTreeMap::new(); + let mut methods_by_version: BTreeMap> = BTreeMap::new(); // Process the items in the declaration. The filter_map function below does a lot of stuff // because the method attributes are stripped at this point @@ -255,6 +251,12 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result { _ => (), }); + let versioned_methods_iter = methods_by_version + .iter() + .flat_map(|(&version, methods)| methods.iter().map(move |method| (method, version))); + let metadata = + crate::runtime_metadata::generate_decl_runtime_metadata(&decl, versioned_methods_iter); + let versioned_api_traits = generate_versioned_api_traits(decl.clone(), methods_by_version); let main_api_ident = decl.ident.clone(); @@ -505,7 +507,7 @@ fn generate_runtime_api_version(version: u32) -> TokenStream { } /// Generates the implementation of `RuntimeApiInfo` for the given trait. -fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream { +fn generate_runtime_info_impl(trait_: &ItemTrait, version: u32) -> TokenStream { let trait_name = &trait_.ident; let crate_ = generate_crate_access(); let id = generate_runtime_api_id(&trait_name.to_string()); @@ -537,7 +539,7 @@ fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream { } /// Get changed in version from the user given attribute or `Ok(None)`, if no attribute was given. -fn get_changed_in(found_attributes: &HashMap<&'static str, Attribute>) -> Result> { +fn get_changed_in(found_attributes: &HashMap<&'static str, Attribute>) -> Result> { found_attributes .get(&CHANGED_IN_ATTRIBUTE) .map(|v| parse_runtime_api_version(v).map(Some)) @@ -545,7 +547,7 @@ fn get_changed_in(found_attributes: &HashMap<&'static str, Attribute>) -> Result } /// Get the api version from the user given attribute or `Ok(1)`, if no attribute was given. -fn get_api_version(found_attributes: &HashMap<&'static str, Attribute>) -> Result { +fn get_api_version(found_attributes: &HashMap<&'static str, Attribute>) -> Result { found_attributes .get(&API_VERSION_ATTRIBUTE) .map(parse_runtime_api_version) @@ -610,7 +612,7 @@ impl CheckTraitDecl { /// /// Any error is stored in `self.errors`. fn check_method_declarations<'a>(&mut self, methods: impl Iterator) { - let mut method_to_signature_changed = HashMap::>>::new(); + let mut method_to_signature_changed = HashMap::>>::new(); methods.into_iter().for_each(|method| { let attributes = remove_supported_attributes(&mut method.attrs.clone()); 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 de922e3253e4..5c9448da2bc7 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -15,14 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ - common::API_VERSION_ATTRIBUTE, - utils::{ - 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, - }, +use crate::utils::{ + extract_api_version, extract_block_type_from_trait_path, extract_impl_trait, + extract_parameter_names_types_and_borrows, generate_crate_access, + generate_runtime_mod_name_for_trait, prefix_function_with_trait, versioned_trait_name, + AllowSelfRefInParameters, ApiVersion, RequireQualifiedTraitPath, }; use proc_macro2::{Span, TokenStream}; @@ -31,11 +28,11 @@ use quote::quote; use syn::{ fold::{self, Fold}, - parenthesized, parse::{Error, Parse, ParseStream, Result}, parse_macro_input, parse_quote, spanned::Spanned, - Attribute, Ident, ImplItem, ItemImpl, LitInt, LitStr, Path, Signature, Type, TypePath, + visit_mut::{self, VisitMut}, + Attribute, Ident, ImplItem, ItemImpl, Path, Signature, Type, TypePath, }; use std::collections::HashMap; @@ -227,34 +224,34 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { let c = generate_crate_access(); let impl_calls = - generate_impl_calls(impls, &input)? - .into_iter() - .map(|(trait_, fn_name, impl_, attrs)| { - let fn_name = - Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site()); - - quote!( - #c::std_disabled! { - #( #attrs )* - #[no_mangle] - #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))] - pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 { - let mut #input = if input_len == 0 { - &[0u8; 0] - } else { - unsafe { - ::core::slice::from_raw_parts(input_data, input_len) - } - }; - - #c::init_runtime_logger(); - - let output = (move || { #impl_ })(); - #c::to_substrate_wasm_fn_return_value(&output) - } - } - ) - }); + generate_impl_calls(impls, &input)? + .into_iter() + .map(|(trait_, fn_name, impl_, attrs)| { + let fn_name = + Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site()); + + quote!( + #c::std_disabled! { + #( #attrs )* + #[no_mangle] + #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))] + pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 { + let mut #input = if input_len == 0 { + &[0u8; 0] + } else { + unsafe { + ::core::slice::from_raw_parts(input_data, input_len) + } + }; + + #c::init_runtime_logger(); + + let output = (move || { #impl_ })(); + #c::to_substrate_wasm_fn_return_value(&output) + } + } + ) + }); Ok(quote!( #( #impl_calls )* )) } @@ -396,10 +393,10 @@ fn generate_runtime_api_base_structures() -> Result { impl> RuntimeApiImpl { fn commit_or_rollback_transaction(&self, commit: bool) { let proof = "\ - We only close a transaction when we opened one ourself. - Other parts of the runtime that make use of transactions (state-machine) - also balance their transactions. The runtime cannot close client initiated - transactions; qed"; + We only close a transaction when we opened one ourself. + Other parts of the runtime that make use of transactions (state-machine) + also balance their transactions. The runtime cannot close client initiated + transactions; qed"; let res = if commit { let res = if let Some(recorder) = &self.recorder { @@ -466,7 +463,7 @@ fn extend_with_runtime_decl_path(mut trait_: Path) -> Path { trait_ } -fn extend_with_api_version(mut trait_: Path, version: Option) -> Path { +fn extend_with_api_version(mut trait_: Path, version: Option) -> Path { let version = if let Some(v) = version { v } else { @@ -740,8 +737,8 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { let mut error = Error::new( span, "Two traits with the same name detected! \ - The trait name is used to generate its ID. \ - Please rename one trait at the declaration!", + The trait name is used to generate its ID. \ + Please rename one trait at the declaration!", ); error.combine(Error::new(other_span, "First trait implementation.")); @@ -787,17 +784,50 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { )) } +/// replaces `Self` with explicit `ItemImpl.self_ty`. +struct ReplaceSelfImpl { + self_ty: Box, +} + +impl ReplaceSelfImpl { + /// Replace `Self` with `ItemImpl.self_ty` + fn replace(&mut self, trait_: &mut ItemImpl) { + visit_mut::visit_item_impl_mut(self, trait_) + } +} + +impl VisitMut for ReplaceSelfImpl { + fn visit_type_mut(&mut self, ty: &mut syn::Type) { + match ty { + Type::Path(p) if p.path.is_ident("Self") => { + *ty = *self.self_ty.clone(); + }, + ty => syn::visit_mut::visit_type_mut(self, ty), + } + } +} + +/// Rename `Self` to `ItemImpl.self_ty` in all items. +fn rename_self_in_trait_impls(impls: &mut [ItemImpl]) { + impls.iter_mut().for_each(|i| { + let mut checker = ReplaceSelfImpl { self_ty: i.self_ty.clone() }; + checker.replace(i); + }); +} + /// The implementation of the `impl_runtime_apis!` macro. pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { // Parse all impl blocks - let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls); + let RuntimeApiImpls { impls: mut api_impls } = parse_macro_input!(input as RuntimeApiImpls); - impl_runtime_apis_impl_inner(&api_impls) + impl_runtime_apis_impl_inner(&mut api_impls) .unwrap_or_else(|e| e.to_compile_error()) .into() } -fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result { +fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result { + rename_self_in_trait_impls(api_impls); + let dispatch_impl = generate_dispatch_function(api_impls)?; let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?; let base_runtime_api = generate_runtime_api_base_structures()?; @@ -841,88 +871,6 @@ fn filter_cfg_attrs(attrs: &[Attribute]) -> Vec { attrs.iter().filter(|a| a.path().is_ident("cfg")).cloned().collect() } -/// Parse feature flagged api_version. -/// E.g. `#[cfg_attr(feature = "enable-staging-api", api_version(99))]` -fn extract_cfg_api_version(attrs: &Vec, span: Span) -> Result> { - let cfg_attrs = attrs.iter().filter(|a| a.path().is_ident("cfg_attr")).collect::>(); - - let mut cfg_api_version_attr = Vec::new(); - for cfg_attr in cfg_attrs { - let mut feature_name = None; - let mut api_version = None; - cfg_attr.parse_nested_meta(|m| { - if m.path.is_ident("feature") { - let a = m.value()?; - let b: LitStr = a.parse()?; - feature_name = Some(b.value()); - } else if m.path.is_ident(API_VERSION_ATTRIBUTE) { - let content; - parenthesized!(content in m.input); - let ver: LitInt = content.parse()?; - api_version = Some(ver.base10_parse::()?); - } - Ok(()) - })?; - - // If there is a cfg attribute containing api_version - save if for processing - if let (Some(feature_name), Some(api_version)) = (feature_name, api_version) { - cfg_api_version_attr.push((feature_name, api_version, cfg_attr.span())); - } - } - - if cfg_api_version_attr.len() > 1 { - let mut err = Error::new(span, format!("Found multiple feature gated api versions (cfg attribute with nested `{}` attribute). This is not supported.", API_VERSION_ATTRIBUTE)); - for (_, _, attr_span) in cfg_api_version_attr { - err.combine(Error::new(attr_span, format!("`{}` found here", API_VERSION_ATTRIBUTE))); - } - - return Err(err); - } - - Ok(cfg_api_version_attr - .into_iter() - .next() - .map(|(feature, name, _)| (feature, name))) -} - -/// Represents an API version. -struct ApiVersion { - /// Corresponds to `#[api_version(X)]` attribute. - pub custom: Option, - /// Corresponds to `#[cfg_attr(feature = "enable-staging-api", api_version(99))]` - /// attribute. `String` is the feature name, `u64` the staging api version. - pub feature_gated: Option<(String, u64)>, -} - -// Extracts the value of `API_VERSION_ATTRIBUTE` and handles errors. -// Returns: -// - Err if the version is malformed -// - `ApiVersion` on success. If a version is set or not is determined by the fields of `ApiVersion` -fn extract_api_version(attrs: &Vec, span: Span) -> Result { - // First fetch all `API_VERSION_ATTRIBUTE` values (should be only one) - let api_ver = attrs - .iter() - .filter(|a| a.path().is_ident(API_VERSION_ATTRIBUTE)) - .collect::>(); - - if api_ver.len() > 1 { - return Err(Error::new( - span, - format!( - "Found multiple #[{}] attributes for an API implementation. \ - Each runtime API can have only one version.", - API_VERSION_ATTRIBUTE - ), - )); - } - - // Parse the runtime version if there exists one. - Ok(ApiVersion { - custom: api_ver.first().map(|v| parse_runtime_api_version(v)).transpose()?, - feature_gated: extract_cfg_api_version(attrs, span)?, - }) -} - #[cfg(test)] mod tests { use super::*; @@ -945,4 +893,34 @@ mod tests { assert_eq!(cfg_std, filtered[0]); assert_eq!(cfg_benchmarks, filtered[1]); } + + #[test] + fn impl_trait_rename_self_param() { + let code = quote::quote! { + impl client::Core for Runtime { + fn initialize_block(header: &HeaderFor) -> Output { + let _: HeaderFor = header.clone(); + example_fn::(header) + } + } + }; + let expected = quote::quote! { + impl client::Core for Runtime { + fn initialize_block(header: &HeaderFor) -> Output { + let _: HeaderFor = header.clone(); + example_fn::(header) + } + } + }; + + // Parse the items + let RuntimeApiImpls { impls: mut api_impls } = + syn::parse2::(code).unwrap(); + + // Run the renamer which is being run first in the `impl_runtime_apis!` macro. + rename_self_in_trait_impls(&mut api_impls); + let result: TokenStream = quote::quote! { #(#api_impls)* }; + + assert_eq!(result.to_string(), expected.to_string()); + } } diff --git a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs index 4cba524dbe25..1706f8ca6fbb 100644 --- a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs +++ b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs @@ -17,14 +17,11 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use syn::{parse_quote, ItemImpl, ItemTrait, Result}; - -use crate::{ - common::CHANGED_IN_ATTRIBUTE, - utils::{ - extract_impl_trait, filter_cfg_attributes, generate_crate_access, - generate_runtime_mod_name_for_trait, get_doc_literals, RequireQualifiedTraitPath, - }, +use syn::{parse_quote, spanned::Spanned, ItemImpl, ItemTrait, Result}; + +use crate::utils::{ + extract_api_version, extract_impl_trait, filter_cfg_attributes, generate_crate_access, + generate_runtime_mod_name_for_trait, get_doc_literals, RequireQualifiedTraitPath, }; /// Get the type parameter argument without lifetime or mutability @@ -72,7 +69,10 @@ fn collect_docs(attrs: &[syn::Attribute], crate_: &TokenStream2) -> TokenStream2 /// /// The metadata is exposed as a generic function on the hidden module /// of the trait generated by the `decl_runtime_apis`. -pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { +pub fn generate_decl_runtime_metadata<'a>( + decl: &ItemTrait, + versioned_methods_iter: impl Iterator, +) -> TokenStream2 { let crate_ = generate_crate_access(); let mut methods = Vec::new(); @@ -86,17 +86,7 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { // This restricts the bounds at the metadata level, without needing to modify the `BlockT` // itself, since the concrete implementations are already satisfying `TypeInfo`. let mut where_clause = Vec::new(); - for item in &decl.items { - // Collect metadata for methods only. - let syn::TraitItem::Fn(method) = item else { continue }; - - // Collect metadata only for the latest methods. - let is_changed_in = - method.attrs.iter().any(|attr| attr.path().is_ident(CHANGED_IN_ATTRIBUTE)); - if is_changed_in { - continue; - } - + for (method, version) in versioned_methods_iter { let mut inputs = Vec::new(); let signature = &method.sig; for input in &signature.inputs { @@ -135,14 +125,21 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { Ok(deprecation) => deprecation, Err(e) => return e.into_compile_error(), }; + + // Methods are filtered so that only those whose version is <= the `impl_version` passed to + // `runtime_metadata` are kept in the metadata we hand back. methods.push(quote!( #( #attrs )* - #crate_::metadata_ir::RuntimeApiMethodMetadataIR { - name: #method_name, - inputs: #crate_::vec![ #( #inputs, )* ], - output: #output, - docs: #docs, - deprecation_info: #deprecation, + if #version <= impl_version { + Some(#crate_::metadata_ir::RuntimeApiMethodMetadataIR { + name: #method_name, + inputs: #crate_::vec![ #( #inputs, )* ], + output: #output, + docs: #docs, + deprecation_info: #deprecation, + }) + } else { + None } )); } @@ -176,12 +173,15 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { #crate_::frame_metadata_enabled! { #( #attrs )* #[inline(always)] - pub fn runtime_metadata #impl_generics () -> #crate_::metadata_ir::RuntimeApiMetadataIR + pub fn runtime_metadata #impl_generics (impl_version: u32) -> #crate_::metadata_ir::RuntimeApiMetadataIR #where_clause { #crate_::metadata_ir::RuntimeApiMetadataIR { name: #trait_name, - methods: #crate_::vec![ #( #methods, )* ], + methods: [ #( #methods, )* ] + .into_iter() + .filter_map(|maybe_m| maybe_m) + .collect(), docs: #docs, deprecation_info: #deprecation, } @@ -242,10 +242,43 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result Result #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { #crate_::vec![ #( #metadata, )* ] } } - #[doc(hidden)] - impl InternalImplRuntimeApis for #runtime_name {} } )) } diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index dc993c2ac420..65620d1bc640 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -21,9 +21,9 @@ use proc_macro2::{Span, TokenStream}; 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, ItemImpl, Lit, Meta, MetaNameValue, Pat, Path, - PathArguments, Result, ReturnType, Signature, Token, Type, TypePath, + parenthesized, parse_quote, punctuated::Punctuated, spanned::Spanned, token::And, Attribute, + Error, Expr, ExprLit, FnArg, GenericArgument, Ident, ItemImpl, Lit, LitInt, LitStr, Meta, + MetaNameValue, Pat, Path, PathArguments, Result, ReturnType, Signature, Token, Type, TypePath, }; /// Generates the access to the `sc_client` crate. @@ -216,7 +216,7 @@ pub fn extract_impl_trait(impl_: &ItemImpl, require: RequireQualifiedTraitPath) } /// Parse the given attribute as `API_VERSION_ATTRIBUTE`. -pub fn parse_runtime_api_version(version: &Attribute) -> Result { +pub fn parse_runtime_api_version(version: &Attribute) -> Result { let version = version.parse_args::().map_err(|_| { Error::new( version.span(), @@ -231,7 +231,7 @@ pub fn parse_runtime_api_version(version: &Attribute) -> Result { } /// Each versioned trait is named 'ApiNameVN' where N is the specific version. E.g. ParachainHostV2 -pub fn versioned_trait_name(trait_ident: &Ident, version: u64) -> Ident { +pub fn versioned_trait_name(trait_ident: &Ident, version: u32) -> Ident { format_ident!("{}V{}", trait_ident, version) } @@ -334,6 +334,89 @@ pub fn get_deprecation(crate_: &TokenStream, attrs: &[syn::Attribute]) -> Result .unwrap_or_else(|| Ok(quote! {#crate_::metadata_ir::DeprecationStatusIR::NotDeprecated})) } +/// Represents an API version. +pub struct ApiVersion { + /// Corresponds to `#[api_version(X)]` attribute. + pub custom: Option, + /// Corresponds to `#[cfg_attr(feature = "enable-staging-api", api_version(99))]` + /// attribute. `String` is the feature name, `u32` the staging api version. + pub feature_gated: Option<(String, u32)>, +} + +/// Extracts the value of `API_VERSION_ATTRIBUTE` and handles errors. +/// Returns: +/// - Err if the version is malformed +/// - `ApiVersion` on success. If a version is set or not is determined by the fields of +/// `ApiVersion` +pub fn extract_api_version(attrs: &[Attribute], span: Span) -> Result { + // First fetch all `API_VERSION_ATTRIBUTE` values (should be only one) + let api_ver = attrs + .iter() + .filter(|a| a.path().is_ident(API_VERSION_ATTRIBUTE)) + .collect::>(); + + if api_ver.len() > 1 { + return Err(Error::new( + span, + format!( + "Found multiple #[{}] attributes for an API implementation. \ + Each runtime API can have only one version.", + API_VERSION_ATTRIBUTE + ), + )); + } + + // Parse the runtime version if there exists one. + Ok(ApiVersion { + custom: api_ver.first().map(|v| parse_runtime_api_version(v)).transpose()?, + feature_gated: extract_cfg_api_version(attrs, span)?, + }) +} + +/// Parse feature flagged api_version. +/// E.g. `#[cfg_attr(feature = "enable-staging-api", api_version(99))]` +fn extract_cfg_api_version(attrs: &[Attribute], span: Span) -> Result> { + let cfg_attrs = attrs.iter().filter(|a| a.path().is_ident("cfg_attr")).collect::>(); + + let mut cfg_api_version_attr = Vec::new(); + for cfg_attr in cfg_attrs { + let mut feature_name = None; + let mut api_version = None; + cfg_attr.parse_nested_meta(|m| { + if m.path.is_ident("feature") { + let a = m.value()?; + let b: LitStr = a.parse()?; + feature_name = Some(b.value()); + } else if m.path.is_ident(API_VERSION_ATTRIBUTE) { + let content; + parenthesized!(content in m.input); + let ver: LitInt = content.parse()?; + api_version = Some(ver.base10_parse::()?); + } + Ok(()) + })?; + + // If there is a cfg attribute containing api_version - save if for processing + if let (Some(feature_name), Some(api_version)) = (feature_name, api_version) { + cfg_api_version_attr.push((feature_name, api_version, cfg_attr.span())); + } + } + + if cfg_api_version_attr.len() > 1 { + let mut err = Error::new(span, format!("Found multiple feature gated api versions (cfg attribute with nested `{}` attribute). This is not supported.", API_VERSION_ATTRIBUTE)); + for (_, _, attr_span) in cfg_api_version_attr { + err.combine(Error::new(attr_span, format!("`{}` found here", API_VERSION_ATTRIBUTE))); + } + + return Err(err); + } + + Ok(cfg_api_version_attr + .into_iter() + .next() + .map(|(feature, name, _)| (feature, name))) +} + #[cfg(test)] mod tests { use assert_matches::assert_matches; diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index 700e212688c8..b412d4b52fed 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -105,7 +105,7 @@ pub mod __private { generic::BlockId, traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, NumberFor}, transaction_validity::TransactionValidity, - ExtrinsicInclusionMode, RuntimeString, TransactionOutcome, + ExtrinsicInclusionMode, TransactionOutcome, }; pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; @@ -286,7 +286,7 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// # Example /// /// ```rust -/// use sp_version::create_runtime_str; +/// extern crate alloc; /// # /// # use sp_runtime::{ExtrinsicInclusionMode, traits::Block as BlockT}; /// # use sp_test_primitives::Block; @@ -338,8 +338,8 @@ pub use sp_api_proc_macro::decl_runtime_apis; /// /// /// Runtime version. This needs to be declared for each runtime. /// pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion { -/// spec_name: create_runtime_str!("node"), -/// impl_name: create_runtime_str!("test-node"), +/// spec_name: alloc::borrow::Cow::Borrowed("node"), +/// impl_name: alloc::borrow::Cow::Borrowed("test-node"), /// authoring_version: 1, /// spec_version: 1, /// impl_version: 0, diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 1d21f23eb804..9b02cf125eae 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -15,18 +15,19 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { workspace = true, default-features = true } +rustversion = { workspace = true } +sc-block-builder = { workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } sp-api = { workspace = true, default-features = true } -substrate-test-runtime-client = { workspace = true } -sp-version = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } -sc-block-builder = { workspace = true, default-features = true } -codec = { workspace = true, default-features = true } +sp-metadata-ir = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } trybuild = { workspace = true } -rustversion = { workspace = true } -scale-info = { features = ["derive"], workspace = true } [dev-dependencies] criterion = { workspace = true, default-features = true } @@ -40,5 +41,5 @@ name = "bench" harness = false [features] -"enable-staging-api" = [] +enable-staging-api = [] disable-ui-tests = [] diff --git a/substrate/primitives/api/test/tests/decl_and_impl.rs b/substrate/primitives/api/test/tests/decl_and_impl.rs index 211a08561fd4..2e5a078cb382 100644 --- a/substrate/primitives/api/test/tests/decl_and_impl.rs +++ b/substrate/primitives/api/test/tests/decl_and_impl.rs @@ -24,7 +24,7 @@ use substrate_test_runtime_client::runtime::{Block, Hash}; /// The declaration of the `Runtime` type is done by the `construct_runtime!` macro in a real /// runtime. -pub enum Runtime {} +pub struct Runtime {} decl_runtime_apis! { pub trait Api { @@ -306,3 +306,64 @@ fn mock_runtime_api_works_with_advanced() { mock.wild_card(Hash::repeat_byte(0x01), 1).unwrap_err().to_string(), ); } + +#[test] +fn runtime_api_metadata_matches_version_implemented() { + use sp_metadata_ir::InternalImplRuntimeApis; + + let rt = Runtime {}; + let runtime_metadata = rt.runtime_metadata(); + + // Check that the metadata for some runtime API matches expectation. + let assert_has_api_with_methods = |api_name: &str, api_methods: &[&str]| { + let Some(api) = runtime_metadata.iter().find(|api| api.name == api_name) else { + panic!("Can't find runtime API '{api_name}'"); + }; + if api.methods.len() != api_methods.len() { + panic!( + "Wrong number of methods in '{api_name}'; expected {} methods but got {}: {:?}", + api_methods.len(), + api.methods.len(), + api.methods + ); + } + for expected_name in api_methods { + if !api.methods.iter().any(|method| &method.name == expected_name) { + panic!("Can't find API method '{expected_name}' in '{api_name}'"); + } + } + }; + + assert_has_api_with_methods("ApiWithCustomVersion", &["same_name"]); + + assert_has_api_with_methods("ApiWithMultipleVersions", &["stable_one", "new_one"]); + + assert_has_api_with_methods( + "ApiWithStagingMethod", + &[ + "stable_one", + #[cfg(feature = "enable-staging-api")] + "staging_one", + ], + ); + + assert_has_api_with_methods( + "ApiWithStagingAndVersionedMethods", + &[ + "stable_one", + "new_one", + #[cfg(feature = "enable-staging-api")] + "staging_one", + ], + ); + + assert_has_api_with_methods( + "ApiWithStagingAndChangedBase", + &[ + "stable_one", + "new_one", + #[cfg(feature = "enable-staging-api")] + "staging_one", + ], + ); +} diff --git a/substrate/primitives/api/test/tests/runtime_calls.rs b/substrate/primitives/api/test/tests/runtime_calls.rs index 5a524d1c7f4d..0470b8b72aa0 100644 --- a/substrate/primitives/api/test/tests/runtime_calls.rs +++ b/substrate/primitives/api/test/tests/runtime_calls.rs @@ -99,8 +99,8 @@ fn record_proof_works() { let transaction = Transfer { amount: 1000, nonce: 0, - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), } .into_unchecked_extrinsic(); diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 1161d43ded5a..9589cce042f5 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -18,10 +18,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-core = { workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["alloc", "derive"], workspace = true } +sp-core = { workspace = true } sp-io = { workspace = true } [features] diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 485656bf30bb..77b82fbe6468 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -21,18 +21,18 @@ codec = { features = [ "derive", "max-encoded-len", ], workspace = true } +docify = { workspace = true } integer-sqrt = { workspace = true } num-traits = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = { workspace = true, default-features = true } -docify = { workspace = true } [dev-dependencies] criterion = { workspace = true, default-features = true } primitive-types = { workspace = true, default-features = true } -sp-crypto-hashing = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 93158274d98f..aed09a684bda 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -21,11 +21,11 @@ codec = { features = ["derive"], workspace = true } futures = { workspace = true } parking_lot = { workspace = true, default-features = true } schnellru = { workspace = true } -thiserror = { workspace = true } sp-api = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-database = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } +thiserror = { workspace = true } tracing = { workspace = true, default-features = true } diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index ee07da6829f5..163fbafa8dd4 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -134,7 +134,7 @@ pub enum ConsensusLog { } /// Configuration data used by the BABE consensus engine. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct BabeConfigurationV1 { /// The slot duration in milliseconds for BABE. Currently, only /// the value provided by this type at genesis will be used. diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 13d80683c853..572e46d8de8d 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -23,9 +23,9 @@ sp-application-crypto = { workspace = true } sp-core = { workspace = true } sp-crypto-hashing = { workspace = true } sp-io = { workspace = true } +sp-keystore = { workspace = true } sp-mmr-primitives = { workspace = true } sp-runtime = { workspace = true } -sp-keystore = { workspace = true } sp-weights = { workspace = true } strum = { features = ["derive"], workspace = true } diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index 764ef1d97346..3a6ffd031ec5 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -20,11 +20,11 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { workspace = true } futures = { features = ["thread-pool"], workspace = true } log = { workspace = true, default-features = true } -thiserror = { workspace = true } sp-core = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } +thiserror = { workspace = true } [dev-dependencies] futures = { workspace = true } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index f6bc17bccaca..0ea885abd22d 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -16,47 +16,47 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { features = ["derive", "max-encoded-len"], workspace = true } -scale-info = { features = ["derive"], workspace = true } -log = { workspace = true } -serde = { optional = true, features = ["alloc", "derive"], workspace = true } bounded-collections = { workspace = true } -primitive-types = { features = ["codec", "scale-info"], workspace = true } -impl-serde = { optional = true, workspace = true } +bs58 = { optional = true, workspace = true } +codec = { features = ["derive", "max-encoded-len"], workspace = true } hash-db = { workspace = true } hash256-std-hasher = { workspace = true } -bs58 = { optional = true, workspace = true } +impl-serde = { optional = true, workspace = true } +log = { workspace = true } +primitive-types = { features = ["codec", "scale-info"], workspace = true } rand = { features = [ "small_rng", ], optional = true, workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true } +serde = { optional = true, features = ["alloc", "derive"], workspace = 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", ] } -zeroize = { workspace = true } -secrecy = { features = ["alloc"], workspace = true } +bitflags = { workspace = true } +dyn-clonable = { optional = true, workspace = true } +futures = { optional = true, workspace = true } +itertools = { optional = true, workspace = true } parking_lot = { optional = true, workspace = true, default-features = true } -ss58-registry = { workspace = true } -sp-std = { workspace = true } +paste = { workspace = true, default-features = true } +secrecy = { features = ["alloc"], workspace = true } sp-debug-derive = { workspace = true } -sp-storage = { workspace = true } sp-externalities = { optional = true, workspace = true } -futures = { optional = true, workspace = true } -dyn-clonable = { optional = true, workspace = true } +sp-std = { workspace = true } +sp-storage = { workspace = true } +ss58-registry = { workspace = true } thiserror = { optional = true, workspace = true } tracing = { optional = true, workspace = true, default-features = true } -bitflags = { workspace = true } -paste = { workspace = true, default-features = true } -itertools = { optional = true, workspace = true } +zeroize = { workspace = true } # full crypto array-bytes = { workspace = true, default-features = true } -ed25519-zebra = { workspace = true } blake2 = { optional = true, workspace = true } +ed25519-zebra = { workspace = true } libsecp256k1 = { features = ["static-context"], workspace = true } -schnorrkel = { features = ["preaudit_deprecated"], workspace = true } merlin = { workspace = true } +schnorrkel = { features = ["preaudit_deprecated"], workspace = true } sp-crypto-hashing = { workspace = true } sp-runtime-interface = { workspace = true } # k256 crate, better portability, intended to be used in substrate-runtimes (no-std) @@ -76,8 +76,8 @@ bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "0fef826", [dev-dependencies] criterion = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } regex = { workspace = true } +serde_json = { workspace = true, default-features = true } [[bench]] name = "bench" diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index b04d94e2bf40..cf24861e233c 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -17,7 +17,7 @@ //! Cryptographic utilities. -use crate::{ed25519, sr25519}; +use crate::{ed25519, sr25519, U256}; use alloc::{format, str, vec::Vec}; #[cfg(all(not(feature = "std"), feature = "serde"))] use alloc::{string::String, vec}; @@ -1191,7 +1191,7 @@ macro_rules! impl_from_entropy_base { } } -impl_from_entropy_base!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); +impl_from_entropy_base!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, U256); #[cfg(test)] mod tests { diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index bb05bebc6274..454f61df7941 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -101,8 +101,9 @@ pub use bounded_collections as bounded; #[cfg(feature = "std")] pub use bounded_collections::{bounded_btree_map, bounded_vec}; pub use bounded_collections::{ - parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, - ConstU16, ConstU32, ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, + parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstInt, + ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, ConstUint, Get, GetDefault, TryCollect, + TypedGet, }; pub use sp_storage as storage; diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 29e30133ebea..1e5964f85575 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -15,17 +15,17 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -ark-ec = { optional = true, workspace = true } -ark-bls12-377-ext = { optional = true, workspace = true } ark-bls12-377 = { features = ["curve"], optional = true, workspace = true } -ark-bls12-381-ext = { optional = true, workspace = true } +ark-bls12-377-ext = { optional = true, workspace = true } ark-bls12-381 = { features = ["curve"], optional = true, workspace = true } -ark-bw6-761-ext = { optional = true, workspace = true } +ark-bls12-381-ext = { optional = true, workspace = true } ark-bw6-761 = { optional = true, workspace = true } -ark-ed-on-bls12-381-bandersnatch-ext = { optional = true, workspace = true } -ark-ed-on-bls12-381-bandersnatch = { optional = true, workspace = true } -ark-ed-on-bls12-377-ext = { optional = true, workspace = true } +ark-bw6-761-ext = { optional = true, workspace = true } +ark-ec = { optional = true, workspace = true } ark-ed-on-bls12-377 = { optional = true, workspace = true } +ark-ed-on-bls12-377-ext = { optional = true, workspace = true } +ark-ed-on-bls12-381-bandersnatch = { optional = true, workspace = true } +ark-ed-on-bls12-381-bandersnatch-ext = { optional = true, workspace = true } ark-scale = { features = ["hazmat"], optional = true, workspace = true } sp-runtime-interface = { optional = true, workspace = true } diff --git a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml index 6f974a3e2c8a..e09661d41c11 100644 --- a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml @@ -20,5 +20,5 @@ proc-macro = true [dependencies] quote = { workspace = true } -syn = { features = ["full", "parsing"], workspace = true } sp-crypto-hashing = { workspace = true } +syn = { features = ["full", "parsing"], workspace = true } diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 4979b89155ab..a26cbbf62ada 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -19,9 +19,9 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] +proc-macro2 = { workspace = true } quote = { workspace = true } syn = { workspace = true } -proc-macro2 = { workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 285b214907ad..f1fa60d023be 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -19,9 +19,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { features = ["bytes"], workspace = true } scale-info = { features = ["derive"], workspace = true } +serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } -serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/genesis-builder/src/lib.rs b/substrate/primitives/genesis-builder/src/lib.rs index 4763aa06341e..9abc27868864 100644 --- a/substrate/primitives/genesis-builder/src/lib.rs +++ b/substrate/primitives/genesis-builder/src/lib.rs @@ -73,13 +73,13 @@ //! which is the foundation for genesis block. extern crate alloc; -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; /// The result type alias, used in build methods. `Err` contains formatted error message. -pub type Result = core::result::Result<(), sp_runtime::RuntimeString>; +pub type Result = core::result::Result<(), String>; /// The type representing preset ID. -pub type PresetId = sp_runtime::RuntimeString; +pub type PresetId = String; /// The default `development` preset used to communicate with the runtime via /// [`GenesisBuilder`] interface. diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 271308c9cbf1..19966919047f 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -19,10 +19,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { optional = true, workspace = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } impl-trait-for-tuples = { workspace = true } -thiserror = { optional = true, workspace = true } +scale-info = { features = ["derive"], workspace = true } sp-runtime = { optional = true, workspace = true } +thiserror = { optional = true, workspace = true } [dev-dependencies] futures = { workspace = true } diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index 97940759a987..b0c99002910b 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -22,20 +22,20 @@ bytes = { workspace = true } codec = { features = [ "bytes", ], workspace = true } -sp-core = { workspace = true } -sp-crypto-hashing = { workspace = true } -sp-keystore = { optional = true, workspace = true } libsecp256k1 = { optional = true, workspace = true, default-features = true } -sp-state-machine = { optional = true, workspace = true } -sp-runtime-interface = { workspace = true } -sp-trie = { optional = true, workspace = true } -sp-externalities = { workspace = true } -sp-tracing = { workspace = true } log = { optional = true, workspace = true, default-features = true } secp256k1 = { features = [ "global-context", "recovery", ], optional = true, workspace = true, default-features = true } +sp-core = { workspace = true } +sp-crypto-hashing = { workspace = true } +sp-externalities = { workspace = true } +sp-keystore = { optional = true, workspace = true } +sp-runtime-interface = { workspace = true } +sp-state-machine = { optional = true, workspace = true } +sp-tracing = { workspace = true } +sp-trie = { optional = true, workspace = true } tracing = { workspace = true } tracing-core = { workspace = true } diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 27f7304a9358..9ffcf50c7b45 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -17,9 +17,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -strum = { features = ["derive"], workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +strum = { features = ["derive"], workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/keyring/src/lib.rs b/substrate/primitives/keyring/src/lib.rs index 008c01b150f0..36e77dabd601 100644 --- a/substrate/primitives/keyring/src/lib.rs +++ b/substrate/primitives/keyring/src/lib.rs @@ -32,20 +32,11 @@ pub mod ed25519; #[cfg(feature = "bandersnatch-experimental")] pub mod bandersnatch; -/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`, since it tends to be -/// used for accounts (although it may also be used by authorities). -pub use sr25519::Keyring as AccountKeyring; - #[cfg(feature = "bandersnatch-experimental")] pub use bandersnatch::Keyring as BandersnatchKeyring; pub use ed25519::Keyring as Ed25519Keyring; pub use sr25519::Keyring as Sr25519Keyring; -pub mod test { - /// The keyring for use with accounts when using the test runtime. - pub use super::ed25519::Keyring as AccountKeyring; -} - #[derive(Debug)] /// Represents an error that occurs when parsing a string into a `KeyRing`. pub struct ParseKeyringError; diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 6f944a3f6a8d..5f861ca7acf1 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -16,9 +16,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -scale-info = { features = ["derive"], workspace = true } log = { workspace = true } mmr-lib = { package = "polkadot-ckb-merkle-mountain-range", version = "0.7.0", default-features = false } +scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { workspace = true } sp-core = { workspace = true } diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index d7786347dd02..046441104b88 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } -frame-metadata = { features = ["current"], workspace = true } +frame-metadata = { features = ["current", "unstable"], workspace = true } scale-info = { features = ["derive"], workspace = true } [features] diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index 4bd13b935afd..dc01f7eaadb3 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -30,6 +30,7 @@ mod types; use frame_metadata::RuntimeMetadataPrefixed; pub use types::*; +mod unstable; mod v14; mod v15; @@ -39,23 +40,33 @@ const V14: u32 = 14; /// Metadata V15. const V15: u32 = 15; +/// Unstable metadata V16. +const UNSTABLE_V16: u32 = u32::MAX; + /// Transform the IR to the specified version. /// /// Use [`supported_versions`] to find supported versions. pub fn into_version(metadata: MetadataIR, version: u32) -> Option { // Note: Unstable metadata version is `u32::MAX` until stabilized. match version { - // Latest stable version. + // Version V14. This needs to be around until the + // deprecation of the `Metadata_metadata` runtime call in favor of + // `Metadata_metadata_at_version. V14 => Some(into_v14(metadata)), - // Unstable metadata. + + // Version V15 - latest stable. V15 => Some(into_latest(metadata)), + + // Unstable metadata under `u32::MAX`. + UNSTABLE_V16 => Some(into_unstable(metadata)), + _ => None, } } /// Returns the supported metadata versions. pub fn supported_versions() -> alloc::vec::Vec { - alloc::vec![V14, V15] + alloc::vec![V14, V15, UNSTABLE_V16] } /// Transform the IR to the latest stable metadata version. @@ -70,6 +81,22 @@ pub fn into_v14(metadata: MetadataIR) -> RuntimeMetadataPrefixed { latest.into() } +/// Transform the IR to unstable metadata version 16. +pub fn into_unstable(metadata: MetadataIR) -> RuntimeMetadataPrefixed { + let latest: frame_metadata::v16::RuntimeMetadataV16 = metadata.into(); + latest.into() +} + +/// INTERNAL USE ONLY +/// +/// Special trait that is used together with `InternalConstructRuntime` by `construct_runtime!` to +/// fetch the runtime api metadata without exploding when there is no runtime api implementation +/// available. +#[doc(hidden)] +pub trait InternalImplRuntimeApis { + fn runtime_metadata(&self) -> alloc::vec::Vec; +} + #[cfg(test)] mod test { use super::*; @@ -81,7 +108,7 @@ mod test { pallets: vec![], extrinsic: ExtrinsicMetadataIR { ty: meta_type::<()>(), - version: 0, + versions: vec![0], address_ty: meta_type::<()>(), call_ty: meta_type::<()>(), signature_ty: meta_type::<()>(), diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index 199b692fbd8c..af217ffe16ee 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -170,8 +170,8 @@ pub struct ExtrinsicMetadataIR { /// /// Note: Field used for metadata V14 only. pub ty: T::Type, - /// Extrinsic version. - pub version: u8, + /// Extrinsic versions. + pub versions: Vec, /// The type of the address that signs the extrinsic pub address_ty: T::Type, /// The type of the outermost Call enum. @@ -191,7 +191,7 @@ impl IntoPortable for ExtrinsicMetadataIR { fn into_portable(self, registry: &mut Registry) -> Self::Output { ExtrinsicMetadataIR { ty: registry.register_type(&self.ty), - version: self.version, + versions: self.versions, address_ty: registry.register_type(&self.address_ty), call_ty: registry.register_type(&self.call_ty), signature_ty: registry.register_type(&self.signature_ty), diff --git a/substrate/primitives/metadata-ir/src/unstable.rs b/substrate/primitives/metadata-ir/src/unstable.rs new file mode 100644 index 000000000000..d46ce3ec6a7d --- /dev/null +++ b/substrate/primitives/metadata-ir/src/unstable.rs @@ -0,0 +1,211 @@ +// 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. + +//! Convert the IR to V16 metadata. + +use crate::{ + DeprecationInfoIR, DeprecationStatusIR, OuterEnumsIR, PalletAssociatedTypeMetadataIR, + PalletCallMetadataIR, PalletConstantMetadataIR, PalletErrorMetadataIR, PalletEventMetadataIR, + PalletStorageMetadataIR, StorageEntryMetadataIR, +}; + +use super::types::{ + ExtrinsicMetadataIR, MetadataIR, PalletMetadataIR, RuntimeApiMetadataIR, + RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, TransactionExtensionMetadataIR, +}; + +use frame_metadata::v16::{ + CustomMetadata, DeprecationInfo, DeprecationStatus, ExtrinsicMetadata, OuterEnums, + PalletAssociatedTypeMetadata, PalletCallMetadata, PalletConstantMetadata, PalletErrorMetadata, + PalletEventMetadata, PalletMetadata, PalletStorageMetadata, RuntimeApiMetadata, + RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV16, + StorageEntryMetadata, TransactionExtensionMetadata, +}; + +impl From for RuntimeMetadataV16 { + fn from(ir: MetadataIR) -> Self { + RuntimeMetadataV16::new( + ir.pallets.into_iter().map(Into::into).collect(), + ir.extrinsic.into(), + ir.apis.into_iter().map(Into::into).collect(), + ir.outer_enums.into(), + // Substrate does not collect yet the custom metadata fields. + // This allows us to extend the V16 easily. + CustomMetadata { map: Default::default() }, + ) + } +} + +impl From for RuntimeApiMetadata { + fn from(ir: RuntimeApiMetadataIR) -> Self { + RuntimeApiMetadata { + name: ir.name, + methods: ir.methods.into_iter().map(Into::into).collect(), + docs: ir.docs, + deprecation_info: ir.deprecation_info.into(), + } + } +} + +impl From for RuntimeApiMethodMetadata { + fn from(ir: RuntimeApiMethodMetadataIR) -> Self { + RuntimeApiMethodMetadata { + name: ir.name, + inputs: ir.inputs.into_iter().map(Into::into).collect(), + output: ir.output, + docs: ir.docs, + deprecation_info: ir.deprecation_info.into(), + } + } +} + +impl From for RuntimeApiMethodParamMetadata { + fn from(ir: RuntimeApiMethodParamMetadataIR) -> Self { + RuntimeApiMethodParamMetadata { name: ir.name, ty: ir.ty } + } +} + +impl From for PalletMetadata { + fn from(ir: PalletMetadataIR) -> Self { + PalletMetadata { + name: ir.name, + storage: ir.storage.map(Into::into), + calls: ir.calls.map(Into::into), + event: ir.event.map(Into::into), + constants: ir.constants.into_iter().map(Into::into).collect(), + error: ir.error.map(Into::into), + index: ir.index, + docs: ir.docs, + associated_types: ir.associated_types.into_iter().map(Into::into).collect(), + deprecation_info: ir.deprecation_info.into(), + } + } +} + +impl From for PalletStorageMetadata { + fn from(ir: PalletStorageMetadataIR) -> Self { + PalletStorageMetadata { + prefix: ir.prefix, + entries: ir.entries.into_iter().map(Into::into).collect(), + } + } +} + +impl From for StorageEntryMetadata { + fn from(ir: StorageEntryMetadataIR) -> Self { + StorageEntryMetadata { + name: ir.name, + modifier: ir.modifier.into(), + ty: ir.ty.into(), + default: ir.default, + docs: ir.docs, + deprecation_info: ir.deprecation_info.into(), + } + } +} + +impl From for PalletAssociatedTypeMetadata { + fn from(ir: PalletAssociatedTypeMetadataIR) -> Self { + PalletAssociatedTypeMetadata { name: ir.name, ty: ir.ty, docs: ir.docs } + } +} + +impl From for PalletErrorMetadata { + fn from(ir: PalletErrorMetadataIR) -> Self { + PalletErrorMetadata { ty: ir.ty, deprecation_info: ir.deprecation_info.into() } + } +} + +impl From for PalletEventMetadata { + fn from(ir: PalletEventMetadataIR) -> Self { + PalletEventMetadata { ty: ir.ty, deprecation_info: ir.deprecation_info.into() } + } +} + +impl From for PalletCallMetadata { + fn from(ir: PalletCallMetadataIR) -> Self { + PalletCallMetadata { ty: ir.ty, deprecation_info: ir.deprecation_info.into() } + } +} + +impl From for PalletConstantMetadata { + fn from(ir: PalletConstantMetadataIR) -> Self { + PalletConstantMetadata { + name: ir.name, + ty: ir.ty, + value: ir.value, + docs: ir.docs, + deprecation_info: ir.deprecation_info.into(), + } + } +} + +impl From for TransactionExtensionMetadata { + fn from(ir: TransactionExtensionMetadataIR) -> Self { + TransactionExtensionMetadata { identifier: ir.identifier, ty: ir.ty, implicit: ir.implicit } + } +} + +impl From for ExtrinsicMetadata { + fn from(ir: ExtrinsicMetadataIR) -> Self { + // Assume version 0 for all extensions. + let indexes = (0..ir.extensions.len()).map(|index| index as u32).collect(); + let transaction_extensions_by_version = [(0, indexes)].iter().cloned().collect(); + + ExtrinsicMetadata { + versions: ir.versions, + address_ty: ir.address_ty, + signature_ty: ir.signature_ty, + transaction_extensions_by_version, + transaction_extensions: ir.extensions.into_iter().map(Into::into).collect(), + } + } +} + +impl From for OuterEnums { + fn from(ir: OuterEnumsIR) -> Self { + OuterEnums { + call_enum_ty: ir.call_enum_ty, + event_enum_ty: ir.event_enum_ty, + error_enum_ty: ir.error_enum_ty, + } + } +} + +impl From for DeprecationStatus { + fn from(ir: DeprecationStatusIR) -> Self { + match ir { + DeprecationStatusIR::NotDeprecated => DeprecationStatus::NotDeprecated, + DeprecationStatusIR::DeprecatedWithoutNote => DeprecationStatus::DeprecatedWithoutNote, + DeprecationStatusIR::Deprecated { since, note } => + DeprecationStatus::Deprecated { since, note }, + } + } +} + +impl From for DeprecationInfo { + fn from(ir: DeprecationInfoIR) -> Self { + match ir { + DeprecationInfoIR::NotDeprecated => DeprecationInfo::NotDeprecated, + DeprecationInfoIR::ItemDeprecated(status) => + DeprecationInfo::ItemDeprecated(status.into()), + DeprecationInfoIR::VariantsDeprecated(btree) => DeprecationInfo::VariantsDeprecated( + btree.into_iter().map(|(key, value)| (key.0, value.into())).collect(), + ), + } + } +} diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index 70e84532add9..f3cb5973f5bd 100644 --- a/substrate/primitives/metadata-ir/src/v14.rs +++ b/substrate/primitives/metadata-ir/src/v14.rs @@ -149,9 +149,12 @@ impl From for SignedExtensionMetadata { impl From for ExtrinsicMetadata { fn from(ir: ExtrinsicMetadataIR) -> Self { + let lowest_supported_version = + ir.versions.iter().min().expect("Metadata V14 supports one version; qed"); + ExtrinsicMetadata { ty: ir.ty, - version: ir.version, + version: *lowest_supported_version, signed_extensions: ir.extensions.into_iter().map(Into::into).collect(), } } diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index 4b3b6106d27f..ed315a31e6dc 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -100,7 +100,7 @@ impl From for SignedExtensionMetadata { impl From for ExtrinsicMetadata { fn from(ir: ExtrinsicMetadataIR) -> Self { ExtrinsicMetadata { - version: ir.version, + version: *ir.versions.iter().min().expect("Metadata V15 supports only one version"), address_ty: ir.address_ty, call_ty: ir.call_ty, signature_ty: ir.signature_ty, diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml index ee44d90fa959..2d82838ca0b3 100644 --- a/substrate/primitives/runtime-interface/Cargo.toml +++ b/substrate/primitives/runtime-interface/Cargo.toml @@ -18,26 +18,26 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { workspace = true } -sp-wasm-interface = { workspace = true } -sp-std = { workspace = true } -sp-tracing = { workspace = true } -sp-runtime-interface-proc-macro = { workspace = true, default-features = true } -sp-externalities = { workspace = true } codec = { features = ["bytes"], workspace = true } -static_assertions = { workspace = true, default-features = true } +impl-trait-for-tuples = { workspace = true } primitive-types = { workspace = true } +sp-externalities = { workspace = true } +sp-runtime-interface-proc-macro = { workspace = true, default-features = true } +sp-std = { workspace = true } sp-storage = { workspace = true } -impl-trait-for-tuples = { workspace = true } +sp-tracing = { workspace = true } +sp-wasm-interface = { workspace = true } +static_assertions = { workspace = true, default-features = true } [target.'cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))'.dependencies] polkavm-derive = { workspace = true } [dev-dependencies] -sp-runtime-interface-test-wasm = { workspace = true } -sp-state-machine = { workspace = true, default-features = true } +rustversion = { workspace = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -rustversion = { workspace = true } +sp-runtime-interface-test-wasm = { workspace = true } +sp-state-machine = { workspace = true, default-features = true } trybuild = { workspace = true } [features] diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 3fd5f073f025..2112d5bc0693 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -20,8 +20,8 @@ proc-macro = true [dependencies] Inflector = { workspace = true } +expander = { workspace = true } proc-macro-crate = { workspace = true } proc-macro2 = { workspace = true } quote = { workspace = true } -expander = { workspace = true } syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } diff --git a/substrate/primitives/runtime-interface/test/Cargo.toml b/substrate/primitives/runtime-interface/test/Cargo.toml index 29ef0f6b4892..ebcf4222bda3 100644 --- a/substrate/primitives/runtime-interface/test/Cargo.toml +++ b/substrate/primitives/runtime-interface/test/Cargo.toml @@ -15,8 +15,6 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -tracing = { workspace = true, default-features = true } -tracing-core = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-executor-common = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } @@ -25,3 +23,5 @@ sp-runtime-interface = { workspace = true, default-features = true } sp-runtime-interface-test-wasm = { workspace = true } sp-runtime-interface-test-wasm-deprecated = { workspace = true } sp-state-machine = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } +tracing-core = { workspace = true, default-features = true } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 8a812c3a5772..89c221d574fc 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -17,7 +17,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +binary-merkle-tree = { workspace = true } codec = { features = ["derive", "max-encoded-len"], workspace = true } +docify = { workspace = true } either = { workspace = true } hash256-std-hasher = { workspace = true } impl-trait-for-tuples = { workspace = true } @@ -34,9 +36,7 @@ sp-io = { workspace = true } sp-std = { workspace = true } 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 } tuplex = { version = "0.1.2", default-features = false } @@ -44,11 +44,11 @@ tuplex = { version = "0.1.2", default-features = false } [dev-dependencies] rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -zstd = { workspace = true } sp-api = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +zstd = { workspace = true } [features] runtime-benchmarks = [] diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index e2ecd5ed6da7..1842b1631621 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -30,6 +30,12 @@ use crate::{ transaction_validity::{TransactionSource, TransactionValidity}, }; +use super::unchecked_extrinsic::ExtensionVersion; + +/// Default version of the [Extension](TransactionExtension) used to construct the inherited +/// implication for legacy transactions. +const DEFAULT_EXTENSION_VERSION: ExtensionVersion = 0; + /// The kind of extrinsic this is, including any fields required of that kind. This is basically /// the full extrinsic except the `Call`. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] @@ -42,7 +48,7 @@ pub enum ExtrinsicFormat { Signed(AccountId, Extension), /// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s. /// regular checks and includes all extension data. - General(Extension), + General(ExtensionVersion, Extension), } /// Definition of something that the external world might want to say; its existence implies that it @@ -85,10 +91,20 @@ where }, ExtrinsicFormat::Signed(ref signer, ref extension) => { let origin = Some(signer.clone()).into(); - extension.validate_only(origin, &self.function, info, len).map(|x| x.0) + extension + .validate_only( + origin, + &self.function, + info, + len, + source, + DEFAULT_EXTENSION_VERSION, + ) + .map(|x| x.0) }, - ExtrinsicFormat::General(ref extension) => - extension.validate_only(None.into(), &self.function, info, len).map(|x| x.0), + ExtrinsicFormat::General(extension_version, ref extension) => extension + .validate_only(None.into(), &self.function, info, len, source, extension_version) + .map(|x| x.0), } } @@ -111,10 +127,15 @@ where Extension::bare_post_dispatch(info, &mut post_info, len, &pd_res)?; Ok(res) }, - ExtrinsicFormat::Signed(signer, extension) => - extension.dispatch_transaction(Some(signer).into(), self.function, info, len), - ExtrinsicFormat::General(extension) => - extension.dispatch_transaction(None.into(), self.function, info, len), + ExtrinsicFormat::Signed(signer, extension) => extension.dispatch_transaction( + Some(signer).into(), + self.function, + info, + len, + DEFAULT_EXTENSION_VERSION, + ), + ExtrinsicFormat::General(extension_version, extension) => extension + .dispatch_transaction(None.into(), self.function, info, len, extension_version), } } } @@ -127,7 +148,7 @@ impl> pub fn extension_weight(&self) -> Weight { match &self.format { ExtrinsicFormat::Bare => Weight::zero(), - ExtrinsicFormat::Signed(_, ext) | ExtrinsicFormat::General(ext) => + ExtrinsicFormat::Signed(_, ext) | ExtrinsicFormat::General(_, ext) => ext.weight(&self.function), } } diff --git a/substrate/primitives/runtime/src/generic/digest.rs b/substrate/primitives/runtime/src/generic/digest.rs index c639576a2867..5ed0c7075cae 100644 --- a/substrate/primitives/runtime/src/generic/digest.rs +++ b/substrate/primitives/runtime/src/generic/digest.rs @@ -20,6 +20,7 @@ #[cfg(all(not(feature = "std"), feature = "serde"))] use alloc::format; use alloc::vec::Vec; +use codec::DecodeAll; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -256,8 +257,7 @@ impl DigestItem { self.dref().try_as_raw(id) } - /// Returns the data contained in the item if `Some` if this entry has the id given, decoded - /// to the type provided `T`. + /// Returns the data decoded as `T`, if the `id` is matching. pub fn try_to(&self, id: OpaqueDigestItemId) -> Option { self.dref().try_to::(id) } @@ -367,17 +367,16 @@ impl<'a> DigestItemRef<'a> { /// Try to match this digest item to the given opaque item identifier; if it matches, then /// try to cast to the given data type; if that works, return it. pub fn try_to(&self, id: OpaqueDigestItemId) -> Option { - self.try_as_raw(id).and_then(|mut x| Decode::decode(&mut x).ok()) + self.try_as_raw(id).and_then(|mut x| DecodeAll::decode_all(&mut x).ok()) } /// Try to match this to a `Self::Seal`, check `id` matches and decode it. /// /// Returns `None` if this isn't a seal item, the `id` doesn't match or when the decoding fails. pub fn seal_try_to(&self, id: &ConsensusEngineId) -> Option { - match self { - Self::Seal(v, s) if *v == id => Decode::decode(&mut &s[..]).ok(), - _ => None, - } + self.as_seal() + .filter(|s| s.0 == *id) + .and_then(|mut d| DecodeAll::decode_all(&mut d.1).ok()) } /// Try to match this to a `Self::Consensus`, check `id` matches and decode it. @@ -385,10 +384,9 @@ impl<'a> DigestItemRef<'a> { /// Returns `None` if this isn't a consensus item, the `id` doesn't match or /// when the decoding fails. pub fn consensus_try_to(&self, id: &ConsensusEngineId) -> Option { - match self { - Self::Consensus(v, s) if *v == id => Decode::decode(&mut &s[..]).ok(), - _ => None, - } + self.as_consensus() + .filter(|s| s.0 == *id) + .and_then(|mut d| DecodeAll::decode_all(&mut d.1).ok()) } /// Try to match this to a `Self::PreRuntime`, check `id` matches and decode it. @@ -396,40 +394,21 @@ impl<'a> DigestItemRef<'a> { /// Returns `None` if this isn't a pre-runtime item, the `id` doesn't match or /// when the decoding fails. pub fn pre_runtime_try_to(&self, id: &ConsensusEngineId) -> Option { - match self { - Self::PreRuntime(v, s) if *v == id => Decode::decode(&mut &s[..]).ok(), - _ => None, - } + self.as_pre_runtime() + .filter(|s| s.0 == *id) + .and_then(|mut d| DecodeAll::decode_all(&mut d.1).ok()) } } impl<'a> Encode for DigestItemRef<'a> { fn encode(&self) -> Vec { - let mut v = Vec::new(); - match *self { - Self::Consensus(val, data) => { - DigestItemType::Consensus.encode_to(&mut v); - (val, data).encode_to(&mut v); - }, - Self::Seal(val, sig) => { - DigestItemType::Seal.encode_to(&mut v); - (val, sig).encode_to(&mut v); - }, - Self::PreRuntime(val, data) => { - DigestItemType::PreRuntime.encode_to(&mut v); - (val, data).encode_to(&mut v); - }, - Self::Other(val) => { - DigestItemType::Other.encode_to(&mut v); - val.encode_to(&mut v); - }, - Self::RuntimeEnvironmentUpdated => { - DigestItemType::RuntimeEnvironmentUpdated.encode_to(&mut v); - }, + Self::Consensus(val, data) => (DigestItemType::Consensus, val, data).encode(), + Self::Seal(val, sig) => (DigestItemType::Seal, val, sig).encode(), + Self::PreRuntime(val, data) => (DigestItemType::PreRuntime, val, data).encode(), + Self::Other(val) => (DigestItemType::Other, val).encode(), + Self::RuntimeEnvironmentUpdated => DigestItemType::RuntimeEnvironmentUpdated.encode(), } - - v } } diff --git a/substrate/primitives/runtime/src/generic/mod.rs b/substrate/primitives/runtime/src/generic/mod.rs index 007dee2684b0..f79058e270ed 100644 --- a/substrate/primitives/runtime/src/generic/mod.rs +++ b/substrate/primitives/runtime/src/generic/mod.rs @@ -33,6 +33,8 @@ pub use self::{ digest::{Digest, DigestItem, DigestItemRef, OpaqueDigestItemId}, era::{Era, Phase}, header::Header, - unchecked_extrinsic::{Preamble, SignedPayload, UncheckedExtrinsic, EXTRINSIC_FORMAT_VERSION}, + unchecked_extrinsic::{ + ExtensionVersion, Preamble, SignedPayload, UncheckedExtrinsic, EXTRINSIC_FORMAT_VERSION, + }, }; pub use unchecked_extrinsic::UncheckedSignaturePayload; diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 8c44e147f90b..d8510a60a789 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -83,7 +83,7 @@ pub enum Preamble { Bare(ExtrinsicVersion), /// An old-school transaction extrinsic which includes a signature of some hard-coded crypto. /// Available only on extrinsic version 4. - Signed(Address, Signature, ExtensionVersion, Extension), + Signed(Address, Signature, Extension), /// A new-school transaction extrinsic which does not include a signature by default. The /// origin authorization, through signatures or other means, is performed by the transaction /// extension in this extrinsic. Available starting with extrinsic version 5. @@ -117,7 +117,7 @@ where let address = Address::decode(input)?; let signature = Signature::decode(input)?; let ext = Extension::decode(input)?; - Self::Signed(address, signature, 0, ext) + Self::Signed(address, signature, ext) }, (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { let ext_version = ExtensionVersion::decode(input)?; @@ -140,7 +140,7 @@ where fn size_hint(&self) -> usize { match &self { Preamble::Bare(_) => EXTRINSIC_FORMAT_VERSION.size_hint(), - Preamble::Signed(address, signature, _, ext) => LEGACY_EXTRINSIC_FORMAT_VERSION + Preamble::Signed(address, signature, ext) => LEGACY_EXTRINSIC_FORMAT_VERSION .size_hint() .saturating_add(address.size_hint()) .saturating_add(signature.size_hint()) @@ -157,7 +157,7 @@ where Preamble::Bare(extrinsic_version) => { (extrinsic_version | BARE_EXTRINSIC).encode_to(dest); }, - Preamble::Signed(address, signature, _, ext) => { + Preamble::Signed(address, signature, ext) => { (LEGACY_EXTRINSIC_FORMAT_VERSION | SIGNED_EXTRINSIC).encode_to(dest); address.encode_to(dest); signature.encode_to(dest); @@ -176,7 +176,7 @@ impl Preamble { /// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields. pub fn to_signed(self) -> Option<(Address, Signature, Extension)> { match self { - Self::Signed(a, s, _, e) => Some((a, s, e)), + Self::Signed(a, s, e) => Some((a, s, e)), _ => None, } } @@ -190,8 +190,7 @@ where fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Bare(_) => write!(f, "Bare"), - Self::Signed(address, _, ext_version, tx_ext) => - write!(f, "Signed({:?}, {:?}, {:?})", address, ext_version, tx_ext), + Self::Signed(address, _, tx_ext) => write!(f, "Signed({:?}, {:?})", address, tx_ext), Self::General(ext_version, tx_ext) => write!(f, "General({:?}, {:?})", ext_version, tx_ext), } @@ -305,7 +304,7 @@ impl UncheckedExtrinsic Self { - Self { preamble: Preamble::Signed(signed, signature, 0, tx_ext), function } + Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } } /// New instance of an new-school unsigned transaction. @@ -345,7 +344,7 @@ where fn check(self, lookup: &Lookup) -> Result { Ok(match self.preamble { - Preamble::Signed(signed, signature, _, tx_ext) => { + Preamble::Signed(signed, signature, tx_ext) => { let signed = lookup.lookup(signed)?; // The `Implicit` is "implicitly" included in the payload. let raw_payload = SignedPayload::new(self.function, tx_ext)?; @@ -355,8 +354,8 @@ where let (function, tx_ext, _) = raw_payload.deconstruct(); CheckedExtrinsic { format: ExtrinsicFormat::Signed(signed, tx_ext), function } }, - Preamble::General(_, tx_ext) => CheckedExtrinsic { - format: ExtrinsicFormat::General(tx_ext), + Preamble::General(extension_version, tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(extension_version, tx_ext), function: self.function, }, Preamble::Bare(_) => @@ -370,15 +369,15 @@ where lookup: &Lookup, ) -> Result { Ok(match self.preamble { - Preamble::Signed(signed, _, _, extra) => { + Preamble::Signed(signed, _, tx_ext) => { let signed = lookup.lookup(signed)?; CheckedExtrinsic { - format: ExtrinsicFormat::Signed(signed, extra), + format: ExtrinsicFormat::Signed(signed, tx_ext), function: self.function, } }, - Preamble::General(_, extra) => CheckedExtrinsic { - format: ExtrinsicFormat::General(extra), + Preamble::General(extension_version, tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(extension_version, tx_ext), function: self.function, }, Preamble::Bare(_) => @@ -390,8 +389,7 @@ where impl> ExtrinsicMetadata for UncheckedExtrinsic { - // TODO: Expose both version 4 and version 5 in metadata v16. - const VERSION: u8 = LEGACY_EXTRINSIC_FORMAT_VERSION; + const VERSIONS: &'static [u8] = &[LEGACY_EXTRINSIC_FORMAT_VERSION, EXTRINSIC_FORMAT_VERSION]; type TransactionExtensions = Extension; } @@ -403,8 +401,7 @@ impl Weight { match &self.preamble { Preamble::Bare(_) => Weight::zero(), - Preamble::Signed(_, _, _, ext) | Preamble::General(_, ext) => - ext.weight(&self.function), + Preamble::Signed(_, _, ext) | Preamble::General(_, ext) => ext.weight(&self.function), } } } @@ -839,7 +836,7 @@ mod tests { assert_eq!( >::check(ux, &Default::default()), Ok(CEx { - format: ExtrinsicFormat::General(DummyExtension), + format: ExtrinsicFormat::General(0, DummyExtension), function: vec![0u8; 0].into() }), ); @@ -915,7 +912,7 @@ mod tests { assert_eq!(decoded_old_ux.function, call); assert_eq!( decoded_old_ux.preamble, - Preamble::Signed(signed, legacy_signature.clone(), 0, extension.clone()) + Preamble::Signed(signed, legacy_signature.clone(), extension.clone()) ); let new_ux = @@ -952,7 +949,7 @@ mod tests { assert_eq!(decoded_old_ux.function, call); assert_eq!( decoded_old_ux.preamble, - Preamble::Signed(signed, signature.clone(), 0, extension.clone()) + Preamble::Signed(signed, signature.clone(), extension.clone()) ); let new_ux = Ex::new_signed(call.clone(), signed, signature.clone(), extension.clone()); diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index 6eed57656a6d..f0c8e50f1ba1 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -49,7 +49,7 @@ extern crate alloc; #[doc(hidden)] -pub use alloc::{format, vec::Vec}; +pub use alloc::vec::Vec; #[doc(hidden)] pub use codec; #[doc(hidden)] @@ -90,15 +90,12 @@ mod multiaddress; pub mod offchain; pub mod proving_trie; pub mod runtime_logger; -mod runtime_string; #[cfg(feature = "std")] pub mod testing; pub mod traits; pub mod transaction_validity; pub mod type_with_default; -pub use crate::runtime_string::*; - // Re-export Multiaddress pub use multiaddress::MultiAddress; @@ -953,7 +950,7 @@ impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic { { let r = ::sp_core::bytes::deserialize(de)?; Decode::decode(&mut &r[..]) - .map_err(|e| ::serde::de::Error::custom(format!("Decode error: {}", e))) + .map_err(|e| ::serde::de::Error::custom(alloc::format!("Decode error: {}", e))) } } @@ -1037,6 +1034,23 @@ impl OpaqueValue { } } +// TODO: Remove in future versions and clean up `parse_str_literal` in `sp-version-proc-macro` +/// Deprecated `Cow::Borrowed()` wrapper. +#[macro_export] +#[deprecated = "Use Cow::Borrowed() instead of create_runtime_str!()"] +macro_rules! create_runtime_str { + ( $y:expr ) => {{ + $crate::Cow::Borrowed($y) + }}; +} +// TODO: Re-export for ^ macro `create_runtime_str`, should be removed once macro is gone +#[doc(hidden)] +pub use alloc::borrow::Cow; +// TODO: Remove in future versions +/// Deprecated alias to improve upgrade experience +#[deprecated = "Use String or Cow<'static, str> instead"] +pub type RuntimeString = alloc::string::String; + #[cfg(test)] mod tests { use crate::traits::BlakeTwo256; diff --git a/substrate/primitives/runtime/src/runtime_string.rs b/substrate/primitives/runtime/src/runtime_string.rs deleted file mode 100644 index bb0347badcbb..000000000000 --- a/substrate/primitives/runtime/src/runtime_string.rs +++ /dev/null @@ -1,168 +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. - -use alloc::vec::Vec; -use codec::{Decode, Encode}; -use sp_core::RuntimeDebug; - -/// A string that wraps a `&'static str` in the runtime and `String`/`Vec` on decode. -#[derive(Eq, RuntimeDebug, Clone)] -pub enum RuntimeString { - /// The borrowed mode that wraps a `&'static str`. - Borrowed(&'static str), - /// The owned mode that wraps a `String`. - #[cfg(feature = "std")] - Owned(String), - /// The owned mode that wraps a `Vec`. - #[cfg(not(feature = "std"))] - Owned(Vec), -} - -impl scale_info::TypeInfo for RuntimeString { - type Identity = str; - - fn type_info() -> scale_info::Type { - Self::Identity::type_info() - } -} - -/// Convenience macro to use the format! interface to get a `RuntimeString::Owned` -#[macro_export] -macro_rules! format_runtime_string { - ($($args:tt)*) => {{ - #[cfg(feature = "std")] - { - sp_runtime::RuntimeString::Owned(format!($($args)*)) - } - #[cfg(not(feature = "std"))] - { - sp_runtime::RuntimeString::Owned($crate::format!($($args)*).as_bytes().to_vec()) - } - }}; -} - -impl From<&'static str> for RuntimeString { - fn from(data: &'static str) -> Self { - Self::Borrowed(data) - } -} - -impl<'a> TryFrom<&'a RuntimeString> for &'a str { - type Error = core::str::Utf8Error; - fn try_from(from: &'a RuntimeString) -> core::result::Result<&'a str, Self::Error> { - match from { - #[cfg(feature = "std")] - RuntimeString::Owned(string) => Ok(string.as_str()), - #[cfg(not(feature = "std"))] - RuntimeString::Owned(vec) => core::str::from_utf8(&vec), - RuntimeString::Borrowed(str) => Ok(str), - } - } -} - -#[cfg(feature = "std")] -impl From for String { - fn from(string: RuntimeString) -> Self { - match string { - RuntimeString::Borrowed(data) => data.to_owned(), - RuntimeString::Owned(data) => data, - } - } -} - -impl Default for RuntimeString { - fn default() -> Self { - Self::Borrowed(Default::default()) - } -} - -impl PartialEq for RuntimeString { - fn eq(&self, other: &Self) -> bool { - self.as_ref() == other.as_ref() - } -} - -impl AsRef<[u8]> for RuntimeString { - fn as_ref(&self) -> &[u8] { - match self { - Self::Borrowed(val) => val.as_ref(), - Self::Owned(val) => val.as_ref(), - } - } -} - -#[cfg(feature = "std")] -impl std::ops::Deref for RuntimeString { - type Target = str; - - fn deref(&self) -> &str { - match self { - Self::Borrowed(val) => val, - Self::Owned(val) => val, - } - } -} - -impl Encode for RuntimeString { - fn encode(&self) -> Vec { - match self { - Self::Borrowed(val) => val.encode(), - Self::Owned(val) => val.encode(), - } - } -} - -impl Decode for RuntimeString { - fn decode(value: &mut I) -> Result { - Decode::decode(value).map(Self::Owned) - } -} - -#[cfg(feature = "std")] -impl std::fmt::Display for RuntimeString { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::Borrowed(val) => write!(f, "{}", val), - Self::Owned(val) => write!(f, "{}", val), - } - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for RuntimeString { - fn serialize(&self, serializer: S) -> Result { - match self { - Self::Borrowed(val) => val.serialize(serializer), - Self::Owned(val) => val.serialize(serializer), - } - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for RuntimeString { - fn deserialize>(de: D) -> Result { - Ok(Self::Owned(serde::Deserialize::deserialize(de)?)) - } -} - -/// Create a const [`RuntimeString`]. -#[macro_export] -macro_rules! create_runtime_str { - ( $y:expr ) => {{ - $crate::RuntimeString::Borrowed($y) - }}; -} diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index e6906cdb3877..cfcc3e5a354d 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -44,8 +44,9 @@ pub use sp_arithmetic::traits::{ use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, TypeId, U256}; #[doc(hidden)] pub use sp_core::{ - parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, - ConstU16, ConstU32, ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, + parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstInt, + ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, ConstUint, Get, GetDefault, TryCollect, + TypedGet, }; #[cfg(feature = "std")] use std::fmt::Display; @@ -1409,10 +1410,10 @@ impl SignaturePayload for () { /// Implementor is an [`Extrinsic`] and provides metadata about this extrinsic. pub trait ExtrinsicMetadata { - /// The format version of the `Extrinsic`. + /// The format versions of the `Extrinsic`. /// - /// By format is meant the encoded representation of the `Extrinsic`. - const VERSION: u8; + /// By format we mean the encoded representation of the `Extrinsic`. + const VERSIONS: &'static [u8]; /// Transaction extensions attached to this `Extrinsic`. type TransactionExtensions; @@ -2348,7 +2349,8 @@ pub trait BlockNumberProvider { + TypeInfo + Debug + MaxEncodedLen - + Copy; + + Copy + + EncodeLike; /// Returns the current block number. /// diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs b/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs index a5179748673f..282064078fe3 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs @@ -25,7 +25,7 @@ use sp_core::RuntimeDebug; use crate::{ traits::{AsSystemOriginSigner, SignedExtension, ValidateResult}, - transaction_validity::InvalidTransaction, + transaction_validity::{InvalidTransaction, TransactionSource}, }; use super::*; @@ -74,6 +74,7 @@ where len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> ValidateResult { let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; let r = self.0.validate(who, call, info, len)?; diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs index e2fb556bf9d3..28030d12fc9f 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs @@ -17,7 +17,11 @@ //! The [DispatchTransaction] trait. -use crate::{traits::AsTransactionAuthorizedOrigin, transaction_validity::InvalidTransaction}; +use crate::{ + generic::ExtensionVersion, + traits::AsTransactionAuthorizedOrigin, + transaction_validity::{InvalidTransaction, TransactionSource}, +}; use super::*; @@ -45,6 +49,8 @@ pub trait DispatchTransaction { call: &Call, info: &Self::Info, len: usize, + source: TransactionSource, + extension_version: ExtensionVersion, ) -> Result<(ValidTransaction, Self::Val, Self::Origin), TransactionValidityError>; /// Validate and prepare a transaction, ready for dispatch. fn validate_and_prepare( @@ -53,6 +59,7 @@ pub trait DispatchTransaction { call: &Call, info: &Self::Info, len: usize, + extension_version: ExtensionVersion, ) -> Result<(Self::Pre, Self::Origin), TransactionValidityError>; /// Dispatch a transaction with the given base origin and call. fn dispatch_transaction( @@ -61,6 +68,7 @@ pub trait DispatchTransaction { call: Call, info: &Self::Info, len: usize, + extension_version: ExtensionVersion, ) -> Self::Result; /// Do everything which would be done in a [dispatch_transaction](Self::dispatch_transaction), /// but instead of executing the call, execute `substitute` instead. Since this doesn't actually @@ -71,6 +79,7 @@ pub trait DispatchTransaction { call: &Call, info: &Self::Info, len: usize, + extension_version: ExtensionVersion, substitute: impl FnOnce( Self::Origin, ) -> crate::DispatchResultWithInfo<::PostInfo>, @@ -93,8 +102,18 @@ where call: &Call, info: &DispatchInfoOf, len: usize, + source: TransactionSource, + extension_version: ExtensionVersion, ) -> Result<(ValidTransaction, T::Val, Self::Origin), TransactionValidityError> { - match self.validate(origin, call, info, len, self.implicit()?, call) { + match self.validate( + origin, + call, + info, + len, + self.implicit()?, + &(extension_version, call), + source, + ) { // After validation, some origin must have been authorized. Ok((_, _, origin)) if !origin.is_transaction_authorized() => Err(InvalidTransaction::UnknownOrigin.into()), @@ -107,8 +126,16 @@ where call: &Call, info: &DispatchInfoOf, len: usize, + extension_version: ExtensionVersion, ) -> Result<(T::Pre, Self::Origin), TransactionValidityError> { - let (_, val, origin) = self.validate_only(origin, call, info, len)?; + let (_, val, origin) = self.validate_only( + origin, + call, + info, + len, + TransactionSource::InBlock, + extension_version, + )?; let pre = self.prepare(val, &origin, &call, info, len)?; Ok((pre, origin)) } @@ -118,8 +145,10 @@ where call: Call, info: &DispatchInfoOf, len: usize, + extension_version: ExtensionVersion, ) -> Self::Result { - let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?; + let (pre, origin) = + self.validate_and_prepare(origin, &call, info, len, extension_version)?; let mut res = call.dispatch(origin); let pd_res = res.map(|_| ()).map_err(|e| e.error); let post_info = match &mut res { @@ -136,11 +165,13 @@ where call: &Call, info: &Self::Info, len: usize, + extension_version: ExtensionVersion, substitute: impl FnOnce( Self::Origin, ) -> crate::DispatchResultWithInfo<::PostInfo>, ) -> Self::Result { - let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?; + let (pre, origin) = + self.validate_and_prepare(origin, &call, info, len, extension_version)?; let mut res = substitute(origin); let pd_res = res.map(|_| ()).map_err(|e| e.error); let post_info = match &mut res { diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 58cd0974661a..f8c5dc6a724e 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -19,7 +19,9 @@ use crate::{ scale_info::{MetaType, StaticTypeInfo}, - transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction}, + transaction_validity::{ + TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, + }, DispatchResult, }; use codec::{Codec, Decode, Encode}; @@ -243,6 +245,7 @@ pub trait TransactionExtension: len: usize, self_implicit: Self::Implicit, inherited_implication: &impl Encode, + source: TransactionSource, ) -> ValidateResult; /// Do any pre-flight stuff for a transaction after validation. @@ -429,6 +432,7 @@ macro_rules! impl_tx_ext_default { _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl $crate::codec::Encode, + _source: $crate::transaction_validity::TransactionSource, ) -> $crate::traits::ValidateResult { Ok((Default::default(), Default::default(), origin)) } @@ -496,6 +500,7 @@ impl TransactionExtension for Tuple { len: usize, self_implicit: Self::Implicit, inherited_implication: &impl Encode, + source: TransactionSource, ) -> Result< (ValidTransaction, Self::Val, ::RuntimeOrigin), TransactionValidityError, @@ -521,7 +526,7 @@ impl TransactionExtension for Tuple { // passed into the next items in this pipeline-tuple. &following_implicit_implications, ); - Tuple.validate(origin, call, info, len, item_implicit, &implications)? + Tuple.validate(origin, call, info, len, item_implicit, &implications, source)? }; let valid = valid.combine_with(item_valid); let val = val.push_back(item_val); @@ -616,6 +621,7 @@ impl TransactionExtension for () { _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> Result< (ValidTransaction, (), ::RuntimeOrigin), TransactionValidityError, diff --git a/substrate/primitives/runtime/src/type_with_default.rs b/substrate/primitives/runtime/src/type_with_default.rs index 1465393640dc..b0eca22e5c1a 100644 --- a/substrate/primitives/runtime/src/type_with_default.rs +++ b/substrate/primitives/runtime/src/type_with_default.rs @@ -31,7 +31,7 @@ use num_traits::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, Num, NumCast, PrimInt, Saturating, ToPrimitive, }; -use scale_info::TypeInfo; +use scale_info::{StaticTypeInfo, TypeInfo}; use sp_core::Get; #[cfg(feature = "serde")] @@ -40,7 +40,8 @@ use serde::{Deserialize, Serialize}; /// A type that wraps another type and provides a default value. /// /// Passes through arithmetical and many other operations to the inner value. -#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen)] +/// Type information for metadata is the same as the inner value's type. +#[derive(Encode, Decode, Debug, MaxEncodedLen)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TypeWithDefault>(T, PhantomData); @@ -50,6 +51,17 @@ impl> TypeWithDefault { } } +// Hides implementation details from the outside (for metadata type information). +// +// The type info showed in metadata is the one of the inner value's type. +impl + 'static> TypeInfo for TypeWithDefault { + type Identity = Self; + + fn type_info() -> scale_info::Type { + T::type_info() + } +} + impl> Clone for TypeWithDefault { fn clone(&self) -> Self { Self(self.0.clone(), PhantomData) @@ -91,24 +103,6 @@ impl> Default for TypeWithDefault { } } -impl, D: Get> From for TypeWithDefault { - fn from(value: u16) -> Self { - Self::new(value.into()) - } -} - -impl, D: Get> From for TypeWithDefault { - fn from(value: u32) -> Self { - Self::new(value.into()) - } -} - -impl, D: Get> From for TypeWithDefault { - fn from(value: u64) -> Self { - Self::new(value.into()) - } -} - impl> CheckedNeg for TypeWithDefault { fn checked_neg(&self) -> Option { self.0.checked_neg().map(Self::new) @@ -205,24 +199,45 @@ impl> AddAssign for TypeWithDefault { } } -impl, D: Get> From for TypeWithDefault { - fn from(value: u8) -> Self { - Self::new(value.into()) - } -} - impl> Display for TypeWithDefault { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}", self.0) } } -impl, D: Get> TryFrom for TypeWithDefault { - type Error = >::Error; - fn try_from(n: u128) -> Result, Self::Error> { - T::try_from(n).map(Self::new) - } -} +macro_rules! impl_from { + ($for_type:ty $(, $from_type:ty)*) => { + $( + impl> From<$from_type> for TypeWithDefault<$for_type, D> { + fn from(value: $from_type) -> Self { + Self::new(value.into()) + } + } + )* + } +} +impl_from!(u128, u128, u64, u32, u16, u8); +impl_from!(u64, u64, u32, u16, u8); +impl_from!(u32, u32, u16, u8); +impl_from!(u16, u16, u8); +impl_from!(u8, u8); + +macro_rules! impl_try_from { + ($for_type:ty $(, $try_from_type:ty)*) => { + $( + impl> TryFrom<$try_from_type> for TypeWithDefault<$for_type, D> { + type Error = <$for_type as TryFrom<$try_from_type>>::Error; + fn try_from(n: $try_from_type) -> Result, Self::Error> { + <$for_type as TryFrom<$try_from_type>>::try_from(n).map(Self::new) + } + } + )* + } +} +impl_try_from!(u8, u16, u32, u64, u128); +impl_try_from!(u16, u32, u64, u128); +impl_try_from!(u32, u64, u128); +impl_try_from!(u64, u128); impl, D: Get> TryFrom for TypeWithDefault { type Error = >::Error; @@ -504,3 +519,70 @@ impl> CompactAs for TypeWithDefault { Ok(Self::new(val)) } } + +#[cfg(test)] +mod tests { + use super::TypeWithDefault; + use scale_info::TypeInfo; + use sp_arithmetic::traits::{AtLeast16Bit, AtLeast32Bit, AtLeast8Bit}; + use sp_core::Get; + + #[test] + #[allow(dead_code)] + fn test_type_with_default_impl_base_arithmetic() { + trait WrapAtLeast8Bit: AtLeast8Bit {} + trait WrapAtLeast16Bit: AtLeast16Bit {} + trait WrapAtLeast32Bit: AtLeast32Bit {} + + struct Getu8; + impl Get for Getu8 { + fn get() -> u8 { + 0 + } + } + type U8WithDefault = TypeWithDefault; + impl WrapAtLeast8Bit for U8WithDefault {} + + struct Getu16; + impl Get for Getu16 { + fn get() -> u16 { + 0 + } + } + type U16WithDefault = TypeWithDefault; + impl WrapAtLeast16Bit for U16WithDefault {} + + struct Getu32; + impl Get for Getu32 { + fn get() -> u32 { + 0 + } + } + type U32WithDefault = TypeWithDefault; + impl WrapAtLeast32Bit for U32WithDefault {} + + struct Getu64; + impl Get for Getu64 { + fn get() -> u64 { + 0 + } + } + type U64WithDefault = TypeWithDefault; + impl WrapAtLeast32Bit for U64WithDefault {} + + struct Getu128; + impl Get for Getu128 { + fn get() -> u128 { + 0 + } + } + type U128WithDefault = TypeWithDefault; + impl WrapAtLeast32Bit for U128WithDefault {} + + assert_eq!(U8WithDefault::type_info(), ::type_info()); + assert_eq!(U16WithDefault::type_info(), ::type_info()); + assert_eq!(U32WithDefault::type_info(), ::type_info()); + assert_eq!(U64WithDefault::type_info(), ::type_info()); + assert_eq!(U128WithDefault::type_info(), ::type_info()); + } +} diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index 6abf83505530..72be81c1222e 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -20,9 +20,9 @@ codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } sp-api = { workspace = true } sp-core = { workspace = true } +sp-keystore = { optional = true, workspace = true } sp-runtime = { optional = true, workspace = true } sp-staking = { workspace = true } -sp-keystore = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 35e7e4f60413..42694cdbb674 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -16,10 +16,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -serde = { features = ["alloc", "derive"], optional = true, workspace = true } codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } impl-trait-for-tuples = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } diff --git a/substrate/primitives/staking/src/offence.rs b/substrate/primitives/staking/src/offence.rs index 2c2ebc1fc971..e73e8efe5839 100644 --- a/substrate/primitives/staking/src/offence.rs +++ b/substrate/primitives/staking/src/offence.rs @@ -242,3 +242,28 @@ impl OffenceReportSystem for () { Ok(()) } } + +/// Wrapper type representing the severity of an offence. +/// +/// As of now the only meaningful value taken into account +/// when deciding the severity of an offence is the associated +/// slash amount `Perbill`. +/// +/// For instance used for the purposes of distinguishing who should be +/// prioritized for disablement. +#[derive( + Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo, +)] +pub struct OffenceSeverity(pub Perbill); + +impl PartialOrd for OffenceSeverity { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for OffenceSeverity { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index e1c67feb7ac5..5bc06b8cb509 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -17,28 +17,28 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +arbitrary = { features = ["derive"], optional = true, workspace = true } codec = { workspace = true } hash-db = { workspace = true } log = { workspace = true } parking_lot = { optional = true, workspace = true, default-features = true } rand = { optional = true, workspace = true, default-features = true } smallvec = { workspace = true, default-features = true } -thiserror = { optional = true, workspace = true } -tracing = { optional = true, workspace = true, default-features = true } sp-core = { workspace = true } sp-externalities = { workspace = true } sp-panic-handler = { optional = true, workspace = true, default-features = true } sp-trie = { workspace = true } +thiserror = { optional = true, workspace = true } +tracing = { optional = true, workspace = true, default-features = true } trie-db = { workspace = true } -arbitrary = { features = ["derive"], optional = true, workspace = true } [dev-dependencies] +arbitrary = { features = ["derive"], workspace = true } array-bytes = { workspace = true, default-features = true } +assert_matches = { workspace = true } pretty_assertions = { workspace = true } rand = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -assert_matches = { workspace = true } -arbitrary = { features = ["derive"], workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/state-machine/fuzz/Cargo.toml b/substrate/primitives/state-machine/fuzz/Cargo.toml index 416c00c34fda..16bf5b92025f 100644 --- a/substrate/primitives/state-machine/fuzz/Cargo.toml +++ b/substrate/primitives/state-machine/fuzz/Cargo.toml @@ -13,8 +13,8 @@ libfuzzer-sys = "0.4" sp-runtime = { path = "../../runtime" } [dependencies.sp-state-machine] -path = ".." features = ["fuzzing"] +path = ".." # Prevent this from interfering with workspaces [workspace] diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index f91ce5d2e52f..8d4dfd34240d 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -73,7 +73,10 @@ pub trait TrieCacheProvider { #[cfg(feature = "std")] impl TrieCacheProvider for LocalTrieCache { - type Cache<'a> = TrieCache<'a, H> where H: 'a; + type Cache<'a> + = TrieCache<'a, H> + where + H: 'a; fn as_trie_db_cache(&self, storage_root: H::Out) -> Self::Cache<'_> { self.as_trie_db_cache(storage_root) @@ -90,7 +93,10 @@ impl TrieCacheProvider for LocalTrieCache { #[cfg(feature = "std")] impl TrieCacheProvider for &LocalTrieCache { - type Cache<'a> = TrieCache<'a, H> where Self: 'a; + type Cache<'a> + = TrieCache<'a, H> + where + Self: 'a; fn as_trie_db_cache(&self, storage_root: H::Out) -> Self::Cache<'_> { (*self).as_trie_db_cache(storage_root) @@ -139,7 +145,10 @@ impl trie_db::TrieCache> for UnimplementedCacheProvider< #[cfg(not(feature = "std"))] impl TrieCacheProvider for UnimplementedCacheProvider { - type Cache<'a> = UnimplementedCacheProvider where H: 'a; + type Cache<'a> + = UnimplementedCacheProvider + where + H: 'a; fn as_trie_db_cache(&self, _storage_root: ::Out) -> Self::Cache<'_> { unimplemented!() @@ -176,7 +185,10 @@ impl trie_db::TrieRecorder for UnimplementedRecorderProvider< #[cfg(not(feature = "std"))] impl TrieRecorderProvider for UnimplementedRecorderProvider { - type Recorder<'a> = UnimplementedRecorderProvider where H: 'a; + type Recorder<'a> + = UnimplementedRecorderProvider + where + H: 'a; fn drain_storage_proof(self) -> Option { unimplemented!() diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index aac676caedc9..df66cfcfc2e6 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -18,23 +18,23 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +sp-api = { workspace = true } +sp-application-crypto = { workspace = true } sp-core = { workspace = true } sp-crypto-hashing = { workspace = true } +sp-externalities = { workspace = true } sp-runtime = { workspace = true } -sp-api = { workspace = true } -sp-application-crypto = { workspace = true } sp-runtime-interface = { workspace = true } -sp-externalities = { workspace = true } thiserror = { optional = true, workspace = true } # ECIES dependencies -ed25519-dalek = { optional = true, workspace = true, default-features = true } -x25519-dalek = { optional = true, features = ["static_secrets"], workspace = true } -curve25519-dalek = { optional = true, workspace = true } aes-gcm = { optional = true, workspace = true } +curve25519-dalek = { optional = true, workspace = true } +ed25519-dalek = { optional = true, workspace = true, default-features = true } hkdf = { optional = true, workspace = true } -sha2 = { optional = true, workspace = true, default-features = true } rand = { features = ["small_rng"], optional = true, workspace = true, default-features = true } +sha2 = { optional = true, workspace = true, default-features = true } +x25519-dalek = { optional = true, features = ["static_secrets"], workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 0fcd5be98e6f..619f1eaa142b 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -18,9 +18,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { optional = true, workspace = true } codec = { features = ["derive"], workspace = true } -thiserror = { optional = true, workspace = true } sp-inherents = { workspace = true } sp-runtime = { workspace = true } +thiserror = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 7f27bb097290..65a9727ed2ae 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -29,20 +29,20 @@ nohash-hasher = { optional = true, workspace = true } parking_lot = { optional = true, workspace = true, default-features = true } rand = { optional = true, workspace = true, default-features = true } scale-info = { features = ["derive"], workspace = true } +schnellru = { optional = true, workspace = true } +sp-core = { workspace = true } +sp-externalities = { workspace = true } thiserror = { optional = true, workspace = true } tracing = { optional = true, workspace = true, default-features = true } trie-db = { workspace = true } trie-root = { workspace = true } -sp-core = { workspace = true } -sp-externalities = { workspace = true } -schnellru = { optional = true, workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } criterion = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } trie-bench = { workspace = true } trie-standardmap = { workspace = true } -sp-runtime = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/primitives/trie/src/node_codec.rs b/substrate/primitives/trie/src/node_codec.rs index 78896988ec4c..400f57f3b1bf 100644 --- a/substrate/primitives/trie/src/node_codec.rs +++ b/substrate/primitives/trie/src/node_codec.rs @@ -110,6 +110,10 @@ where NodeHeader::Null => Ok(NodePlan::Empty), NodeHeader::HashedValueBranch(nibble_count) | NodeHeader::Branch(_, nibble_count) => { let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0; + // data should be at least of size offset + 1 + if data.len() < input.offset + 1 { + return Err(Error::BadFormat) + } // check that the padding is valid (if any) if padding && nibble_ops::pad_left(data[input.offset]) != 0 { return Err(Error::BadFormat) @@ -154,6 +158,10 @@ where }, NodeHeader::HashedValueLeaf(nibble_count) | NodeHeader::Leaf(nibble_count) => { let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0; + // data should be at least of size offset + 1 + if data.len() < input.offset + 1 { + return Err(Error::BadFormat) + } // check that the padding is valid (if any) if padding && nibble_ops::pad_left(data[input.offset]) != 0 { return Err(Error::BadFormat) diff --git a/substrate/primitives/trie/src/recorder.rs b/substrate/primitives/trie/src/recorder.rs index 2886577eddc6..4ec13066ded7 100644 --- a/substrate/primitives/trie/src/recorder.rs +++ b/substrate/primitives/trie/src/recorder.rs @@ -252,7 +252,10 @@ pub struct TrieRecorder<'a, H: Hasher> { } impl crate::TrieRecorderProvider for Recorder { - type Recorder<'a> = TrieRecorder<'a, H> where H: 'a; + type Recorder<'a> + = TrieRecorder<'a, H> + where + H: 'a; fn drain_storage_proof(self) -> Option { Some(Recorder::drain_storage_proof(self)) diff --git a/substrate/primitives/trie/src/storage_proof.rs b/substrate/primitives/trie/src/storage_proof.rs index a9f6298742f6..bf0dc72e650b 100644 --- a/substrate/primitives/trie/src/storage_proof.rs +++ b/substrate/primitives/trie/src/storage_proof.rs @@ -232,7 +232,8 @@ pub mod tests { use super::*; use crate::{tests::create_storage_proof, StorageProof}; - type Layout = crate::LayoutV1; + type Hasher = sp_core::Blake2Hasher; + type Layout = crate::LayoutV1; const TEST_DATA: &[(&[u8], &[u8])] = &[(b"key1", &[1; 64]), (b"key2", &[2; 64]), (b"key3", &[3; 64]), (b"key11", &[4; 64])]; @@ -245,4 +246,11 @@ pub mod tests { Err(StorageProofError::DuplicateNodes) )); } + + #[test] + fn invalid_compact_proof_does_not_panic_when_decoding() { + let invalid_proof = CompactProof { encoded_nodes: vec![vec![135]] }; + let result = invalid_proof.to_memory_db::(None); + assert!(result.is_err()); + } } diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 0424304989b7..7fa983d02823 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -22,11 +22,11 @@ impl-serde = { optional = true, workspace = true } parity-wasm = { optional = true, workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], optional = true, workspace = true } -thiserror = { optional = true, workspace = true } sp-crypto-hashing-proc-macro = { workspace = true, default-features = true } sp-runtime = { workspace = true } sp-std = { workspace = true } sp-version-proc-macro = { workspace = true } +thiserror = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs b/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs index b4f749c90f59..ac6d501b927d 100644 --- a/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs +++ b/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs @@ -182,21 +182,47 @@ impl ParseRuntimeVersion { } fn parse_str_literal(expr: &Expr) -> Result { - let mac = match *expr { - Expr::Macro(syn::ExprMacro { ref mac, .. }) => mac, - _ => return Err(Error::new(expr.span(), "a macro expression is expected here")), - }; + match expr { + // TODO: Remove this branch when `sp_runtime::create_runtime_str` is removed + Expr::Macro(syn::ExprMacro { mac, .. }) => { + let lit: ExprLit = mac.parse_body().map_err(|e| { + Error::new( + e.span(), + format!( + "a single literal argument is expected, but parsing is failed: {}", + e + ), + ) + })?; - let lit: ExprLit = mac.parse_body().map_err(|e| { - Error::new( - e.span(), - format!("a single literal argument is expected, but parsing is failed: {}", e), - ) - })?; + match &lit.lit { + Lit::Str(lit) => Ok(lit.value()), + _ => Err(Error::new(lit.span(), "only string literals are supported here")), + } + }, + Expr::Call(call) => { + if call.args.len() != 1 { + return Err(Error::new( + expr.span(), + "a single literal argument is expected, but parsing is failed", + )); + } + let Expr::Lit(lit) = call.args.first().expect("Length checked above; qed") else { + return Err(Error::new( + expr.span(), + "a single literal argument is expected, but parsing is failed", + )); + }; - match lit.lit { - Lit::Str(ref lit) => Ok(lit.value()), - _ => Err(Error::new(lit.span(), "only string literals are supported here")), + match &lit.lit { + Lit::Str(lit) => Ok(lit.value()), + _ => Err(Error::new(lit.span(), "only string literals are supported here")), + } + }, + _ => Err(Error::new( + expr.span(), + format!("a function call is expected here, instead of: {expr:?}"), + )), } } diff --git a/substrate/primitives/version/src/lib.rs b/substrate/primitives/version/src/lib.rs index a9f1c2373069..2e1464646647 100644 --- a/substrate/primitives/version/src/lib.rs +++ b/substrate/primitives/version/src/lib.rs @@ -46,7 +46,7 @@ use std::collections::HashSet; pub use alloc::borrow::Cow; use codec::{Decode, Encode, Input}; use scale_info::TypeInfo; -use sp_runtime::RuntimeString; +#[allow(deprecated)] pub use sp_runtime::{create_runtime_str, StateVersion}; #[doc(hidden)] pub use sp_std; @@ -72,12 +72,15 @@ pub mod embed; /// This macro accepts a const item like the following: /// /// ```rust -/// use sp_version::{create_runtime_str, RuntimeVersion}; +/// extern crate alloc; +/// +/// use alloc::borrow::Cow; +/// use sp_version::RuntimeVersion; /// /// #[sp_version::runtime_version] /// pub const VERSION: RuntimeVersion = RuntimeVersion { -/// spec_name: create_runtime_str!("test"), -/// impl_name: create_runtime_str!("test"), +/// spec_name: Cow::Borrowed("test"), +/// impl_name: Cow::Borrowed("test"), /// authoring_version: 10, /// spec_version: 265, /// impl_version: 1, @@ -164,14 +167,14 @@ pub struct RuntimeVersion { /// Identifies the different Substrate runtimes. There'll be at least polkadot and node. /// A different on-chain spec_name to that of the native runtime would normally result /// in node not attempting to sync or author blocks. - pub spec_name: RuntimeString, + pub spec_name: Cow<'static, str>, /// Name of the implementation of the spec. This is of little consequence for the node /// and serves only to differentiate code of different implementation teams. For this /// codebase, it will be parity-polkadot. If there were a non-Rust implementation of the /// Polkadot runtime (e.g. C++), then it would identify itself with an accordingly different /// `impl_name`. - pub impl_name: RuntimeString, + pub impl_name: Cow<'static, str>, /// `authoring_version` is the version of the authorship interface. An authoring node /// will not attempt to author blocks unless this is equal to its native runtime. @@ -472,8 +475,8 @@ impl<'de> serde::Deserialize<'de> for RuntimeVersion { where A: serde::de::MapAccess<'de>, { - let mut spec_name: Option = None; - let mut impl_name: Option = None; + let mut spec_name: Option> = None; + let mut impl_name: Option> = None; let mut authoring_version: Option = None; let mut spec_version: Option = None; let mut impl_version: Option = None; diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index 9d0310fd22e8..9f8eea5102d6 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -17,11 +17,11 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +anyhow = { optional = true, workspace = true } codec = { features = ["derive"], workspace = true } impl-trait-for-tuples = { workspace = true } log = { optional = true, workspace = true, default-features = true } wasmtime = { optional = true, workspace = true } -anyhow = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index c4e1897dbb8e..9cd0d9ac2e20 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -19,11 +19,11 @@ targets = ["x86_64-unknown-linux-gnu"] bounded-collections = { workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +schemars = { optional = true, workspace = true } serde = { optional = true, features = ["alloc", "derive"], workspace = true } smallvec = { workspace = true, default-features = true } sp-arithmetic = { workspace = true } sp-debug-derive = { workspace = true } -schemars = { optional = true, workspace = true } [features] default = ["std"] diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index d335dbcf3971..5b90044d44dd 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -18,7 +18,7 @@ clap = { features = ["derive"], workspace = true } flate2 = { workspace = true } fs_extra = { workspace = true } glob = { workspace = true } +itertools = { workspace = true } tar = { workspace = true } tempfile = { workspace = true } toml_edit = { workspace = true } -itertools = { workspace = true } diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index 4f7a70906859..87c9cb731e3a 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -20,5 +20,5 @@ futures = { workspace = true } tokio = { features = ["macros", "time"], workspace = true, default-features = true } [dev-dependencies] -trybuild = { features = ["diff"], workspace = true } sc-service = { workspace = true, default-features = true } +trybuild = { features = ["diff"], workspace = true } diff --git a/substrate/test-utils/cli/Cargo.toml b/substrate/test-utils/cli/Cargo.toml index 3fbcf2090683..b11e67bc49bc 100644 --- a/substrate/test-utils/cli/Cargo.toml +++ b/substrate/test-utils/cli/Cargo.toml @@ -16,17 +16,17 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -substrate-rpc-client = { workspace = true, default-features = true } -sp-rpc = { workspace = true, default-features = true } assert_cmd = { workspace = true } +futures = { workspace = true } nix = { features = ["signal"], workspace = true } -regex = { workspace = true } -tokio = { features = ["full"], workspace = true, default-features = true } -node-primitives = { workspace = true, default-features = true } node-cli = { workspace = true } +node-primitives = { workspace = true, default-features = true } +regex = { workspace = true } sc-cli = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } -futures = { workspace = true } +sp-rpc = { workspace = true, default-features = true } +substrate-rpc-client = { workspace = true, default-features = true } +tokio = { features = ["full"], workspace = true, default-features = true } [features] try-runtime = ["node-cli/try-runtime"] diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index ebd1eab5980d..e7ab4c8c8367 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -20,8 +20,6 @@ array-bytes = { workspace = true, default-features = true } async-trait = { workspace = true } codec = { workspace = true, default-features = true } futures = { workspace = true } -serde = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-client-db = { features = [ "test-helpers", @@ -29,9 +27,9 @@ sc-client-db = { features = [ sc-consensus = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-offchain = { workspace = true, default-features = true } -sc-service = { features = [ - "test-helpers", -], workspace = true } +sc-service = { workspace = true } +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index c07640653d56..5a4e6c911694 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -27,9 +27,7 @@ pub use sc_client_db::{self, Backend, BlocksPruning}; pub use sc_executor::{self, WasmExecutionMethod, WasmExecutor}; pub use sc_service::{client, RpcHandlers}; pub use sp_consensus; -pub use sp_keyring::{ - ed25519::Keyring as Ed25519Keyring, sr25519::Keyring as Sr25519Keyring, AccountKeyring, -}; +pub use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; pub use sp_keystore::{Keystore, KeystorePtr}; pub use sp_runtime::{Storage, StorageChild}; diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 1c82c73072bc..7af692b437f6 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -16,43 +16,43 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +codec = { features = ["derive"], workspace = true } +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-babe = { workspace = true } +pallet-balances = { workspace = true } +pallet-timestamp = { workspace = true } +sc-service = { optional = true, workspace = true } +scale-info = { features = ["derive"], workspace = true } +sp-api = { workspace = true } sp-application-crypto = { features = ["serde"], workspace = true } +sp-block-builder = { workspace = true } sp-consensus-aura = { features = ["serde"], workspace = true } sp-consensus-babe = { features = ["serde"], workspace = true } +sp-consensus-grandpa = { features = ["serde"], workspace = true } +sp-core = { features = ["serde"], workspace = true } +sp-crypto-hashing = { workspace = true } +sp-externalities = { workspace = true } sp-genesis-builder = { workspace = true } -sp-block-builder = { workspace = true } -codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } sp-inherents = { workspace = true } +sp-io = { workspace = true } sp-keyring = { workspace = true } sp-offchain = { workspace = true } -sp-core = { features = ["serde"], workspace = true } -sp-crypto-hashing = { workspace = true } -sp-io = { workspace = true } -frame-support = { workspace = true } -sp-version = { workspace = true } -sp-session = { workspace = true } -sp-api = { workspace = true } sp-runtime = { features = ["serde"], workspace = true } -pallet-babe = { workspace = true } -pallet-balances = { workspace = true } -frame-executive = { workspace = true } -frame-metadata-hash-extension = { workspace = true } -frame-system = { workspace = true } -frame-system-rpc-runtime-api = { workspace = true } -pallet-timestamp = { workspace = true } -sp-consensus-grandpa = { features = ["serde"], workspace = true } -sp-trie = { workspace = true } +sp-session = { workspace = true } +sp-state-machine = { workspace = true } sp-transaction-pool = { workspace = true } +sp-trie = { workspace = true } +sp-version = { workspace = true } trie-db = { workspace = true } -sc-service = { features = ["test-helpers"], optional = true, workspace = true } -sp-state-machine = { workspace = true } -sp-externalities = { workspace = true } # 3rd party array-bytes = { optional = true, workspace = true, default-features = true } -serde_json = { workspace = true, features = ["alloc"] } log = { workspace = true } +serde_json = { workspace = true, features = ["alloc"] } tracing = { workspace = true, default-features = false } [dev-dependencies] @@ -61,11 +61,11 @@ sc-block-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-executor-common = { workspace = true, default-features = true } -sp-consensus = { workspace = true, default-features = true } -substrate-test-runtime-client = { workspace = true } -sp-tracing = { workspace = true, default-features = true } serde = { features = ["alloc", "derive"], workspace = true } serde_json = { features = ["alloc"], workspace = true } +sp-consensus = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +substrate-test-runtime-client = { workspace = true } [build-dependencies] substrate-wasm-builder = { optional = true, features = ["metadata-hash"], workspace = true, default-features = true } diff --git a/substrate/test-utils/runtime/client/src/lib.rs b/substrate/test-utils/runtime/client/src/lib.rs index 435f3f5ebacb..a5a37660660c 100644 --- a/substrate/test-utils/runtime/client/src/lib.rs +++ b/substrate/test-utils/runtime/client/src/lib.rs @@ -45,7 +45,7 @@ pub mod prelude { Backend, ExecutorDispatch, TestClient, TestClientBuilder, WasmExecutionMethod, }; // Keyring - pub use super::{AccountKeyring, Sr25519Keyring}; + pub use super::Sr25519Keyring; } /// Test client database backend. diff --git a/substrate/test-utils/runtime/client/src/trait_tests.rs b/substrate/test-utils/runtime/client/src/trait_tests.rs index c3a5f173d14e..815e05163281 100644 --- a/substrate/test-utils/runtime/client/src/trait_tests.rs +++ b/substrate/test-utils/runtime/client/src/trait_tests.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use crate::{ - AccountKeyring, BlockBuilderExt, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt, + BlockBuilderExt, ClientBlockImportExt, Sr25519Keyring, TestClientBuilder, TestClientBuilderExt, }; use futures::executor::block_on; use sc_block_builder::BlockBuilderBuilder; @@ -132,8 +132,8 @@ where // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -179,8 +179,8 @@ where // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 1, }) @@ -199,8 +199,8 @@ where // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 0, }) @@ -295,8 +295,8 @@ where // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -338,8 +338,8 @@ where // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 1, }) @@ -357,8 +357,8 @@ where // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 0, }) @@ -464,8 +464,8 @@ where // this push is required as otherwise B2 has the same hash as A2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 41, nonce: 0, }) @@ -507,8 +507,8 @@ where // this push is required as otherwise C3 has the same hash as B3 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 1, }) @@ -526,8 +526,8 @@ where // this push is required as otherwise D2 has the same hash as B2 and won't get imported builder .push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Ferdie.into(), amount: 1, nonce: 0, }) diff --git a/substrate/test-utils/runtime/src/extrinsic.rs b/substrate/test-utils/runtime/src/extrinsic.rs index 8f94dd10a834..491086bef497 100644 --- a/substrate/test-utils/runtime/src/extrinsic.rs +++ b/substrate/test-utils/runtime/src/extrinsic.rs @@ -25,7 +25,7 @@ use codec::Encode; use frame_metadata_hash_extension::CheckMetadataHash; use frame_system::{CheckNonce, CheckWeight}; use sp_core::crypto::Pair as TraitPair; -use sp_keyring::AccountKeyring; +use sp_keyring::Sr25519Keyring; use sp_runtime::{ generic::Preamble, traits::TransactionExtension, transaction_validity::TransactionPriority, Perbill, @@ -54,8 +54,8 @@ impl Transfer { impl Default for TransferData { fn default() -> Self { Self { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), amount: 0, nonce: 0, } @@ -69,7 +69,7 @@ impl TryFrom<&Extrinsic> for TransferData { match uxt { Extrinsic { function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }), - preamble: Preamble::Signed(from, _, _, ((CheckNonce(nonce), ..), ..)), + preamble: Preamble::Signed(from, _, ((CheckNonce(nonce), ..), ..)), } => Ok(TransferData { from: *from, to: *dest, amount: *value, nonce: *nonce }), Extrinsic { function: RuntimeCall::SubstrateTest(PalletCall::bench_call { transfer }), @@ -93,7 +93,7 @@ impl ExtrinsicBuilder { pub fn new(function: impl Into) -> Self { Self { function: function.into(), - signer: Some(AccountKeyring::Alice.pair()), + signer: Some(Sr25519Keyring::Alice.pair()), nonce: None, metadata_hash: None, } diff --git a/substrate/test-utils/runtime/src/genesismap.rs b/substrate/test-utils/runtime/src/genesismap.rs index 9e972886b377..5c0c146d45a5 100644 --- a/substrate/test-utils/runtime/src/genesismap.rs +++ b/substrate/test-utils/runtime/src/genesismap.rs @@ -27,7 +27,7 @@ use sp_core::{ storage::{well_known_keys, StateVersion, Storage}, Pair, }; -use sp_keyring::{AccountKeyring, Sr25519Keyring}; +use sp_keyring::Sr25519Keyring; use sp_runtime::{ traits::{Block as BlockT, Hash as HashT, Header as HeaderT}, BuildStorage, @@ -60,11 +60,11 @@ impl Default for GenesisStorageBuilder { ], (0..16_usize) .into_iter() - .map(|i| AccountKeyring::numeric(i).public()) + .map(|i| Sr25519Keyring::numeric(i).public()) .chain(vec![ - AccountKeyring::Alice.into(), - AccountKeyring::Bob.into(), - AccountKeyring::Charlie.into(), + Sr25519Keyring::Alice.into(), + Sr25519Keyring::Bob.into(), + Sr25519Keyring::Charlie.into(), ]) .collect(), 1000 * currency::DOLLARS, diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index a4a0d348a390..666776865316 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -47,7 +47,7 @@ use frame_system::{ }; use scale_info::TypeInfo; use sp_application_crypto::Ss58Codec; -use sp_keyring::AccountKeyring; +use sp_keyring::Sr25519Keyring; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; use sp_core::{OpaqueMetadata, RuntimeDebug}; @@ -63,7 +63,7 @@ pub use sp_core::hash::H256; use sp_genesis_builder::PresetId; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ - create_runtime_str, impl_opaque_keys, impl_tx_ext_default, + impl_opaque_keys, impl_tx_ext_default, traits::{BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, NumberFor, Verify}, transaction_validity::{ TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -114,8 +114,8 @@ pub fn wasm_binary_logging_disabled_unwrap() -> &'static [u8] { /// Test runtime version. #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("test"), - impl_name: create_runtime_str!("parity-test"), + spec_name: alloc::borrow::Cow::Borrowed("test"), + impl_name: alloc::borrow::Cow::Borrowed("parity-test"), authoring_version: 1, spec_version: 2, impl_version: 2, @@ -292,6 +292,7 @@ impl sp_runtime::traits::TransactionExtension for CheckSubstrateCal _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Encode, + _source: TransactionSource, ) -> Result< (ValidTransaction, Self::Val, ::RuntimeOrigin), TransactionValidityError, @@ -727,11 +728,11 @@ impl_runtime_apis! { fn get_preset(name: &Option) -> Option> { get_preset::(name, |name| { - let patch = match name.try_into() { - Ok("staging") => { + let patch = match name.as_ref() { + "staging" => { let endowed_accounts: Vec = vec![ - AccountKeyring::Bob.public().into(), - AccountKeyring::Charlie.public().into(), + Sr25519Keyring::Bob.public().into(), + Sr25519Keyring::Charlie.public().into(), ]; json!({ @@ -740,13 +741,13 @@ impl_runtime_apis! { }, "substrateTest": { "authorities": [ - AccountKeyring::Alice.public().to_ss58check(), - AccountKeyring::Ferdie.public().to_ss58check() + Sr25519Keyring::Alice.public().to_ss58check(), + Sr25519Keyring::Ferdie.public().to_ss58check() ], } }) }, - Ok("foobar") => json!({"foo":"bar"}), + "foobar" => json!({"foo":"bar"}), _ => return None, }; Some(serde_json::to_string(&patch) @@ -910,11 +911,11 @@ pub mod storage_key_generator { let balances_map_keys = (0..16_usize) .into_iter() - .map(|i| AccountKeyring::numeric(i).public().to_vec()) + .map(|i| Sr25519Keyring::numeric(i).public().to_vec()) .chain(vec![ - AccountKeyring::Alice.public().to_vec(), - AccountKeyring::Bob.public().to_vec(), - AccountKeyring::Charlie.public().to_vec(), + Sr25519Keyring::Alice.public().to_vec(), + Sr25519Keyring::Bob.public().to_vec(), + Sr25519Keyring::Charlie.public().to_vec(), ]) .map(|pubkey| { sp_crypto_hashing::blake2_128(&pubkey) @@ -1053,7 +1054,7 @@ mod tests { use sp_core::{storage::well_known_keys::HEAP_PAGES, traits::CallContext}; use sp_runtime::{ traits::{DispatchTransaction, Hash as _}, - transaction_validity::{InvalidTransaction, ValidTransaction}, + transaction_validity::{InvalidTransaction, TransactionSource::External, ValidTransaction}, }; use substrate_test_runtime_client::{ prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, @@ -1132,8 +1133,8 @@ mod tests { pub fn new_test_ext() -> sp_io::TestExternalities { genesismap::GenesisStorageBuilder::new( - vec![AccountKeyring::One.public().into(), AccountKeyring::Two.public().into()], - vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()], + vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()], 1000 * currency::DOLLARS, ) .build() @@ -1201,7 +1202,7 @@ mod tests { fn check_substrate_check_signed_extension_works() { sp_tracing::try_init_simple(); new_test_ext().execute_with(|| { - let x = AccountKeyring::Alice.into(); + let x = Sr25519Keyring::Alice.into(); let info = DispatchInfo::default(); let len = 0_usize; assert_eq!( @@ -1211,6 +1212,8 @@ mod tests { &ExtrinsicBuilder::new_call_with_priority(16).build().function, &info, len, + External, + 0, ) .unwrap() .0 @@ -1225,6 +1228,8 @@ mod tests { &ExtrinsicBuilder::new_call_do_not_propagate().build().function, &info, len, + External, + 0, ) .unwrap() .0 @@ -1392,10 +1397,8 @@ mod tests { let r = BuildResult::decode(&mut &r[..]).unwrap(); log::info!("result: {:#?}", r); assert_eq!(r, Err( - sp_runtime::RuntimeString::Owned( - "Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 4 column 25".to_string(), - )) - ); + "Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 4 column 25".to_string(), + )); } #[test] @@ -1406,10 +1409,8 @@ mod tests { let r = executor_call(&mut t, "GenesisBuilder_build_state", &j.encode()).unwrap(); let r = BuildResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Err( - sp_runtime::RuntimeString::Owned( - "Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 3 column 9".to_string(), - )) - ); + "Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 3 column 9".to_string(), + )); } #[test] @@ -1419,14 +1420,11 @@ mod tests { let mut t = BasicExternalities::new_empty(); let r = executor_call(&mut t, "GenesisBuilder_build_state", &j.encode()).unwrap(); - let r = - core::result::Result::<(), sp_runtime::RuntimeString>::decode(&mut &r[..]).unwrap(); + let r = core::result::Result::<(), String>::decode(&mut &r[..]).unwrap(); assert_eq!( r, - Err(sp_runtime::RuntimeString::Owned( - "Invalid JSON blob: missing field `authorities` at line 11 column 3" - .to_string() - )) + Err("Invalid JSON blob: missing field `authorities` at line 11 column 3" + .to_string()) ); } @@ -1474,8 +1472,8 @@ mod tests { }, "substrateTest": { "authorities": [ - AccountKeyring::Ferdie.public().to_ss58check(), - AccountKeyring::Alice.public().to_ss58check() + Sr25519Keyring::Ferdie.public().to_ss58check(), + Sr25519Keyring::Alice.public().to_ss58check() ], } }); @@ -1504,8 +1502,8 @@ mod tests { let authority_key_vec = Vec::::decode(&mut &value[..]).unwrap(); assert_eq!(authority_key_vec.len(), 2); - assert_eq!(authority_key_vec[0], AccountKeyring::Ferdie.public()); - assert_eq!(authority_key_vec[1], AccountKeyring::Alice.public()); + assert_eq!(authority_key_vec[0], Sr25519Keyring::Ferdie.public()); + assert_eq!(authority_key_vec[1], Sr25519Keyring::Alice.public()); //Babe|Authorities let value: Vec = get_from_storage( diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index 3cdaea642263..501c9f99ebf1 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -19,9 +19,9 @@ codec = { workspace = true, default-features = true } futures = { workspace = true } log = { workspace = true } parking_lot = { workspace = true, default-features = true } -thiserror = { workspace = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +thiserror = { workspace = true } diff --git a/substrate/test-utils/runtime/transaction-pool/src/lib.rs b/substrate/test-utils/runtime/transaction-pool/src/lib.rs index 6a4f38f63e82..93e5855eefc6 100644 --- a/substrate/test-utils/runtime/transaction-pool/src/lib.rs +++ b/substrate/test-utils/runtime/transaction-pool/src/lib.rs @@ -43,7 +43,7 @@ use substrate_test_runtime_client::{ AccountId, Block, BlockNumber, Extrinsic, ExtrinsicBuilder, Hash, Header, Nonce, Transfer, TransferData, }, - AccountKeyring::{self, *}, + Sr25519Keyring::{self, *}, }; /// Error type used by [`TestApi`]. @@ -338,7 +338,7 @@ trait TagFrom { impl TagFrom for AccountId { fn tag_from(&self) -> u8 { - let f = AccountKeyring::iter().enumerate().find(|k| AccountId::from(k.1) == *self); + let f = Sr25519Keyring::iter().enumerate().find(|k| AccountId::from(k.1) == *self); u8::try_from(f.unwrap().0).unwrap() } } @@ -534,7 +534,7 @@ impl sp_blockchain::HeaderMetadata for TestApi { /// Generate transfer extrinsic with a given nonce. /// /// Part of the test api. -pub fn uxt(who: AccountKeyring, nonce: Nonce) -> Extrinsic { +pub fn uxt(who: Sr25519Keyring, nonce: Nonce) -> Extrinsic { let dummy = codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap(); let transfer = Transfer { from: who.into(), to: dummy, nonce, amount: 1 }; ExtrinsicBuilder::new_transfer(transfer).build() diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index 9577d94ef0bf..86d64face80e 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -12,16 +12,16 @@ homepage.workspace = true workspace = true [dependencies] -codec = { workspace = true, features = ["derive"] } array-bytes = { optional = true, workspace = true, default-features = true } -log = { optional = true, workspace = true } +codec = { workspace = true, features = ["derive"] } hash-db = { workspace = true } +log = { optional = true, workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [features] debug = ["array-bytes", "log"] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 8a4a06b1b40a..c38a7e4f77d8 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -16,25 +16,27 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +Inflector = { workspace = true } array-bytes = { workspace = true, default-features = true } chrono = { workspace = true } clap = { features = ["derive"], workspace = true } codec = { workspace = true, default-features = true } comfy-table = { workspace = true } +cumulus-client-parachain-inherent = { workspace = true, default-features = true } +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } +frame-benchmarking = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } +gethostname = { workspace = true } handlebars = { workspace = true } -Inflector = { workspace = true } +hex = { workspace = true, default-features = true } itertools = { workspace = true } linked-hash-map = { workspace = true } log = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } rand = { features = ["small_rng"], workspace = true, default-features = true } rand_pcg = { workspace = true } -serde = { workspace = true, default-features = true } -serde_json = { workspace = true, default-features = true } -thiserror = { workspace = true } -thousands = { workspace = true } -frame-benchmarking = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true } sc-cli = { workspace = true } @@ -42,35 +44,34 @@ sc-client-api = { workspace = true, default-features = true } sc-client-db = { workspace = true } sc-executor = { workspace = true, default-features = true } sc-executor-common = { workspace = true } +sc-runtime-utilities = { workspace = true, default-features = true } sc-service = { workspace = true } sc-sysinfo = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } sp-database = { workspace = true, default-features = true } sp-externalities = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } -sp-crypto-hashing = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } sp-storage = { workspace = true, default-features = true } -sp-trie = { workspace = true, default-features = true } -sp-block-builder = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } sp-transaction-pool = { workspace = true, default-features = true } +sp-trie = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } sp-wasm-interface = { workspace = true, default-features = true } subxt = { workspace = true, features = ["native"] } subxt-signer = { workspace = true, features = ["unstable-eth"] } -cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } -cumulus-client-parachain-inherent = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -gethostname = { workspace = true } -hex = { workspace = true, default-features = true } +thiserror = { workspace = true } +thousands = { workspace = true } [dev-dependencies] cumulus-test-runtime = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 1e8642e54d70..e1c3c5fe3706 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -30,7 +30,6 @@ pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ remark_builder::{DynamicRemarkBuilder, SubstrateRemarkBuilder}, - runtime_utilities::fetch_latest_metadata_from_code_blob, OpaqueBlock, OverheadCmd, }; pub use pallet::PalletCmd; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs index 8102f14b4f4b..8df8ee5464f7 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -18,7 +18,6 @@ //! Contains the [`OverheadCmd`] as entry point for the CLI to execute //! the *overhead* benchmarks. -use super::runtime_utilities::*; use crate::{ extrinsic::{ bench::{Benchmark, BenchmarkParams as ExtrinsicBenchmarkParams}, @@ -37,7 +36,7 @@ use crate::{ }, }; use clap::{error::ErrorKind, Args, CommandFactory, Parser}; -use codec::Encode; +use codec::{Decode, Encode}; use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; use fake_runtime_api::RuntimeApi as FakeRuntimeApi; use frame_support::Deserialize; @@ -50,6 +49,7 @@ use sc_cli::{CliConfiguration, Database, ImportParams, Result, SharedParams}; use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; use sc_client_db::{BlocksPruning, DatabaseSettings}; use sc_executor::WasmExecutor; +use sc_runtime_utilities::fetch_latest_metadata_from_code_blob; use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; use serde::Serialize; use serde_json::{json, Value}; @@ -317,7 +317,7 @@ impl OverheadCmd { Some(self.params.genesis_builder_preset.clone()), ), self.params.para_id, - )) + )); }; Err("Neither a runtime nor a chain-spec were specified".to_string().into()) @@ -335,7 +335,7 @@ impl OverheadCmd { ErrorKind::MissingRequiredArgument, "Provide either a runtime via `--runtime` or a chain spec via `--chain`" .to_string(), - )) + )); } match self.params.genesis_builder { @@ -344,7 +344,7 @@ impl OverheadCmd { return Err(( ErrorKind::MissingRequiredArgument, "Provide a chain spec via `--chain`.".to_string(), - )) + )); }, _ => {}, }; @@ -400,8 +400,12 @@ impl OverheadCmd { .with_allow_missing_host_functions(true) .build(); - let metadata = - fetch_latest_metadata_from_code_blob(&executor, state_handler.get_code_bytes()?)?; + let opaque_metadata = + fetch_latest_metadata_from_code_blob(&executor, state_handler.get_code_bytes()?) + .map_err(|_| { + <&str as Into>::into("Unable to fetch latest stable metadata") + })?; + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?; // At this point we know what kind of chain we are dealing with. let chain_type = identify_chain(&metadata, para_id); @@ -682,6 +686,7 @@ mod tests { OverheadCmd, }; use clap::Parser; + use codec::Decode; use sc_executor::WasmExecutor; #[test] @@ -690,8 +695,9 @@ mod tests { let code_bytes = westend_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of westend-runtime") .to_vec(); - let metadata = + let opaque_metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice()).unwrap(); let chain_type = identify_chain(&metadata, None); assert_eq!(chain_type, ChainType::Relaychain); assert_eq!(chain_type.requires_proof_recording(), false); @@ -703,8 +709,9 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = + let opaque_metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice()).unwrap(); let chain_type = identify_chain(&metadata, Some(100)); assert_eq!(chain_type, ChainType::Parachain(100)); assert!(chain_type.requires_proof_recording()); @@ -717,8 +724,9 @@ mod tests { let code_bytes = substrate_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of substrate-test-runtime") .to_vec(); - let metadata = + let opaque_metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice()).unwrap(); let chain_type = identify_chain(&metadata, None); assert_eq!(chain_type, ChainType::Unknown); assert_eq!(chain_type.requires_proof_recording(), false); diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs index 89c23d1fb6c1..de524d9ebc18 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -20,6 +20,5 @@ pub mod template; mod fake_runtime_api; pub mod remark_builder; -pub mod runtime_utilities; pub use command::{OpaqueBlock, OverheadCmd}; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs index a1d5f282d9f8..3a2d8776d1e1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs @@ -54,13 +54,15 @@ impl> DynamicRemarkBuilder { log::debug!("Found metadata API version {}.", metadata_api_version); let opaque_metadata = if metadata_api_version > 1 { - let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) else { + let Ok(supported_metadata_versions) = api.metadata_versions(genesis) else { return Err("Unable to fetch metadata versions".to_string().into()); }; let latest = supported_metadata_versions - .pop() - .ok_or("No metadata version supported".to_string())?; + .into_iter() + .filter(|v| *v != u32::MAX) + .max() + .ok_or("No stable metadata versions supported".to_string())?; api.metadata_at_version(genesis, latest) .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 6f7e79f16384..0c068fc585ba 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -96,6 +96,7 @@ pub(crate) type PovModesMap = #[derive(Debug, Clone)] struct SelectedBenchmark { pallet: String, + instance: String, extrinsic: String, components: Vec<(BenchmarkParameter, u32, u32)>, pov_modes: Vec<(String, String)>, @@ -152,7 +153,7 @@ fn combine_batches( } /// Explains possible reasons why the metadata for the benchmarking could not be found. -const ERROR_METADATA_NOT_FOUND: &'static str = "Did not find the benchmarking metadata. \ +const ERROR_API_NOT_FOUND: &'static str = "Did not find the benchmarking runtime api. \ This could mean that you either did not build the node correctly with the \ `--features runtime-benchmarks` flag, or the chain spec that you are using was \ not created by a node that was compiled with the flag"; @@ -306,6 +307,33 @@ impl PalletCmd { .with_runtime_cache_size(2) .build(); + let runtime_version: sp_version::RuntimeVersion = Self::exec_state_machine( + StateMachine::new( + state, + &mut Default::default(), + &executor, + "Core_version", + &[], + &mut Self::build_extensions(executor.clone(), state.recorder()), + &runtime_code, + CallContext::Offchain, + ), + "Could not find `Core::version` runtime api.", + )?; + + let benchmark_api_version = runtime_version + .api_version( + &, + sp_runtime::generic::UncheckedExtrinsic<(), (), (), ()>, + >, + > as sp_api::RuntimeApiInfo>::ID, + ) + .ok_or_else(|| ERROR_API_NOT_FOUND)?; + let (list, storage_info): (Vec, Vec) = Self::exec_state_machine( StateMachine::new( @@ -318,7 +346,7 @@ impl PalletCmd { &runtime_code, CallContext::Offchain, ), - ERROR_METADATA_NOT_FOUND, + ERROR_API_NOT_FOUND, )?; // Use the benchmark list and the user input to determine the set of benchmarks to run. @@ -338,7 +366,7 @@ impl PalletCmd { let pov_modes = Self::parse_pov_modes(&benchmarks_to_run)?; let mut failed = Vec::<(String, String)>::new(); - 'outer: for (i, SelectedBenchmark { pallet, extrinsic, components, .. }) in + 'outer: for (i, SelectedBenchmark { pallet, instance, extrinsic, components, .. }) in benchmarks_to_run.clone().into_iter().enumerate() { log::info!( @@ -392,7 +420,31 @@ impl PalletCmd { } all_components }; + for (s, selected_components) in all_components.iter().enumerate() { + let params = |verify: bool, repeats: u32| -> Vec { + if benchmark_api_version >= 2 { + ( + pallet.as_bytes(), + instance.as_bytes(), + extrinsic.as_bytes(), + &selected_components.clone(), + verify, + repeats, + ) + .encode() + } else { + ( + pallet.as_bytes(), + extrinsic.as_bytes(), + &selected_components.clone(), + verify, + repeats, + ) + .encode() + } + }; + // First we run a verification if !self.no_verify { let state = &state_without_tracking; @@ -407,14 +459,7 @@ impl PalletCmd { &mut Default::default(), &executor, "Benchmark_dispatch_benchmark", - &( - pallet.as_bytes(), - extrinsic.as_bytes(), - &selected_components.clone(), - true, // run verification code - 1, // no need to do internal repeats - ) - .encode(), + ¶ms(true, 1), &mut Self::build_extensions(executor.clone(), state.recorder()), &runtime_code, CallContext::Offchain, @@ -447,14 +492,7 @@ impl PalletCmd { &mut Default::default(), &executor, "Benchmark_dispatch_benchmark", - &( - pallet.as_bytes(), - extrinsic.as_bytes(), - &selected_components.clone(), - false, // don't run verification code for final values - self.repeat, - ) - .encode(), + ¶ms(false, self.repeat), &mut Self::build_extensions(executor.clone(), state.recorder()), &runtime_code, CallContext::Offchain, @@ -489,14 +527,7 @@ impl PalletCmd { &mut Default::default(), &executor, "Benchmark_dispatch_benchmark", - &( - pallet.as_bytes(), - extrinsic.as_bytes(), - &selected_components.clone(), - false, // don't run verification code for final values - self.repeat, - ) - .encode(), + ¶ms(false, self.repeat), &mut Self::build_extensions(executor.clone(), state.recorder()), &runtime_code, CallContext::Offchain, @@ -571,6 +602,7 @@ impl PalletCmd { { benchmarks_to_run.push(( item.pallet.clone(), + item.instance.clone(), benchmark.name.clone(), benchmark.components.clone(), benchmark.pov_modes.clone(), @@ -581,13 +613,15 @@ impl PalletCmd { // Convert `Vec` to `String` for better readability. let benchmarks_to_run: Vec<_> = benchmarks_to_run .into_iter() - .map(|(pallet, extrinsic, components, pov_modes)| { - let pallet = String::from_utf8(pallet.clone()).expect("Encoded from String; qed"); + .map(|(pallet, instance, extrinsic, components, pov_modes)| { + let pallet = String::from_utf8(pallet).expect("Encoded from String; qed"); + let instance = String::from_utf8(instance).expect("Encoded from String; qed"); let extrinsic = String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"); SelectedBenchmark { pallet, + instance, extrinsic, components, pov_modes: pov_modes diff --git a/substrate/utils/frame/generate-bags/Cargo.toml b/substrate/utils/frame/generate-bags/Cargo.toml index c37c42646699..c03f85ece05d 100644 --- a/substrate/utils/frame/generate-bags/Cargo.toml +++ b/substrate/utils/frame/generate-bags/Cargo.toml @@ -13,8 +13,8 @@ workspace = true [dependencies] # FRAME -frame-support = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } pallet-staking = { workspace = true, default-features = true } sp-staking = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index 3d5748647257..aace0f4ad23f 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -13,8 +13,8 @@ publish = false workspace = true [dependencies] -kitchensink-runtime = { workspace = true } generate-bags = { workspace = true, default-features = true } +kitchensink-runtime = { workspace = true } # third-party clap = { features = ["derive"], workspace = true } diff --git a/substrate/utils/frame/omni-bencher/Cargo.toml b/substrate/utils/frame/omni-bencher/Cargo.toml index 345a7288d45b..d0d7f1a3428f 100644 --- a/substrate/utils/frame/omni-bencher/Cargo.toml +++ b/substrate/utils/frame/omni-bencher/Cargo.toml @@ -15,16 +15,16 @@ workspace = true clap = { features = ["derive"], workspace = true } cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } frame-benchmarking-cli = { workspace = true } +log = { workspace = true } sc-cli = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-statement-store = { workspace = true, default-features = true } tracing-subscriber = { workspace = true } -log = { workspace = true } [dev-dependencies] -tempfile = { workspace = true } assert_cmd = { workspace = true } cumulus-test-runtime = { workspace = true } -sp-tracing = { workspace = true, default-features = true } -sp-genesis-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true } +sp-genesis-builder = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +tempfile = { workspace = true } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 41a0091027c1..4ed0e1edf3e4 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -15,20 +15,20 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { features = ["http-client"], workspace = true } codec = { workspace = true, default-features = true } +futures = { workspace = true } +indicatif = { workspace = true } +jsonrpsee = { features = ["http-client"], workspace = true } log = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } -sp-state-machine = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -tokio = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } -substrate-rpc-client = { workspace = true, default-features = true } -futures = { workspace = true } -indicatif = { workspace = true } +sp-state-machine = { workspace = true, default-features = true } spinners = { workspace = true } +substrate-rpc-client = { workspace = true, default-features = true } +tokio = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } tokio-retry = { workspace = true } [dev-dependencies] diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index d26be3a13124..6282621e1c75 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -15,13 +15,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = { workspace = true } jsonrpsee = { features = ["ws-client"], workspace = true } +log = { workspace = true, default-features = true } sc-rpc-api = { workspace = true, default-features = true } -async-trait = { workspace = true } serde = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } [dev-dependencies] -tokio = { features = ["macros", "rt-multi-thread", "sync"], workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } +tokio = { features = ["macros", "rt-multi-thread", "sync"], workspace = true, default-features = true } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 82652c8fa262..45b2bc6fa9b3 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true, default-features = true } -jsonrpsee = { features = ["jsonrpsee-types"], workspace = true } -serde = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } +jsonrpsee = { features = ["jsonrpsee-types"], workspace = true } sc-rpc-api = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } sp-storage = { workspace = true, default-features = true } [dev-dependencies] -scale-info = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } jsonrpsee = { features = ["jsonrpsee-types", "ws-client"], workspace = true } -tokio = { workspace = true, default-features = true } +scale-info = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -frame-system = { workspace = true, default-features = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 5757a48498c7..68dfbb833c6f 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -16,16 +16,16 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = { workspace = true } codec = { workspace = true, default-features = true } docify = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true, default-features = true } +futures = { workspace = true } jsonrpsee = { features = [ "client-core", "macros", "server-core", ], workspace = true } log = { workspace = true, default-features = true } -frame-system-rpc-runtime-api = { workspace = true, default-features = true } sc-rpc-api = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } @@ -35,8 +35,8 @@ sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } [dev-dependencies] -sc-transaction-pool = { workspace = true, default-features = true } -tokio = { workspace = true, default-features = true } assert_matches = { workspace = true } +sc-transaction-pool = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } +tokio = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/rpc/system/src/lib.rs b/substrate/utils/frame/rpc/system/src/lib.rs index 824c871a3562..e1b3994c03dd 100644 --- a/substrate/utils/frame/rpc/system/src/lib.rs +++ b/substrate/utils/frame/rpc/system/src/lib.rs @@ -224,7 +224,7 @@ mod tests { transaction_validity::{InvalidTransaction, TransactionValidityError}, ApplyExtrinsicResult, }; - use substrate_test_runtime_client::{runtime::Transfer, AccountKeyring}; + use substrate_test_runtime_client::{runtime::Transfer, Sr25519Keyring}; fn deny_unsafe() -> Extensions { let mut ext = Extensions::new(); @@ -256,8 +256,8 @@ mod tests { let source = sp_runtime::transaction_validity::TransactionSource::External; let new_transaction = |nonce: u64| { let t = Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), amount: 5, nonce, }; @@ -273,7 +273,7 @@ mod tests { let accounts = System::new(client, pool); // when - let nonce = accounts.nonce(AccountKeyring::Alice.into()).await; + let nonce = accounts.nonce(Sr25519Keyring::Alice.into()).await; // then assert_eq!(nonce.unwrap(), 2); @@ -321,8 +321,8 @@ mod tests { let accounts = System::new(client, pool); let tx = Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), amount: 5, nonce: 0, } @@ -357,8 +357,8 @@ mod tests { let accounts = System::new(client, pool); let tx = Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Bob.into(), + from: Sr25519Keyring::Alice.into(), + to: Sr25519Keyring::Bob.into(), amount: 5, nonce: 100, } diff --git a/substrate/utils/prometheus/Cargo.toml b/substrate/utils/prometheus/Cargo.toml index 9bdec3cb8183..b8dfd6fb2bee 100644 --- a/substrate/utils/prometheus/Cargo.toml +++ b/substrate/utils/prometheus/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] http-body-util = { workspace = true } hyper = { features = ["http1", "server"], workspace = true } -hyper-util = { features = ["server-auto", "tokio"], workspace = true } +hyper-util = { features = ["server-auto", "server-graceful", "tokio"], workspace = true } log = { workspace = true, default-features = true } prometheus = { workspace = true } thiserror = { workspace = true } diff --git a/substrate/utils/prometheus/src/lib.rs b/substrate/utils/prometheus/src/lib.rs index 35597cad03d8..ae39cb4a7dd3 100644 --- a/substrate/utils/prometheus/src/lib.rs +++ b/substrate/utils/prometheus/src/lib.rs @@ -87,7 +87,7 @@ async fn request_metrics( /// to serve metrics. pub async fn init_prometheus(prometheus_addr: SocketAddr, registry: Registry) -> Result<(), Error> { let listener = tokio::net::TcpListener::bind(&prometheus_addr).await.map_err(|e| { - log::error!(target: "prometheus", "Error binding to '{:#?}': {:#?}", prometheus_addr, e); + log::error!(target: "prometheus", "Error binding to '{prometheus_addr:?}': {e:?}"); Error::PortInUse(prometheus_addr) })?; @@ -102,6 +102,7 @@ async fn init_prometheus_with_listener( log::info!(target: "prometheus", "〽️ Prometheus exporter started at {}", listener.local_addr()?); let server = hyper_util::server::conn::auto::Builder::new(hyper_util::rt::TokioExecutor::new()); + let graceful = hyper_util::server::graceful::GracefulShutdown::new(); loop { let io = match listener.accept().await { @@ -120,6 +121,7 @@ async fn init_prometheus_with_listener( hyper::service::service_fn(move |req| request_metrics(req, registry.clone())), ) .into_owned(); + let conn = graceful.watch(conn); tokio::spawn(async move { if let Err(err) = conn.await { diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 8f0e8a23e54a..6645dd1803bf 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -18,28 +18,28 @@ targets = ["x86_64-unknown-linux-gnu"] build-helper = { workspace = true } cargo_metadata = { workspace = true } console = { workspace = true } +filetime = { workspace = true } +jobserver = { workspace = true } +parity-wasm = { workspace = true } +polkavm-linker = { workspace = true } +sp-maybe-compressed-blob = { workspace = true, default-features = true } strum = { features = ["derive"], workspace = true, default-features = true } tempfile = { workspace = true } toml = { workspace = true } walkdir = { workspace = true } -sp-maybe-compressed-blob = { workspace = true, default-features = true } -filetime = { workspace = true } wasm-opt = { workspace = true } -parity-wasm = { workspace = true } -polkavm-linker = { workspace = true } -jobserver = { workspace = true } # Dependencies required for the `metadata-hash` feature. +array-bytes = { optional = true, workspace = true, default-features = true } +codec = { optional = true, workspace = true, default-features = true } +frame-metadata = { features = ["current", "unstable"], optional = true, workspace = true, default-features = true } merkleized-metadata = { optional = true, workspace = true } sc-executor = { optional = true, workspace = true, default-features = true } +shlex = { workspace = true } sp-core = { optional = true, workspace = true, default-features = true } sp-io = { optional = true, workspace = true, default-features = true } -sp-version = { optional = true, workspace = true, default-features = true } -frame-metadata = { features = ["current"], optional = true, workspace = true, default-features = true } -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 } +sp-version = { optional = true, workspace = true, default-features = true } [features] # Enable support for generating the metadata hash. diff --git a/substrate/utils/wasm-builder/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs index a40aafe1d812..5bdc743eac31 100644 --- a/substrate/utils/wasm-builder/src/builder.rs +++ b/substrate/utils/wasm-builder/src/builder.rs @@ -235,7 +235,8 @@ impl WasmBuilder { /// Build the WASM binary. pub fn build(mut self) { - let target = crate::runtime_target(); + let target = RuntimeTarget::new(); + if target == RuntimeTarget::Wasm { if self.export_heap_base { self.rust_flags.push("-Clink-arg=--export=__heap_base".into()); diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index 420ecd63e1dc..ce90f492e08f 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -112,7 +112,6 @@ //! wasm32-unknown-unknown --toolchain nightly-2020-02-20`. use std::{ - collections::BTreeSet, env, fs, io::BufRead, path::{Path, PathBuf}, @@ -254,26 +253,22 @@ struct CargoCommand { program: String, args: Vec, version: Option, - target_list: Option>, } impl CargoCommand { fn new(program: &str) -> Self { let version = Self::extract_version(program, &[]); - let target_list = Self::extract_target_list(program, &[]); - CargoCommand { program: program.into(), args: Vec::new(), version, target_list } + CargoCommand { program: program.into(), args: Vec::new(), version } } fn new_with_args(program: &str, args: &[&str]) -> Self { let version = Self::extract_version(program, args); - let target_list = Self::extract_target_list(program, args); CargoCommand { program: program.into(), args: args.iter().map(ToString::to_string).collect(), version, - target_list, } } @@ -294,23 +289,6 @@ impl CargoCommand { Version::extract(&version) } - fn extract_target_list(program: &str, args: &[&str]) -> Option> { - // This is technically an unstable option, but we don't care because we only need this - // to build RISC-V runtimes, and those currently require a specific nightly toolchain - // anyway, so it's totally fine for this to fail in other cases. - let list = Command::new(program) - .args(args) - .args(&["rustc", "-Z", "unstable-options", "--print", "target-list"]) - // Make sure if we're called from within a `build.rs` the host toolchain won't override - // a rustup toolchain we've picked. - .env_remove("RUSTC") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok())?; - - Some(list.trim().split("\n").map(ToString::to_string).collect()) - } - /// Returns the version of this cargo command or `None` if it failed to extract the version. fn version(&self) -> Option { self.version @@ -326,19 +304,10 @@ impl CargoCommand { fn supports_substrate_runtime_env(&self, target: RuntimeTarget) -> bool { match target { RuntimeTarget::Wasm => self.supports_substrate_runtime_env_wasm(), - RuntimeTarget::Riscv => self.supports_substrate_runtime_env_riscv(), + RuntimeTarget::Riscv => true, } } - /// Check if the supplied cargo command supports our RISC-V runtime environment. - fn supports_substrate_runtime_env_riscv(&self) -> bool { - let Some(target_list) = self.target_list.as_ref() else { return false }; - // This is our custom target which currently doesn't exist on any upstream toolchain, - // so if it exists it's guaranteed to be our custom toolchain and have have everything - // we need, so any further version checks are unnecessary at this point. - target_list.contains("riscv32ema-unknown-none-elf") - } - /// Check if the supplied cargo command supports our Substrate wasm environment. /// /// This means that either the cargo version is at minimum 1.68.0 or this is a nightly cargo. @@ -409,13 +378,6 @@ fn get_bool_environment_variable(name: &str) -> Option { } } -/// Returns whether we need to also compile the standard library when compiling the runtime. -fn build_std_required() -> bool { - let default = runtime_target() == RuntimeTarget::Wasm; - - crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(default) -} - #[derive(Copy, Clone, PartialEq, Eq)] enum RuntimeTarget { Wasm, @@ -423,36 +385,55 @@ enum RuntimeTarget { } impl RuntimeTarget { - fn rustc_target(self) -> &'static str { + /// Creates a new instance. + fn new() -> Self { + let Some(value) = env::var_os(RUNTIME_TARGET) else { + return Self::Wasm; + }; + + if value == "wasm" { + Self::Wasm + } else if value == "riscv" { + Self::Riscv + } else { + build_helper::warning!( + "RUNTIME_TARGET environment variable must be set to either \"wasm\" or \"riscv\"" + ); + std::process::exit(1); + } + } + + /// Figures out the target parameter value for rustc. + fn rustc_target(self) -> String { match self { - RuntimeTarget::Wasm => "wasm32-unknown-unknown", - RuntimeTarget::Riscv => "riscv32ema-unknown-none-elf", + RuntimeTarget::Wasm => "wasm32-unknown-unknown".to_string(), + RuntimeTarget::Riscv => { + let path = polkavm_linker::target_json_32_path().expect("riscv not found"); + path.into_os_string().into_string().unwrap() + }, } } - fn build_subdirectory(self) -> &'static str { - // Keep the build directories separate so that when switching between - // the targets we won't trigger unnecessary rebuilds. + /// Figures out the target directory name used by cargo. + fn rustc_target_dir(self) -> &'static str { match self { - RuntimeTarget::Wasm => "wbuild", - RuntimeTarget::Riscv => "rbuild", + RuntimeTarget::Wasm => "wasm32-unknown-unknown", + RuntimeTarget::Riscv => "riscv32emac-unknown-none-polkavm", } } -} -fn runtime_target() -> RuntimeTarget { - let Some(value) = env::var_os(RUNTIME_TARGET) else { - return RuntimeTarget::Wasm; - }; + /// Figures out the build-std argument. + fn rustc_target_build_std(self) -> Option<&'static str> { + if !crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(true) { + return None; + } - if value == "wasm" { - RuntimeTarget::Wasm - } else if value == "riscv" { - RuntimeTarget::Riscv - } else { - build_helper::warning!( - "the '{RUNTIME_TARGET}' environment variable has an invalid value; it must be either 'wasm' or 'riscv'" - ); - std::process::exit(1); + // This is a nightly-only flag. + let arg = match self { + RuntimeTarget::Wasm => "build-std", + RuntimeTarget::Riscv => "build-std=core,alloc", + }; + + Some(arg) } } diff --git a/substrate/utils/wasm-builder/src/prerequisites.rs b/substrate/utils/wasm-builder/src/prerequisites.rs index 4de6b87f618d..9abfd1725237 100644 --- a/substrate/utils/wasm-builder/src/prerequisites.rs +++ b/substrate/utils/wasm-builder/src/prerequisites.rs @@ -196,11 +196,14 @@ fn check_wasm_toolchain_installed( error, colorize_aux_message(&"-".repeat(60)), )) - } + }; } let version = dummy_crate.get_rustc_version(); - if crate::build_std_required() { + + let target = RuntimeTarget::new(); + assert!(target == RuntimeTarget::Wasm); + if target.rustc_target_build_std().is_some() { if let Some(sysroot) = dummy_crate.get_sysroot() { let src_path = Path::new(sysroot.trim()).join("lib").join("rustlib").join("src").join("rust"); diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 26edd2ea1f22..6530e4c22fb9 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -109,6 +109,15 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { crate_metadata } +/// Keep the build directories separate so that when switching between the +/// targets we won't trigger unnecessary rebuilds. +fn build_subdirectory(target: RuntimeTarget) -> &'static str { + match target { + RuntimeTarget::Wasm => "wbuild", + RuntimeTarget::Riscv => "rbuild", + } +} + /// Creates the WASM project, compiles the WASM binary and compacts the WASM binary. /// /// # Returns @@ -125,7 +134,7 @@ pub(crate) fn create_and_compile( #[cfg(feature = "metadata-hash")] enable_metadata_hash: Option, ) -> (Option, WasmBinaryBloaty) { let runtime_workspace_root = get_wasm_workspace_root(); - let runtime_workspace = runtime_workspace_root.join(target.build_subdirectory()); + let runtime_workspace = runtime_workspace_root.join(build_subdirectory(target)); let crate_metadata = crate_metadata(orig_project_cargo_toml); @@ -770,7 +779,7 @@ impl BuildConfiguration { .collect::>() .iter() .rev() - .take_while(|c| c.as_os_str() != target.build_subdirectory()) + .take_while(|c| c.as_os_str() != build_subdirectory(target)) .last() .expect("We put the runtime project within a `target/.../[rw]build` path; qed") .as_os_str() @@ -841,9 +850,7 @@ fn build_bloaty_blob( "-C target-cpu=mvp -C target-feature=-sign-ext -C link-arg=--export-table ", ); }, - RuntimeTarget::Riscv => { - rustflags.push_str("-C target-feature=+lui-addi-fusion -C relocation-model=pie -C link-arg=--emit-relocs -C link-arg=--unique "); - }, + RuntimeTarget::Riscv => (), } rustflags.push_str(default_rustflags); @@ -907,10 +914,9 @@ fn build_bloaty_blob( // // So here we force the compiler to also compile the standard library crates for us // to make sure that they also only use the MVP features. - if crate::build_std_required() { - // Unfortunately this is still a nightly-only flag, but FWIW it is pretty widely used - // so it's unlikely to break without a replacement. - build_cmd.arg("-Z").arg("build-std"); + if let Some(arg) = target.rustc_target_build_std() { + build_cmd.arg("-Z").arg(arg); + if !cargo_cmd.supports_nightly_features() { build_cmd.env("RUSTC_BOOTSTRAP", "1"); } @@ -934,7 +940,7 @@ fn build_bloaty_blob( let blob_name = get_blob_name(target, &manifest_path); let target_directory = project .join("target") - .join(target.rustc_target()) + .join(target.rustc_target_dir()) .join(blob_build_profile.directory()); match target { RuntimeTarget::Riscv => { @@ -968,7 +974,7 @@ fn build_bloaty_blob( }, }; - std::fs::write(&polkavm_path, program.as_bytes()) + std::fs::write(&polkavm_path, program) .expect("writing the blob to a file always works"); } diff --git a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl index bc587b044774..cca1f544b350 100644 --- a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl +++ b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.zndsl @@ -35,7 +35,10 @@ bob: reports block height is at least {{DB_BLOCK_HEIGHT}} within 10 seconds alice: reports substrate_beefy_best_block is at least {{200*180/6}} within 180 seconds bob: reports substrate_beefy_best_block is at least {{200*180/6}} within 180 seconds -alice: count of log lines containing "error" is 0 within 10 seconds +# Validators started without public addresses must emit an error. +# Double check the error is the expected one. +alice: log line matches "No public addresses configured and no global listen addresses found" within 60 seconds +alice: count of log lines containing "error" is 1 within 10 seconds bob: count of log lines containing "verification failed" is 0 within 10 seconds # new blocks were built diff --git a/templates/minimal/README.md b/templates/minimal/README.md index cf43d71d8849..22f396c243ef 100644 --- a/templates/minimal/README.md +++ b/templates/minimal/README.md @@ -105,12 +105,11 @@ Omni Node, nonetheless. #### Run Omni Node -Start Omni Node with manual seal (3 seconds block times), minimal template runtime based -chain spec. We'll use `--tmp` flag to start the node with its configurations stored in a -temporary directory, which will be deleted at the end of the process. +Start Omni Node in development mode (sets up block production and finalization based on manual seal, +sealing a new block every 3 seconds), with a minimal template runtime chain spec. ```sh -polkadot-omni-node --chain --dev-block-time 3000 --tmp +polkadot-omni-node --chain --dev ``` ### Minimal Template Node @@ -160,7 +159,7 @@ Then make the changes in the network specification like so: # ... chain = "dev" chain_spec_path = "" -default_args = ["--dev-block-time 3000"] +default_args = ["--dev"] # .. ``` diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 956efca34532..a2a999f02671 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -14,15 +14,15 @@ build = "build.rs" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -docify = { workspace = true } clap = { features = ["derive"], workspace = true } +docify = { workspace = true } futures = { features = ["thread-pool"], workspace = true } futures-timer = { workspace = true } jsonrpsee = { features = ["server"], workspace = true } serde_json = { workspace = true, default-features = true } -polkadot-sdk = { workspace = true, features = ["experimental", "node"] } minimal-template-runtime = { workspace = true } +polkadot-sdk = { workspace = true, features = ["experimental", "node"] } [build-dependencies] polkadot-sdk = { workspace = true, features = ["substrate-build-script-utils"] } diff --git a/templates/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs index f9a9d1e0f3cf..5988dbf3ce6e 100644 --- a/templates/minimal/node/src/service.rs +++ b/templates/minimal/node/src/service.rs @@ -21,9 +21,7 @@ use minimal_template_runtime::{interface::OpaqueBlock as Block, RuntimeApi}; use polkadot_sdk::{ sc_client_api::backend::Backend, sc_executor::WasmExecutor, - sc_service::{ - build_polkadot_syncing_strategy, error::Error as ServiceError, Configuration, TaskManager, - }, + sc_service::{error::Error as ServiceError, Configuration, TaskManager}, sc_telemetry::{Telemetry, TelemetryWorker}, sc_transaction_pool_api::OffchainTransactionPoolFactory, sp_runtime::traits::Block as BlockT, @@ -124,7 +122,7 @@ pub fn new_full::Ha other: mut telemetry, } = new_partial(&config)?; - let mut net_config = sc_network::config::FullNetworkConfiguration::< + let net_config = sc_network::config::FullNetworkConfiguration::< Block, ::Hash, Network, @@ -136,26 +134,16 @@ pub fn new_full::Ha config.prometheus_config.as_ref().map(|cfg| &cfg.registry), ); - let syncing_strategy = build_polkadot_syncing_strategy( - config.protocol_id(), - config.chain_spec.fork_id(), - &mut net_config, - None, - client.clone(), - &task_manager.spawn_handle(), - config.prometheus_config.as_ref().map(|config| &config.registry), - )?; - - let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, + net_config, client: client.clone(), transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), import_queue, - net_config, block_announce_validator_builder: None, - syncing_strategy, + warp_sync_config: None, block_relay: None, metrics, })?; @@ -276,6 +264,5 @@ pub fn new_full::Ha _ => {}, } - network_starter.start_network(); Ok(task_manager) } diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index 9a02d4daeaac..e11ce0e9955c 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -14,11 +14,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } polkadot-sdk = { workspace = true, default-features = false, features = [ "experimental", "runtime", ] } +scale-info = { features = ["derive"], workspace = true } [features] diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index b803c74539ef..1554e92c0bf5 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -11,7 +11,6 @@ publish = false [dependencies] codec = { workspace = true } -scale-info = { workspace = true } polkadot-sdk = { workspace = true, features = [ "pallet-balances", "pallet-sudo", @@ -20,6 +19,7 @@ polkadot-sdk = { workspace = true, features = [ "pallet-transaction-payment-rpc-runtime-api", "runtime", ] } +scale-info = { workspace = true } serde_json = { workspace = true, default-features = false, features = ["alloc"] } # local pallet templates diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 304e50af2508..72eded5bfd13 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -41,7 +41,7 @@ pub mod genesis_config_presets { use super::*; use crate::{ interface::{Balance, MinimumBalance}, - sp_keyring::AccountKeyring, + sp_keyring::Sr25519Keyring, BalancesConfig, RuntimeGenesisConfig, SudoConfig, }; @@ -51,23 +51,20 @@ pub mod genesis_config_presets { /// Returns a development genesis config preset. pub fn development_config_genesis() -> Value { let endowment = >::get().max(1) * 1000; - let config = RuntimeGenesisConfig { + frame_support::build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { - balances: AccountKeyring::iter() + balances: Sr25519Keyring::iter() .map(|a| (a.to_account_id(), endowment)) .collect::>(), }, - sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.to_account_id()) }, + }) } /// Get the set of the available genesis config presets. pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => development_config_genesis(), + let patch = match id.as_ref() { + sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(), _ => return None, }; Some( @@ -86,8 +83,8 @@ pub mod genesis_config_presets { /// The runtime version. #[runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("minimal-template-runtime"), - impl_name: create_runtime_str!("minimal-template-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"), + impl_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"), authoring_version: 1, spec_version: 0, impl_version: 1, diff --git a/templates/minimal/zombienet-omni-node.toml b/templates/minimal/zombienet-omni-node.toml index 33b0fceba68c..acd5b121c674 100644 --- a/templates/minimal/zombienet-omni-node.toml +++ b/templates/minimal/zombienet-omni-node.toml @@ -2,7 +2,7 @@ default_command = "polkadot-omni-node" chain = "dev" chain_spec_path = "" -default_args = ["--dev-block-time 3000"] +default_args = ["--dev"] [[relaychain.nodes]] name = "alice" diff --git a/templates/parachain/README.md b/templates/parachain/README.md index 65a6979041f2..c1e333df9e9e 100644 --- a/templates/parachain/README.md +++ b/templates/parachain/README.md @@ -27,6 +27,7 @@ - [Connect with the Polkadot-JS Apps Front-End](#connect-with-the-polkadot-js-apps-front-end) - [Takeaways](#takeaways) +- [Runtime development](#runtime-development) - [Contributing](#contributing) - [Getting Help](#getting-help) @@ -107,13 +108,11 @@ with the relay chain ID where this instantiation of parachain-template will conn #### Run Omni Node -Start Omni Node with the generated chain spec. We'll start it development mode (without a relay chain config), -with a temporary directory for configuration (given `--tmp`), and block production set to create a block with -every second. +Start Omni Node with the generated chain spec. We'll start it in development mode (without a relay chain config), producing +and finalizing blocks based on manual seal, configured below to seal a block with each second. ```bash -polkadot-omni-node --chain --tmp --dev-block-time 1000 - +polkadot-omni-node --chain --dev --dev-block-time 1000 ``` However, such a setup is not close to what would run in production, and for that we need to setup a local @@ -197,6 +196,37 @@ Development parachains: - 💰 Are preconfigured with a genesis state that includes several prefunded development accounts. - 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts. +## Runtime development + +We recommend using [`chopsticks`](https://github.com/AcalaNetwork/chopsticks) when the focus is more on the runtime +development and `OmniNode` is enough as is. + +### Install chopsticks + +To use `chopsticks`, please install the latest version according to the installation [guide](https://github.com/AcalaNetwork/chopsticks?tab=readme-ov-file#install). + +### Build a raw chain spec + +Build the `parachain-template-runtime` as mentioned before in this guide and use `chain-spec-builder` +again but this time by passing `--raw-storage` flag: + +```sh +chain-spec-builder create --raw-storage --relay-chain "rococo-local" --para-id 1000 --runtime \ + target/release/wbuild/parachain-template-runtime/parachain_template_runtime.wasm named-preset development +``` + +### Start `chopsticks` with the chain spec + +```sh +npx @acala-network/chopsticks@latest --chain-spec +``` + +### Alternatives + +`OmniNode` can be still used for runtime development if using the `--dev` flag, while `parachain-template-node` doesn't +support it at this moment. It can still be used to test a runtime in a full setup where it is started alongside a +relay chain network (see [Parachain Template node](#parachain-template-node) setup). + ## Contributing - 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk). diff --git a/templates/parachain/node/Cargo.toml b/templates/parachain/node/Cargo.toml index ba5f1212b79c..ec4b13b184fc 100644 --- a/templates/parachain/node/Cargo.toml +++ b/templates/parachain/node/Cargo.toml @@ -12,22 +12,22 @@ build = "build.rs" [dependencies] clap = { features = ["derive"], workspace = true } -log = { workspace = true, default-features = true } codec = { workspace = true, default-features = true } -serde = { features = ["derive"], workspace = true, default-features = true } -jsonrpsee = { features = ["server"], workspace = true } +color-print = { workspace = true } +docify = { workspace = true } futures = { workspace = true } +jsonrpsee = { features = ["server"], workspace = true } +log = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -docify = { workspace = true } -color-print = { workspace = true } polkadot-sdk = { workspace = true, features = ["node"] } parachain-template-runtime = { workspace = true } # Substrate -sc-tracing = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } [build-dependencies] polkadot-sdk = { workspace = true, features = ["substrate-build-script-utils"] } diff --git a/templates/parachain/node/src/chain_spec.rs b/templates/parachain/node/src/chain_spec.rs index 55a099dd022b..d4b3a41b8969 100644 --- a/templates/parachain/node/src/chain_spec.rs +++ b/templates/parachain/node/src/chain_spec.rs @@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize}; /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; +/// The relay chain that you want to configure this parachain to connect to. +pub const RELAY_CHAIN: &str = "rococo-local"; /// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] @@ -35,16 +37,13 @@ pub fn development_chain_spec() -> ChainSpec { ChainSpec::builder( runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: "rococo-local".into(), - // You MUST set this to the correct network! - para_id: 1000, - }, + Extensions { relay_chain: RELAY_CHAIN.into(), para_id: runtime::PARACHAIN_ID }, ) .with_name("Development") .with_id("dev") .with_chain_type(ChainType::Development) .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) + .with_properties(properties) .build() } @@ -58,11 +57,7 @@ pub fn local_chain_spec() -> ChainSpec { #[allow(deprecated)] ChainSpec::builder( runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: "rococo-local".into(), - // You MUST set this to the correct network! - para_id: 1000, - }, + Extensions { relay_chain: RELAY_CHAIN.into(), para_id: runtime::PARACHAIN_ID }, ) .with_name("Local Testnet") .with_id("local_testnet") diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 57ffcb9049d8..8c526317283e 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -270,7 +270,7 @@ pub async fn start_parachain_node( // NOTE: because we use Aura here explicitly, we can use `CollatorSybilResistance::Resistant` // when starting the network. - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = build_network(BuildNetworkParams { parachain_config: ¶chain_config, net_config, @@ -406,7 +406,5 @@ pub async fn start_parachain_node( )?; } - start_network.start_network(); - Ok((task_manager, client)) } diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index f1d33b4143e4..9a0548106ed7 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -13,17 +13,17 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -substrate-wasm-builder = { optional = true, workspace = true, default-features = true } docify = { workspace = true } +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] codec = { features = ["derive"], workspace = true } +docify = { workspace = true } hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } -smallvec = { workspace = true, default-features = true } -docify = { workspace = true } serde_json = { workspace = true, default-features = false, features = ["alloc"] } +smallvec = { workspace = true, default-features = true } # Local pallet-parachain-template = { workspace = true } diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs index eba9293a67ba..05a508ca655f 100644 --- a/templates/parachain/runtime/src/apis.rs +++ b/templates/parachain/runtime/src/apis.rs @@ -261,7 +261,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; use super::*; diff --git a/templates/parachain/runtime/src/genesis_config_presets.rs b/templates/parachain/runtime/src/genesis_config_presets.rs index 9091db357005..f1b24e437247 100644 --- a/templates/parachain/runtime/src/genesis_config_presets.rs +++ b/templates/parachain/runtime/src/genesis_config_presets.rs @@ -8,6 +8,7 @@ use alloc::{vec, vec::Vec}; use polkadot_sdk::{staging_xcm as xcm, *}; use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; use parachains_common::AuraId; use serde_json::Value; use sp_genesis_builder::PresetId; @@ -15,8 +16,8 @@ use sp_keyring::Sr25519Keyring; /// The default XCM version to set in genesis config. const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -/// Parachain id used for gensis config presets of parachain template. -const PARACHAIN_ID: u32 = 1000; +/// Parachain id used for genesis config presets of parachain template. +pub const PARACHAIN_ID: u32 = 1000; /// Generate the session keys from individual elements. /// @@ -31,7 +32,7 @@ fn testnet_genesis( root: AccountId, id: ParaId, ) -> Value { - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -39,11 +40,10 @@ fn testnet_genesis( .map(|k| (k, 1u128 << 60)) .collect::>(), }, - parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + parachain_info: ParachainInfoConfig { parachain_id: id }, collator_selection: CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), candidacy_bond: EXISTENTIAL_DEPOSIT * 16, - ..Default::default() }, session: SessionConfig { keys: invulnerables @@ -56,17 +56,10 @@ fn testnet_genesis( ) }) .collect::>(), - ..Default::default() - }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() }, + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, sudo: SudoConfig { key: Some(root) }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + }) } fn local_testnet_genesis() -> Value { @@ -97,9 +90,9 @@ fn development_config_genesis() -> Value { /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => local_testnet_genesis(), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => development_config_genesis(), + let patch = match id.as_ref() { + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => local_testnet_genesis(), + sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(), _ => return None, }; Some( diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 78dc38ef427f..9669237af785 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -20,7 +20,7 @@ use smallvec::smallvec; use polkadot_sdk::{staging_parachain_info as parachain_info, *}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{BlakeTwo256, IdentifyAccount, Verify}, MultiSignature, }; @@ -33,6 +33,7 @@ use frame_support::weights::{ constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; +pub use genesis_config_presets::PARACHAIN_ID; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; @@ -164,8 +165,8 @@ impl_opaque_keys! { #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("parachain-template-runtime"), - impl_name: create_runtime_str!("parachain-template-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("parachain-template-runtime"), + impl_name: alloc::borrow::Cow::Borrowed("parachain-template-runtime"), authoring_version: 1, spec_version: 1, impl_version: 0, diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index 8a3c7d0ac780..90f576c88c23 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -17,41 +17,41 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { features = ["derive"], workspace = true } futures = { features = ["thread-pool"], workspace = true } -serde_json = { workspace = true, default-features = true } jsonrpsee = { features = ["server"], workspace = true } +serde_json = { workspace = true, default-features = true } # substrate client +sc-basic-authorship = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +sc-consensus-aura = { workspace = true, default-features = true } +sc-consensus-grandpa = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } +sc-offchain = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } -sc-offchain = { workspace = true, default-features = true } -sc-consensus-aura = { workspace = true, default-features = true } sp-consensus-aura = { workspace = true, default-features = true } -sc-consensus = { workspace = true, default-features = true } -sc-consensus-grandpa = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sc-basic-authorship = { workspace = true, default-features = true } # substrate primitives -sp-runtime = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } -sp-inherents = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } sp-block-builder = { workspace = true, default-features = true } +sp-blockchain = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } # frame and pallets -frame-system = { workspace = true, default-features = true } frame-metadata-hash-extension = { workspace = true, default-features = true } +frame-system = { workspace = true, default-features = true } pallet-transaction-payment = { workspace = true, default-features = true } pallet-transaction-payment-rpc = { workspace = true, default-features = true } substrate-frame-rpc-system = { workspace = true, default-features = true } diff --git a/templates/solochain/node/src/service.rs b/templates/solochain/node/src/service.rs index 2524906fd508..79d97fbab8df 100644 --- a/templates/solochain/node/src/service.rs +++ b/templates/solochain/node/src/service.rs @@ -4,10 +4,7 @@ use futures::FutureExt; use sc_client_api::{Backend, BlockBackend}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; use sc_consensus_grandpa::SharedVoterState; -use sc_service::{ - build_polkadot_syncing_strategy, error::Error as ServiceError, Configuration, TaskManager, - WarpSyncConfig, -}; +use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncConfig}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use solochain_template_runtime::{self, apis::RuntimeApi, opaque::Block}; @@ -172,17 +169,7 @@ pub fn new_full< Vec::default(), )); - let syncing_strategy = build_polkadot_syncing_strategy( - config.protocol_id(), - config.chain_spec.fork_id(), - &mut net_config, - Some(WarpSyncConfig::WithProvider(warp_sync)), - client.clone(), - &task_manager.spawn_handle(), - config.prometheus_config.as_ref().map(|config| &config.registry), - )?; - - let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = + let (network, system_rpc_tx, tx_handler_controller, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, net_config, @@ -191,7 +178,7 @@ pub fn new_full< spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - syncing_strategy, + warp_sync_config: Some(WarpSyncConfig::WithProvider(warp_sync)), block_relay: None, metrics, })?; @@ -342,6 +329,5 @@ pub fn new_full< ); } - network_starter.start_network(); Ok(task_manager) } diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 837849e844b1..1cff982fbf3c 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -23,11 +23,11 @@ scale-info = { features = [ serde_json = { workspace = true, default-features = false, features = ["alloc"] } # frame +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } frame-support = { features = ["experimental"], workspace = true } frame-system = { workspace = true } frame-try-runtime = { optional = true, workspace = true } -frame-executive = { workspace = true } -frame-metadata-hash-extension = { workspace = true } # frame pallets pallet-aura = { workspace = true } @@ -46,11 +46,12 @@ sp-consensus-aura = { features = [ sp-consensus-grandpa = { features = [ "serde", ], workspace = true } -sp-keyring = { workspace = true } sp-core = { features = [ "serde", ], workspace = true } +sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } +sp-keyring = { workspace = true } sp-offchain = { workspace = true } sp-runtime = { features = [ "serde", @@ -61,7 +62,6 @@ sp-transaction-pool = { workspace = true } sp-version = { features = [ "serde", ], workspace = true } -sp-genesis-builder = { workspace = true } # RPC related frame-system-rpc-runtime-api = { workspace = true } diff --git a/templates/solochain/runtime/src/apis.rs b/templates/solochain/runtime/src/apis.rs index f21eaa344431..06c645fa0c53 100644 --- a/templates/solochain/runtime/src/apis.rs +++ b/templates/solochain/runtime/src/apis.rs @@ -237,7 +237,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { + ) -> Result, alloc::string::String> { use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch}; use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; diff --git a/templates/solochain/runtime/src/genesis_config_presets.rs b/templates/solochain/runtime/src/genesis_config_presets.rs index 693ae5c2221f..6af8dc9cd18a 100644 --- a/templates/solochain/runtime/src/genesis_config_presets.rs +++ b/templates/solochain/runtime/src/genesis_config_presets.rs @@ -17,11 +17,12 @@ use crate::{AccountId, BalancesConfig, RuntimeGenesisConfig, SudoConfig}; use alloc::{vec, vec::Vec}; +use frame_support::build_struct_json_patch; use serde_json::Value; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_genesis_builder::{self, PresetId}; -use sp_keyring::AccountKeyring; +use sp_keyring::Sr25519Keyring; // Returns the genesis config presets populated with given parameters. fn testnet_genesis( @@ -29,7 +30,7 @@ fn testnet_genesis( endowed_accounts: Vec, root: AccountId, ) -> Value { - let config = RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts .iter() @@ -42,13 +43,9 @@ fn testnet_genesis( }, grandpa: pallet_grandpa::GenesisConfig { authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::>(), - ..Default::default() }, sudo: SudoConfig { key: Some(root) }, - ..Default::default() - }; - - serde_json::to_value(config).expect("Could not build genesis config.") + }) } /// Return the development genesis config. @@ -59,12 +56,12 @@ pub fn development_config_genesis() -> Value { sp_keyring::Ed25519Keyring::Alice.public().into(), )], vec![ - AccountKeyring::Alice.to_account_id(), - AccountKeyring::Bob.to_account_id(), - AccountKeyring::AliceStash.to_account_id(), - AccountKeyring::BobStash.to_account_id(), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], - sp_keyring::AccountKeyring::Alice.to_account_id(), + sp_keyring::Sr25519Keyring::Alice.to_account_id(), ) } @@ -81,19 +78,19 @@ pub fn local_config_genesis() -> Value { sp_keyring::Ed25519Keyring::Bob.public().into(), ), ], - AccountKeyring::iter() - .filter(|v| v != &AccountKeyring::One && v != &AccountKeyring::Two) + Sr25519Keyring::iter() + .filter(|v| v != &Sr25519Keyring::One && v != &Sr25519Keyring::Two) .map(|v| v.to_account_id()) .collect::>(), - AccountKeyring::Alice.to_account_id(), + Sr25519Keyring::Alice.to_account_id(), ) } /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.try_into() { - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => development_config_genesis(), - Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => local_config_genesis(), + let patch = match id.as_ref() { + sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(), + sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => local_config_genesis(), _ => return None, }; Some( diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index f2eb49592be9..ae0ea16ae42e 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -11,7 +11,7 @@ pub mod configs; extern crate alloc; use alloc::vec::Vec; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + generic, impl_opaque_keys, traits::{BlakeTwo256, IdentifyAccount, Verify}, MultiAddress, MultiSignature, }; @@ -61,8 +61,8 @@ impl_opaque_keys! { // https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("solochain-template-runtime"), - impl_name: create_runtime_str!("solochain-template-runtime"), + spec_name: alloc::borrow::Cow::Borrowed("solochain-template-runtime"), + impl_name: alloc::borrow::Cow::Borrowed("solochain-template-runtime"), authoring_version: 1, // The version of the runtime specification. A full node will not attempt to use its native // runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, diff --git a/templates/zombienet/Cargo.toml b/templates/zombienet/Cargo.toml index f29325dbe6a9..805e4ddbcee2 100644 --- a/templates/zombienet/Cargo.toml +++ b/templates/zombienet/Cargo.toml @@ -10,10 +10,10 @@ edition.workspace = true publish = false [dependencies] +anyhow = { workspace = true } env_logger = { workspace = true } log = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread"] } -anyhow = { workspace = true } zombienet-sdk = { workspace = true } [features] diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 7f50658c4e16..f36d39d63f6a 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -120,7 +120,6 @@ std = [ "pallet-recovery?/std", "pallet-referenda?/std", "pallet-remark?/std", - "pallet-revive-fixtures?/std", "pallet-revive-mock-network?/std", "pallet-revive?/std", "pallet-root-offences?/std", @@ -363,6 +362,7 @@ runtime-benchmarks = [ "staging-node-inspect?/runtime-benchmarks", "staging-xcm-builder?/runtime-benchmarks", "staging-xcm-executor?/runtime-benchmarks", + "staging-xcm?/runtime-benchmarks", "xcm-runtime-apis?/runtime-benchmarks", ] try-runtime = [ @@ -541,7 +541,7 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] -runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-fixtures", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] +runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] runtime = [ "frame-benchmarking", "frame-benchmarking-pallet-pov", @@ -605,7 +605,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-eth-rpc", "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-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", "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-eth-rpc", "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-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", "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-runtime-utilities", "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", @@ -617,1885 +617,1891 @@ workspace = true [package.authors] workspace = true +[package.homepage] +workspace = true + +[package.repository] +workspace = true + [dependencies.assets-common] -path = "../cumulus/parachains/runtimes/assets/common" default-features = false optional = true +path = "../cumulus/parachains/runtimes/assets/common" [dependencies.binary-merkle-tree] -path = "../substrate/utils/binary-merkle-tree" default-features = false optional = true +path = "../substrate/utils/binary-merkle-tree" [dependencies.bp-header-chain] -path = "../bridges/primitives/header-chain" default-features = false optional = true +path = "../bridges/primitives/header-chain" [dependencies.bp-messages] -path = "../bridges/primitives/messages" default-features = false optional = true +path = "../bridges/primitives/messages" [dependencies.bp-parachains] -path = "../bridges/primitives/parachains" default-features = false optional = true +path = "../bridges/primitives/parachains" [dependencies.bp-polkadot] -path = "../bridges/chains/chain-polkadot" default-features = false optional = true +path = "../bridges/chains/chain-polkadot" [dependencies.bp-polkadot-core] -path = "../bridges/primitives/polkadot-core" default-features = false optional = true +path = "../bridges/primitives/polkadot-core" [dependencies.bp-relayers] -path = "../bridges/primitives/relayers" default-features = false optional = true +path = "../bridges/primitives/relayers" [dependencies.bp-runtime] -path = "../bridges/primitives/runtime" default-features = false optional = true +path = "../bridges/primitives/runtime" [dependencies.bp-test-utils] -path = "../bridges/primitives/test-utils" default-features = false optional = true +path = "../bridges/primitives/test-utils" [dependencies.bp-xcm-bridge-hub] -path = "../bridges/primitives/xcm-bridge-hub" default-features = false optional = true +path = "../bridges/primitives/xcm-bridge-hub" [dependencies.bp-xcm-bridge-hub-router] -path = "../bridges/primitives/xcm-bridge-hub-router" default-features = false optional = true +path = "../bridges/primitives/xcm-bridge-hub-router" [dependencies.bridge-hub-common] -path = "../cumulus/parachains/runtimes/bridge-hubs/common" default-features = false optional = true +path = "../cumulus/parachains/runtimes/bridge-hubs/common" [dependencies.bridge-runtime-common] -path = "../bridges/bin/runtime-common" default-features = false optional = true +path = "../bridges/bin/runtime-common" [dependencies.cumulus-pallet-aura-ext] -path = "../cumulus/pallets/aura-ext" default-features = false optional = true +path = "../cumulus/pallets/aura-ext" [dependencies.cumulus-pallet-dmp-queue] -path = "../cumulus/pallets/dmp-queue" default-features = false optional = true +path = "../cumulus/pallets/dmp-queue" [dependencies.cumulus-pallet-parachain-system] -path = "../cumulus/pallets/parachain-system" default-features = false optional = true +path = "../cumulus/pallets/parachain-system" [dependencies.cumulus-pallet-parachain-system-proc-macro] -path = "../cumulus/pallets/parachain-system/proc-macro" default-features = false optional = true +path = "../cumulus/pallets/parachain-system/proc-macro" [dependencies.cumulus-pallet-session-benchmarking] -path = "../cumulus/pallets/session-benchmarking" default-features = false optional = true +path = "../cumulus/pallets/session-benchmarking" [dependencies.cumulus-pallet-solo-to-para] -path = "../cumulus/pallets/solo-to-para" default-features = false optional = true +path = "../cumulus/pallets/solo-to-para" [dependencies.cumulus-pallet-xcm] -path = "../cumulus/pallets/xcm" default-features = false optional = true +path = "../cumulus/pallets/xcm" [dependencies.cumulus-pallet-xcmp-queue] -path = "../cumulus/pallets/xcmp-queue" default-features = false optional = true +path = "../cumulus/pallets/xcmp-queue" [dependencies.cumulus-ping] -path = "../cumulus/parachains/pallets/ping" default-features = false optional = true +path = "../cumulus/parachains/pallets/ping" [dependencies.cumulus-primitives-aura] -path = "../cumulus/primitives/aura" default-features = false optional = true +path = "../cumulus/primitives/aura" [dependencies.cumulus-primitives-core] -path = "../cumulus/primitives/core" default-features = false optional = true +path = "../cumulus/primitives/core" [dependencies.cumulus-primitives-parachain-inherent] -path = "../cumulus/primitives/parachain-inherent" default-features = false optional = true +path = "../cumulus/primitives/parachain-inherent" [dependencies.cumulus-primitives-proof-size-hostfunction] -path = "../cumulus/primitives/proof-size-hostfunction" default-features = false optional = true +path = "../cumulus/primitives/proof-size-hostfunction" [dependencies.cumulus-primitives-storage-weight-reclaim] -path = "../cumulus/primitives/storage-weight-reclaim" default-features = false optional = true +path = "../cumulus/primitives/storage-weight-reclaim" [dependencies.cumulus-primitives-timestamp] -path = "../cumulus/primitives/timestamp" default-features = false optional = true +path = "../cumulus/primitives/timestamp" [dependencies.cumulus-primitives-utility] -path = "../cumulus/primitives/utility" default-features = false optional = true +path = "../cumulus/primitives/utility" [dependencies.frame-benchmarking] -path = "../substrate/frame/benchmarking" default-features = false optional = true +path = "../substrate/frame/benchmarking" [dependencies.frame-benchmarking-pallet-pov] -path = "../substrate/frame/benchmarking/pov" default-features = false optional = true +path = "../substrate/frame/benchmarking/pov" [dependencies.frame-election-provider-solution-type] -path = "../substrate/frame/election-provider-support/solution-type" default-features = false optional = true +path = "../substrate/frame/election-provider-support/solution-type" [dependencies.frame-election-provider-support] -path = "../substrate/frame/election-provider-support" default-features = false optional = true +path = "../substrate/frame/election-provider-support" [dependencies.frame-executive] -path = "../substrate/frame/executive" default-features = false optional = true +path = "../substrate/frame/executive" [dependencies.frame-metadata-hash-extension] -path = "../substrate/frame/metadata-hash-extension" default-features = false optional = true +path = "../substrate/frame/metadata-hash-extension" [dependencies.frame-support] -path = "../substrate/frame/support" default-features = false optional = true +path = "../substrate/frame/support" [dependencies.frame-support-procedural] -path = "../substrate/frame/support/procedural" default-features = false optional = true +path = "../substrate/frame/support/procedural" [dependencies.frame-support-procedural-tools-derive] -path = "../substrate/frame/support/procedural/tools/derive" default-features = false optional = true +path = "../substrate/frame/support/procedural/tools/derive" [dependencies.frame-system] -path = "../substrate/frame/system" default-features = false optional = true +path = "../substrate/frame/system" [dependencies.frame-system-benchmarking] -path = "../substrate/frame/system/benchmarking" default-features = false optional = true +path = "../substrate/frame/system/benchmarking" [dependencies.frame-system-rpc-runtime-api] -path = "../substrate/frame/system/rpc/runtime-api" default-features = false optional = true +path = "../substrate/frame/system/rpc/runtime-api" [dependencies.frame-try-runtime] -path = "../substrate/frame/try-runtime" default-features = false optional = true +path = "../substrate/frame/try-runtime" [dependencies.pallet-alliance] -path = "../substrate/frame/alliance" default-features = false optional = true +path = "../substrate/frame/alliance" [dependencies.pallet-asset-conversion] -path = "../substrate/frame/asset-conversion" default-features = false optional = true +path = "../substrate/frame/asset-conversion" [dependencies.pallet-asset-conversion-ops] -path = "../substrate/frame/asset-conversion/ops" default-features = false optional = true +path = "../substrate/frame/asset-conversion/ops" [dependencies.pallet-asset-conversion-tx-payment] -path = "../substrate/frame/transaction-payment/asset-conversion-tx-payment" default-features = false optional = true +path = "../substrate/frame/transaction-payment/asset-conversion-tx-payment" [dependencies.pallet-asset-rate] -path = "../substrate/frame/asset-rate" default-features = false optional = true +path = "../substrate/frame/asset-rate" [dependencies.pallet-asset-tx-payment] -path = "../substrate/frame/transaction-payment/asset-tx-payment" default-features = false optional = true +path = "../substrate/frame/transaction-payment/asset-tx-payment" [dependencies.pallet-assets] -path = "../substrate/frame/assets" default-features = false optional = true +path = "../substrate/frame/assets" [dependencies.pallet-assets-freezer] -path = "../substrate/frame/assets-freezer" default-features = false optional = true +path = "../substrate/frame/assets-freezer" [dependencies.pallet-atomic-swap] -path = "../substrate/frame/atomic-swap" default-features = false optional = true +path = "../substrate/frame/atomic-swap" [dependencies.pallet-aura] -path = "../substrate/frame/aura" default-features = false optional = true +path = "../substrate/frame/aura" [dependencies.pallet-authority-discovery] -path = "../substrate/frame/authority-discovery" default-features = false optional = true +path = "../substrate/frame/authority-discovery" [dependencies.pallet-authorship] -path = "../substrate/frame/authorship" default-features = false optional = true +path = "../substrate/frame/authorship" [dependencies.pallet-babe] -path = "../substrate/frame/babe" default-features = false optional = true +path = "../substrate/frame/babe" [dependencies.pallet-bags-list] -path = "../substrate/frame/bags-list" default-features = false optional = true +path = "../substrate/frame/bags-list" [dependencies.pallet-balances] -path = "../substrate/frame/balances" default-features = false optional = true +path = "../substrate/frame/balances" [dependencies.pallet-beefy] -path = "../substrate/frame/beefy" default-features = false optional = true +path = "../substrate/frame/beefy" [dependencies.pallet-beefy-mmr] -path = "../substrate/frame/beefy-mmr" default-features = false optional = true +path = "../substrate/frame/beefy-mmr" [dependencies.pallet-bounties] -path = "../substrate/frame/bounties" default-features = false optional = true +path = "../substrate/frame/bounties" [dependencies.pallet-bridge-grandpa] -path = "../bridges/modules/grandpa" default-features = false optional = true +path = "../bridges/modules/grandpa" [dependencies.pallet-bridge-messages] -path = "../bridges/modules/messages" default-features = false optional = true +path = "../bridges/modules/messages" [dependencies.pallet-bridge-parachains] -path = "../bridges/modules/parachains" default-features = false optional = true +path = "../bridges/modules/parachains" [dependencies.pallet-bridge-relayers] -path = "../bridges/modules/relayers" default-features = false optional = true +path = "../bridges/modules/relayers" [dependencies.pallet-broker] -path = "../substrate/frame/broker" default-features = false optional = true +path = "../substrate/frame/broker" [dependencies.pallet-child-bounties] -path = "../substrate/frame/child-bounties" default-features = false optional = true +path = "../substrate/frame/child-bounties" [dependencies.pallet-collator-selection] -path = "../cumulus/pallets/collator-selection" default-features = false optional = true +path = "../cumulus/pallets/collator-selection" [dependencies.pallet-collective] -path = "../substrate/frame/collective" default-features = false optional = true +path = "../substrate/frame/collective" [dependencies.pallet-collective-content] -path = "../cumulus/parachains/pallets/collective-content" default-features = false optional = true +path = "../cumulus/parachains/pallets/collective-content" [dependencies.pallet-contracts] -path = "../substrate/frame/contracts" default-features = false optional = true +path = "../substrate/frame/contracts" [dependencies.pallet-contracts-proc-macro] -path = "../substrate/frame/contracts/proc-macro" default-features = false optional = true +path = "../substrate/frame/contracts/proc-macro" [dependencies.pallet-contracts-uapi] -path = "../substrate/frame/contracts/uapi" default-features = false optional = true +path = "../substrate/frame/contracts/uapi" [dependencies.pallet-conviction-voting] -path = "../substrate/frame/conviction-voting" default-features = false optional = true +path = "../substrate/frame/conviction-voting" [dependencies.pallet-core-fellowship] -path = "../substrate/frame/core-fellowship" default-features = false optional = true +path = "../substrate/frame/core-fellowship" [dependencies.pallet-delegated-staking] -path = "../substrate/frame/delegated-staking" default-features = false optional = true +path = "../substrate/frame/delegated-staking" [dependencies.pallet-democracy] -path = "../substrate/frame/democracy" default-features = false optional = true +path = "../substrate/frame/democracy" [dependencies.pallet-dev-mode] -path = "../substrate/frame/examples/dev-mode" default-features = false optional = true +path = "../substrate/frame/examples/dev-mode" [dependencies.pallet-election-provider-multi-phase] -path = "../substrate/frame/election-provider-multi-phase" default-features = false optional = true +path = "../substrate/frame/election-provider-multi-phase" [dependencies.pallet-election-provider-support-benchmarking] -path = "../substrate/frame/election-provider-support/benchmarking" default-features = false optional = true +path = "../substrate/frame/election-provider-support/benchmarking" [dependencies.pallet-elections-phragmen] -path = "../substrate/frame/elections-phragmen" default-features = false optional = true +path = "../substrate/frame/elections-phragmen" [dependencies.pallet-fast-unstake] -path = "../substrate/frame/fast-unstake" default-features = false optional = true +path = "../substrate/frame/fast-unstake" [dependencies.pallet-glutton] -path = "../substrate/frame/glutton" default-features = false optional = true +path = "../substrate/frame/glutton" [dependencies.pallet-grandpa] -path = "../substrate/frame/grandpa" default-features = false optional = true +path = "../substrate/frame/grandpa" [dependencies.pallet-identity] -path = "../substrate/frame/identity" default-features = false optional = true +path = "../substrate/frame/identity" [dependencies.pallet-im-online] -path = "../substrate/frame/im-online" default-features = false optional = true +path = "../substrate/frame/im-online" [dependencies.pallet-indices] -path = "../substrate/frame/indices" default-features = false optional = true +path = "../substrate/frame/indices" [dependencies.pallet-insecure-randomness-collective-flip] -path = "../substrate/frame/insecure-randomness-collective-flip" default-features = false optional = true +path = "../substrate/frame/insecure-randomness-collective-flip" [dependencies.pallet-lottery] -path = "../substrate/frame/lottery" default-features = false optional = true +path = "../substrate/frame/lottery" [dependencies.pallet-membership] -path = "../substrate/frame/membership" default-features = false optional = true +path = "../substrate/frame/membership" [dependencies.pallet-message-queue] -path = "../substrate/frame/message-queue" default-features = false optional = true +path = "../substrate/frame/message-queue" [dependencies.pallet-migrations] -path = "../substrate/frame/migrations" default-features = false optional = true +path = "../substrate/frame/migrations" [dependencies.pallet-mixnet] -path = "../substrate/frame/mixnet" default-features = false optional = true +path = "../substrate/frame/mixnet" [dependencies.pallet-mmr] -path = "../substrate/frame/merkle-mountain-range" default-features = false optional = true +path = "../substrate/frame/merkle-mountain-range" [dependencies.pallet-multisig] -path = "../substrate/frame/multisig" default-features = false optional = true +path = "../substrate/frame/multisig" [dependencies.pallet-nft-fractionalization] -path = "../substrate/frame/nft-fractionalization" default-features = false optional = true +path = "../substrate/frame/nft-fractionalization" [dependencies.pallet-nfts] -path = "../substrate/frame/nfts" default-features = false optional = true +path = "../substrate/frame/nfts" [dependencies.pallet-nfts-runtime-api] -path = "../substrate/frame/nfts/runtime-api" default-features = false optional = true +path = "../substrate/frame/nfts/runtime-api" [dependencies.pallet-nis] -path = "../substrate/frame/nis" default-features = false optional = true +path = "../substrate/frame/nis" [dependencies.pallet-node-authorization] -path = "../substrate/frame/node-authorization" default-features = false optional = true +path = "../substrate/frame/node-authorization" [dependencies.pallet-nomination-pools] -path = "../substrate/frame/nomination-pools" default-features = false optional = true +path = "../substrate/frame/nomination-pools" [dependencies.pallet-nomination-pools-benchmarking] -path = "../substrate/frame/nomination-pools/benchmarking" default-features = false optional = true +path = "../substrate/frame/nomination-pools/benchmarking" [dependencies.pallet-nomination-pools-runtime-api] -path = "../substrate/frame/nomination-pools/runtime-api" default-features = false optional = true +path = "../substrate/frame/nomination-pools/runtime-api" [dependencies.pallet-offences] -path = "../substrate/frame/offences" default-features = false optional = true +path = "../substrate/frame/offences" [dependencies.pallet-offences-benchmarking] -path = "../substrate/frame/offences/benchmarking" default-features = false optional = true +path = "../substrate/frame/offences/benchmarking" [dependencies.pallet-paged-list] -path = "../substrate/frame/paged-list" default-features = false optional = true +path = "../substrate/frame/paged-list" [dependencies.pallet-parameters] -path = "../substrate/frame/parameters" default-features = false optional = true +path = "../substrate/frame/parameters" [dependencies.pallet-preimage] -path = "../substrate/frame/preimage" default-features = false optional = true +path = "../substrate/frame/preimage" [dependencies.pallet-proxy] -path = "../substrate/frame/proxy" default-features = false optional = true +path = "../substrate/frame/proxy" [dependencies.pallet-ranked-collective] -path = "../substrate/frame/ranked-collective" default-features = false optional = true +path = "../substrate/frame/ranked-collective" [dependencies.pallet-recovery] -path = "../substrate/frame/recovery" default-features = false optional = true +path = "../substrate/frame/recovery" [dependencies.pallet-referenda] -path = "../substrate/frame/referenda" default-features = false optional = true +path = "../substrate/frame/referenda" [dependencies.pallet-remark] -path = "../substrate/frame/remark" default-features = false optional = true +path = "../substrate/frame/remark" [dependencies.pallet-revive] -path = "../substrate/frame/revive" -default-features = false -optional = true - -[dependencies.pallet-revive-fixtures] -path = "../substrate/frame/revive/fixtures" default-features = false optional = true +path = "../substrate/frame/revive" [dependencies.pallet-revive-proc-macro] -path = "../substrate/frame/revive/proc-macro" default-features = false optional = true +path = "../substrate/frame/revive/proc-macro" [dependencies.pallet-revive-uapi] -path = "../substrate/frame/revive/uapi" default-features = false optional = true +path = "../substrate/frame/revive/uapi" [dependencies.pallet-root-offences] -path = "../substrate/frame/root-offences" default-features = false optional = true +path = "../substrate/frame/root-offences" [dependencies.pallet-root-testing] -path = "../substrate/frame/root-testing" default-features = false optional = true +path = "../substrate/frame/root-testing" [dependencies.pallet-safe-mode] -path = "../substrate/frame/safe-mode" default-features = false optional = true +path = "../substrate/frame/safe-mode" [dependencies.pallet-salary] -path = "../substrate/frame/salary" default-features = false optional = true +path = "../substrate/frame/salary" [dependencies.pallet-scheduler] -path = "../substrate/frame/scheduler" default-features = false optional = true +path = "../substrate/frame/scheduler" [dependencies.pallet-scored-pool] -path = "../substrate/frame/scored-pool" default-features = false optional = true +path = "../substrate/frame/scored-pool" [dependencies.pallet-session] -path = "../substrate/frame/session" default-features = false optional = true +path = "../substrate/frame/session" [dependencies.pallet-session-benchmarking] -path = "../substrate/frame/session/benchmarking" default-features = false optional = true +path = "../substrate/frame/session/benchmarking" [dependencies.pallet-skip-feeless-payment] -path = "../substrate/frame/transaction-payment/skip-feeless-payment" default-features = false optional = true +path = "../substrate/frame/transaction-payment/skip-feeless-payment" [dependencies.pallet-society] -path = "../substrate/frame/society" default-features = false optional = true +path = "../substrate/frame/society" [dependencies.pallet-staking] -path = "../substrate/frame/staking" default-features = false optional = true +path = "../substrate/frame/staking" [dependencies.pallet-staking-reward-curve] -path = "../substrate/frame/staking/reward-curve" default-features = false optional = true +path = "../substrate/frame/staking/reward-curve" [dependencies.pallet-staking-reward-fn] -path = "../substrate/frame/staking/reward-fn" default-features = false optional = true +path = "../substrate/frame/staking/reward-fn" [dependencies.pallet-staking-runtime-api] -path = "../substrate/frame/staking/runtime-api" default-features = false optional = true +path = "../substrate/frame/staking/runtime-api" [dependencies.pallet-state-trie-migration] -path = "../substrate/frame/state-trie-migration" default-features = false optional = true +path = "../substrate/frame/state-trie-migration" [dependencies.pallet-statement] -path = "../substrate/frame/statement" default-features = false optional = true +path = "../substrate/frame/statement" [dependencies.pallet-sudo] -path = "../substrate/frame/sudo" default-features = false optional = true +path = "../substrate/frame/sudo" [dependencies.pallet-timestamp] -path = "../substrate/frame/timestamp" default-features = false optional = true +path = "../substrate/frame/timestamp" [dependencies.pallet-tips] -path = "../substrate/frame/tips" default-features = false optional = true +path = "../substrate/frame/tips" [dependencies.pallet-transaction-payment] -path = "../substrate/frame/transaction-payment" default-features = false optional = true +path = "../substrate/frame/transaction-payment" [dependencies.pallet-transaction-payment-rpc-runtime-api] -path = "../substrate/frame/transaction-payment/rpc/runtime-api" default-features = false optional = true +path = "../substrate/frame/transaction-payment/rpc/runtime-api" [dependencies.pallet-transaction-storage] -path = "../substrate/frame/transaction-storage" default-features = false optional = true +path = "../substrate/frame/transaction-storage" [dependencies.pallet-treasury] -path = "../substrate/frame/treasury" default-features = false optional = true +path = "../substrate/frame/treasury" [dependencies.pallet-tx-pause] -path = "../substrate/frame/tx-pause" default-features = false optional = true +path = "../substrate/frame/tx-pause" [dependencies.pallet-uniques] -path = "../substrate/frame/uniques" default-features = false optional = true +path = "../substrate/frame/uniques" [dependencies.pallet-utility] -path = "../substrate/frame/utility" default-features = false optional = true +path = "../substrate/frame/utility" [dependencies.pallet-verify-signature] -path = "../substrate/frame/verify-signature" default-features = false optional = true +path = "../substrate/frame/verify-signature" [dependencies.pallet-vesting] -path = "../substrate/frame/vesting" default-features = false optional = true +path = "../substrate/frame/vesting" [dependencies.pallet-whitelist] -path = "../substrate/frame/whitelist" default-features = false optional = true +path = "../substrate/frame/whitelist" [dependencies.pallet-xcm] -path = "../polkadot/xcm/pallet-xcm" default-features = false optional = true +path = "../polkadot/xcm/pallet-xcm" [dependencies.pallet-xcm-benchmarks] -path = "../polkadot/xcm/pallet-xcm-benchmarks" default-features = false optional = true +path = "../polkadot/xcm/pallet-xcm-benchmarks" [dependencies.pallet-xcm-bridge-hub] -path = "../bridges/modules/xcm-bridge-hub" default-features = false optional = true +path = "../bridges/modules/xcm-bridge-hub" [dependencies.pallet-xcm-bridge-hub-router] -path = "../bridges/modules/xcm-bridge-hub-router" default-features = false optional = true +path = "../bridges/modules/xcm-bridge-hub-router" [dependencies.parachains-common] -path = "../cumulus/parachains/common" default-features = false optional = true +path = "../cumulus/parachains/common" [dependencies.polkadot-core-primitives] -path = "../polkadot/core-primitives" default-features = false optional = true +path = "../polkadot/core-primitives" [dependencies.polkadot-parachain-primitives] -path = "../polkadot/parachain" default-features = false optional = true +path = "../polkadot/parachain" [dependencies.polkadot-primitives] -path = "../polkadot/primitives" default-features = false optional = true +path = "../polkadot/primitives" [dependencies.polkadot-runtime-common] -path = "../polkadot/runtime/common" default-features = false optional = true +path = "../polkadot/runtime/common" [dependencies.polkadot-runtime-metrics] -path = "../polkadot/runtime/metrics" default-features = false optional = true +path = "../polkadot/runtime/metrics" [dependencies.polkadot-runtime-parachains] -path = "../polkadot/runtime/parachains" default-features = false optional = true +path = "../polkadot/runtime/parachains" [dependencies.polkadot-sdk-frame] -path = "../substrate/frame" default-features = false optional = true +path = "../substrate/frame" [dependencies.sc-chain-spec-derive] -path = "../substrate/client/chain-spec/derive" default-features = false optional = true +path = "../substrate/client/chain-spec/derive" [dependencies.sc-tracing-proc-macro] -path = "../substrate/client/tracing/proc-macro" default-features = false optional = true +path = "../substrate/client/tracing/proc-macro" [dependencies.slot-range-helper] -path = "../polkadot/runtime/common/slot_range_helper" default-features = false optional = true +path = "../polkadot/runtime/common/slot_range_helper" [dependencies.snowbridge-beacon-primitives] -path = "../bridges/snowbridge/primitives/beacon" default-features = false optional = true +path = "../bridges/snowbridge/primitives/beacon" [dependencies.snowbridge-core] -path = "../bridges/snowbridge/primitives/core" default-features = false optional = true +path = "../bridges/snowbridge/primitives/core" [dependencies.snowbridge-ethereum] -path = "../bridges/snowbridge/primitives/ethereum" default-features = false optional = true +path = "../bridges/snowbridge/primitives/ethereum" [dependencies.snowbridge-outbound-queue-merkle-tree] -path = "../bridges/snowbridge/pallets/outbound-queue/merkle-tree" default-features = false optional = true +path = "../bridges/snowbridge/pallets/outbound-queue/merkle-tree" [dependencies.snowbridge-outbound-queue-runtime-api] -path = "../bridges/snowbridge/pallets/outbound-queue/runtime-api" default-features = false optional = true +path = "../bridges/snowbridge/pallets/outbound-queue/runtime-api" [dependencies.snowbridge-pallet-ethereum-client] -path = "../bridges/snowbridge/pallets/ethereum-client" default-features = false optional = true +path = "../bridges/snowbridge/pallets/ethereum-client" [dependencies.snowbridge-pallet-ethereum-client-fixtures] -path = "../bridges/snowbridge/pallets/ethereum-client/fixtures" default-features = false optional = true +path = "../bridges/snowbridge/pallets/ethereum-client/fixtures" [dependencies.snowbridge-pallet-inbound-queue] -path = "../bridges/snowbridge/pallets/inbound-queue" default-features = false optional = true +path = "../bridges/snowbridge/pallets/inbound-queue" [dependencies.snowbridge-pallet-inbound-queue-fixtures] -path = "../bridges/snowbridge/pallets/inbound-queue/fixtures" default-features = false optional = true +path = "../bridges/snowbridge/pallets/inbound-queue/fixtures" [dependencies.snowbridge-pallet-outbound-queue] -path = "../bridges/snowbridge/pallets/outbound-queue" default-features = false optional = true +path = "../bridges/snowbridge/pallets/outbound-queue" [dependencies.snowbridge-pallet-system] -path = "../bridges/snowbridge/pallets/system" default-features = false optional = true +path = "../bridges/snowbridge/pallets/system" [dependencies.snowbridge-router-primitives] -path = "../bridges/snowbridge/primitives/router" default-features = false optional = true +path = "../bridges/snowbridge/primitives/router" [dependencies.snowbridge-runtime-common] -path = "../bridges/snowbridge/runtime/runtime-common" default-features = false optional = true +path = "../bridges/snowbridge/runtime/runtime-common" [dependencies.snowbridge-system-runtime-api] -path = "../bridges/snowbridge/pallets/system/runtime-api" default-features = false optional = true +path = "../bridges/snowbridge/pallets/system/runtime-api" [dependencies.sp-api] -path = "../substrate/primitives/api" default-features = false optional = true +path = "../substrate/primitives/api" [dependencies.sp-api-proc-macro] -path = "../substrate/primitives/api/proc-macro" default-features = false optional = true +path = "../substrate/primitives/api/proc-macro" [dependencies.sp-application-crypto] -path = "../substrate/primitives/application-crypto" default-features = false optional = true +path = "../substrate/primitives/application-crypto" [dependencies.sp-arithmetic] -path = "../substrate/primitives/arithmetic" default-features = false optional = true +path = "../substrate/primitives/arithmetic" [dependencies.sp-authority-discovery] -path = "../substrate/primitives/authority-discovery" default-features = false optional = true +path = "../substrate/primitives/authority-discovery" [dependencies.sp-block-builder] -path = "../substrate/primitives/block-builder" default-features = false optional = true +path = "../substrate/primitives/block-builder" [dependencies.sp-consensus-aura] -path = "../substrate/primitives/consensus/aura" default-features = false optional = true +path = "../substrate/primitives/consensus/aura" [dependencies.sp-consensus-babe] -path = "../substrate/primitives/consensus/babe" default-features = false optional = true +path = "../substrate/primitives/consensus/babe" [dependencies.sp-consensus-beefy] -path = "../substrate/primitives/consensus/beefy" default-features = false optional = true +path = "../substrate/primitives/consensus/beefy" [dependencies.sp-consensus-grandpa] -path = "../substrate/primitives/consensus/grandpa" default-features = false optional = true +path = "../substrate/primitives/consensus/grandpa" [dependencies.sp-consensus-pow] -path = "../substrate/primitives/consensus/pow" default-features = false optional = true +path = "../substrate/primitives/consensus/pow" [dependencies.sp-consensus-slots] -path = "../substrate/primitives/consensus/slots" default-features = false optional = true +path = "../substrate/primitives/consensus/slots" [dependencies.sp-core] -path = "../substrate/primitives/core" default-features = false optional = true +path = "../substrate/primitives/core" [dependencies.sp-crypto-ec-utils] -path = "../substrate/primitives/crypto/ec-utils" default-features = false optional = true +path = "../substrate/primitives/crypto/ec-utils" [dependencies.sp-crypto-hashing] -path = "../substrate/primitives/crypto/hashing" default-features = false optional = true +path = "../substrate/primitives/crypto/hashing" [dependencies.sp-crypto-hashing-proc-macro] -path = "../substrate/primitives/crypto/hashing/proc-macro" default-features = false optional = true +path = "../substrate/primitives/crypto/hashing/proc-macro" [dependencies.sp-debug-derive] -path = "../substrate/primitives/debug-derive" default-features = false optional = true +path = "../substrate/primitives/debug-derive" [dependencies.sp-externalities] -path = "../substrate/primitives/externalities" default-features = false optional = true +path = "../substrate/primitives/externalities" [dependencies.sp-genesis-builder] -path = "../substrate/primitives/genesis-builder" default-features = false optional = true +path = "../substrate/primitives/genesis-builder" [dependencies.sp-inherents] -path = "../substrate/primitives/inherents" default-features = false optional = true +path = "../substrate/primitives/inherents" [dependencies.sp-io] -path = "../substrate/primitives/io" default-features = false optional = true +path = "../substrate/primitives/io" [dependencies.sp-keyring] -path = "../substrate/primitives/keyring" default-features = false optional = true +path = "../substrate/primitives/keyring" [dependencies.sp-keystore] -path = "../substrate/primitives/keystore" default-features = false optional = true +path = "../substrate/primitives/keystore" [dependencies.sp-metadata-ir] -path = "../substrate/primitives/metadata-ir" default-features = false optional = true +path = "../substrate/primitives/metadata-ir" [dependencies.sp-mixnet] -path = "../substrate/primitives/mixnet" default-features = false optional = true +path = "../substrate/primitives/mixnet" [dependencies.sp-mmr-primitives] -path = "../substrate/primitives/merkle-mountain-range" default-features = false optional = true +path = "../substrate/primitives/merkle-mountain-range" [dependencies.sp-npos-elections] -path = "../substrate/primitives/npos-elections" default-features = false optional = true +path = "../substrate/primitives/npos-elections" [dependencies.sp-offchain] -path = "../substrate/primitives/offchain" default-features = false optional = true +path = "../substrate/primitives/offchain" [dependencies.sp-runtime] -path = "../substrate/primitives/runtime" default-features = false optional = true +path = "../substrate/primitives/runtime" [dependencies.sp-runtime-interface] -path = "../substrate/primitives/runtime-interface" default-features = false optional = true +path = "../substrate/primitives/runtime-interface" [dependencies.sp-runtime-interface-proc-macro] -path = "../substrate/primitives/runtime-interface/proc-macro" default-features = false optional = true +path = "../substrate/primitives/runtime-interface/proc-macro" [dependencies.sp-session] -path = "../substrate/primitives/session" default-features = false optional = true +path = "../substrate/primitives/session" [dependencies.sp-staking] -path = "../substrate/primitives/staking" default-features = false optional = true +path = "../substrate/primitives/staking" [dependencies.sp-state-machine] -path = "../substrate/primitives/state-machine" default-features = false optional = true +path = "../substrate/primitives/state-machine" [dependencies.sp-statement-store] -path = "../substrate/primitives/statement-store" default-features = false optional = true +path = "../substrate/primitives/statement-store" [dependencies.sp-std] -path = "../substrate/primitives/std" default-features = false optional = true +path = "../substrate/primitives/std" [dependencies.sp-storage] -path = "../substrate/primitives/storage" default-features = false optional = true +path = "../substrate/primitives/storage" [dependencies.sp-timestamp] -path = "../substrate/primitives/timestamp" default-features = false optional = true +path = "../substrate/primitives/timestamp" [dependencies.sp-tracing] -path = "../substrate/primitives/tracing" default-features = false optional = true +path = "../substrate/primitives/tracing" [dependencies.sp-transaction-pool] -path = "../substrate/primitives/transaction-pool" default-features = false optional = true +path = "../substrate/primitives/transaction-pool" [dependencies.sp-transaction-storage-proof] -path = "../substrate/primitives/transaction-storage-proof" default-features = false optional = true +path = "../substrate/primitives/transaction-storage-proof" [dependencies.sp-trie] -path = "../substrate/primitives/trie" default-features = false optional = true +path = "../substrate/primitives/trie" [dependencies.sp-version] -path = "../substrate/primitives/version" default-features = false optional = true +path = "../substrate/primitives/version" [dependencies.sp-version-proc-macro] -path = "../substrate/primitives/version/proc-macro" default-features = false optional = true +path = "../substrate/primitives/version/proc-macro" [dependencies.sp-wasm-interface] -path = "../substrate/primitives/wasm-interface" default-features = false optional = true +path = "../substrate/primitives/wasm-interface" [dependencies.sp-weights] -path = "../substrate/primitives/weights" default-features = false optional = true +path = "../substrate/primitives/weights" [dependencies.staging-parachain-info] -path = "../cumulus/parachains/pallets/parachain-info" default-features = false optional = true +path = "../cumulus/parachains/pallets/parachain-info" [dependencies.staging-xcm] -path = "../polkadot/xcm" default-features = false optional = true +path = "../polkadot/xcm" [dependencies.staging-xcm-builder] -path = "../polkadot/xcm/xcm-builder" default-features = false optional = true +path = "../polkadot/xcm/xcm-builder" [dependencies.staging-xcm-executor] -path = "../polkadot/xcm/xcm-executor" default-features = false optional = true +path = "../polkadot/xcm/xcm-executor" [dependencies.substrate-bip39] -path = "../substrate/utils/substrate-bip39" default-features = false optional = true +path = "../substrate/utils/substrate-bip39" [dependencies.testnet-parachains-constants] -path = "../cumulus/parachains/runtimes/constants" default-features = false optional = true +path = "../cumulus/parachains/runtimes/constants" [dependencies.tracing-gum-proc-macro] -path = "../polkadot/node/gum/proc-macro" default-features = false optional = true +path = "../polkadot/node/gum/proc-macro" [dependencies.xcm-procedural] -path = "../polkadot/xcm/procedural" default-features = false optional = true +path = "../polkadot/xcm/procedural" [dependencies.xcm-runtime-apis] -path = "../polkadot/xcm/xcm-runtime-apis" default-features = false optional = true +path = "../polkadot/xcm/xcm-runtime-apis" [dependencies.asset-test-utils] -path = "../cumulus/parachains/runtimes/assets/test-utils" default-features = false optional = true +path = "../cumulus/parachains/runtimes/assets/test-utils" [dependencies.bridge-hub-test-utils] -path = "../cumulus/parachains/runtimes/bridge-hubs/test-utils" default-features = false optional = true +path = "../cumulus/parachains/runtimes/bridge-hubs/test-utils" [dependencies.cumulus-client-cli] -path = "../cumulus/client/cli" default-features = false optional = true +path = "../cumulus/client/cli" [dependencies.cumulus-client-collator] -path = "../cumulus/client/collator" default-features = false optional = true +path = "../cumulus/client/collator" [dependencies.cumulus-client-consensus-aura] -path = "../cumulus/client/consensus/aura" default-features = false optional = true +path = "../cumulus/client/consensus/aura" [dependencies.cumulus-client-consensus-common] -path = "../cumulus/client/consensus/common" default-features = false optional = true +path = "../cumulus/client/consensus/common" [dependencies.cumulus-client-consensus-proposer] -path = "../cumulus/client/consensus/proposer" default-features = false optional = true +path = "../cumulus/client/consensus/proposer" [dependencies.cumulus-client-consensus-relay-chain] -path = "../cumulus/client/consensus/relay-chain" default-features = false optional = true +path = "../cumulus/client/consensus/relay-chain" [dependencies.cumulus-client-network] -path = "../cumulus/client/network" default-features = false optional = true +path = "../cumulus/client/network" [dependencies.cumulus-client-parachain-inherent] -path = "../cumulus/client/parachain-inherent" default-features = false optional = true +path = "../cumulus/client/parachain-inherent" [dependencies.cumulus-client-pov-recovery] -path = "../cumulus/client/pov-recovery" default-features = false optional = true +path = "../cumulus/client/pov-recovery" [dependencies.cumulus-client-service] -path = "../cumulus/client/service" default-features = false optional = true +path = "../cumulus/client/service" [dependencies.cumulus-relay-chain-inprocess-interface] -path = "../cumulus/client/relay-chain-inprocess-interface" default-features = false optional = true +path = "../cumulus/client/relay-chain-inprocess-interface" [dependencies.cumulus-relay-chain-interface] -path = "../cumulus/client/relay-chain-interface" default-features = false optional = true +path = "../cumulus/client/relay-chain-interface" [dependencies.cumulus-relay-chain-minimal-node] -path = "../cumulus/client/relay-chain-minimal-node" default-features = false optional = true +path = "../cumulus/client/relay-chain-minimal-node" [dependencies.cumulus-relay-chain-rpc-interface] -path = "../cumulus/client/relay-chain-rpc-interface" default-features = false optional = true +path = "../cumulus/client/relay-chain-rpc-interface" [dependencies.cumulus-test-relay-sproof-builder] -path = "../cumulus/test/relay-sproof-builder" default-features = false optional = true +path = "../cumulus/test/relay-sproof-builder" [dependencies.emulated-integration-tests-common] -path = "../cumulus/parachains/integration-tests/emulated/common" default-features = false optional = true +path = "../cumulus/parachains/integration-tests/emulated/common" [dependencies.fork-tree] -path = "../substrate/utils/fork-tree" default-features = false optional = true +path = "../substrate/utils/fork-tree" [dependencies.frame-benchmarking-cli] -path = "../substrate/utils/frame/benchmarking-cli" default-features = false optional = true +path = "../substrate/utils/frame/benchmarking-cli" [dependencies.frame-remote-externalities] -path = "../substrate/utils/frame/remote-externalities" default-features = false optional = true +path = "../substrate/utils/frame/remote-externalities" [dependencies.frame-support-procedural-tools] -path = "../substrate/frame/support/procedural/tools" default-features = false optional = true +path = "../substrate/frame/support/procedural/tools" [dependencies.generate-bags] -path = "../substrate/utils/frame/generate-bags" default-features = false optional = true +path = "../substrate/utils/frame/generate-bags" [dependencies.mmr-gadget] -path = "../substrate/client/merkle-mountain-range" default-features = false optional = true +path = "../substrate/client/merkle-mountain-range" [dependencies.mmr-rpc] -path = "../substrate/client/merkle-mountain-range/rpc" default-features = false optional = true +path = "../substrate/client/merkle-mountain-range/rpc" [dependencies.pallet-contracts-mock-network] -path = "../substrate/frame/contracts/mock-network" default-features = false optional = true +path = "../substrate/frame/contracts/mock-network" [dependencies.pallet-revive-eth-rpc] -path = "../substrate/frame/revive/rpc" default-features = false optional = true +path = "../substrate/frame/revive/rpc" [dependencies.pallet-revive-mock-network] -path = "../substrate/frame/revive/mock-network" default-features = false optional = true +path = "../substrate/frame/revive/mock-network" [dependencies.pallet-transaction-payment-rpc] -path = "../substrate/frame/transaction-payment/rpc" default-features = false optional = true +path = "../substrate/frame/transaction-payment/rpc" [dependencies.parachains-runtimes-test-utils] -path = "../cumulus/parachains/runtimes/test-utils" default-features = false optional = true +path = "../cumulus/parachains/runtimes/test-utils" [dependencies.polkadot-approval-distribution] -path = "../polkadot/node/network/approval-distribution" default-features = false optional = true +path = "../polkadot/node/network/approval-distribution" [dependencies.polkadot-availability-bitfield-distribution] -path = "../polkadot/node/network/bitfield-distribution" default-features = false optional = true +path = "../polkadot/node/network/bitfield-distribution" [dependencies.polkadot-availability-distribution] -path = "../polkadot/node/network/availability-distribution" default-features = false optional = true +path = "../polkadot/node/network/availability-distribution" [dependencies.polkadot-availability-recovery] -path = "../polkadot/node/network/availability-recovery" default-features = false optional = true +path = "../polkadot/node/network/availability-recovery" [dependencies.polkadot-cli] -path = "../polkadot/cli" default-features = false optional = true +path = "../polkadot/cli" [dependencies.polkadot-collator-protocol] -path = "../polkadot/node/network/collator-protocol" default-features = false optional = true +path = "../polkadot/node/network/collator-protocol" [dependencies.polkadot-dispute-distribution] -path = "../polkadot/node/network/dispute-distribution" default-features = false optional = true +path = "../polkadot/node/network/dispute-distribution" [dependencies.polkadot-erasure-coding] -path = "../polkadot/erasure-coding" default-features = false optional = true +path = "../polkadot/erasure-coding" [dependencies.polkadot-gossip-support] -path = "../polkadot/node/network/gossip-support" default-features = false optional = true +path = "../polkadot/node/network/gossip-support" [dependencies.polkadot-network-bridge] -path = "../polkadot/node/network/bridge" default-features = false optional = true +path = "../polkadot/node/network/bridge" [dependencies.polkadot-node-collation-generation] -path = "../polkadot/node/collation-generation" default-features = false optional = true +path = "../polkadot/node/collation-generation" [dependencies.polkadot-node-core-approval-voting] -path = "../polkadot/node/core/approval-voting" default-features = false optional = true +path = "../polkadot/node/core/approval-voting" [dependencies.polkadot-node-core-approval-voting-parallel] -path = "../polkadot/node/core/approval-voting-parallel" default-features = false optional = true +path = "../polkadot/node/core/approval-voting-parallel" [dependencies.polkadot-node-core-av-store] -path = "../polkadot/node/core/av-store" default-features = false optional = true +path = "../polkadot/node/core/av-store" [dependencies.polkadot-node-core-backing] -path = "../polkadot/node/core/backing" default-features = false optional = true +path = "../polkadot/node/core/backing" [dependencies.polkadot-node-core-bitfield-signing] -path = "../polkadot/node/core/bitfield-signing" default-features = false optional = true +path = "../polkadot/node/core/bitfield-signing" [dependencies.polkadot-node-core-candidate-validation] -path = "../polkadot/node/core/candidate-validation" default-features = false optional = true +path = "../polkadot/node/core/candidate-validation" [dependencies.polkadot-node-core-chain-api] -path = "../polkadot/node/core/chain-api" default-features = false optional = true +path = "../polkadot/node/core/chain-api" [dependencies.polkadot-node-core-chain-selection] -path = "../polkadot/node/core/chain-selection" default-features = false optional = true +path = "../polkadot/node/core/chain-selection" [dependencies.polkadot-node-core-dispute-coordinator] -path = "../polkadot/node/core/dispute-coordinator" default-features = false optional = true +path = "../polkadot/node/core/dispute-coordinator" [dependencies.polkadot-node-core-parachains-inherent] -path = "../polkadot/node/core/parachains-inherent" default-features = false optional = true +path = "../polkadot/node/core/parachains-inherent" [dependencies.polkadot-node-core-prospective-parachains] -path = "../polkadot/node/core/prospective-parachains" default-features = false optional = true +path = "../polkadot/node/core/prospective-parachains" [dependencies.polkadot-node-core-provisioner] -path = "../polkadot/node/core/provisioner" default-features = false optional = true +path = "../polkadot/node/core/provisioner" [dependencies.polkadot-node-core-pvf] -path = "../polkadot/node/core/pvf" default-features = false optional = true +path = "../polkadot/node/core/pvf" [dependencies.polkadot-node-core-pvf-checker] -path = "../polkadot/node/core/pvf-checker" default-features = false optional = true +path = "../polkadot/node/core/pvf-checker" [dependencies.polkadot-node-core-pvf-common] -path = "../polkadot/node/core/pvf/common" default-features = false optional = true +path = "../polkadot/node/core/pvf/common" [dependencies.polkadot-node-core-pvf-execute-worker] -path = "../polkadot/node/core/pvf/execute-worker" default-features = false optional = true +path = "../polkadot/node/core/pvf/execute-worker" [dependencies.polkadot-node-core-pvf-prepare-worker] -path = "../polkadot/node/core/pvf/prepare-worker" default-features = false optional = true +path = "../polkadot/node/core/pvf/prepare-worker" [dependencies.polkadot-node-core-runtime-api] -path = "../polkadot/node/core/runtime-api" default-features = false optional = true +path = "../polkadot/node/core/runtime-api" [dependencies.polkadot-node-metrics] -path = "../polkadot/node/metrics" default-features = false optional = true +path = "../polkadot/node/metrics" [dependencies.polkadot-node-network-protocol] -path = "../polkadot/node/network/protocol" default-features = false optional = true +path = "../polkadot/node/network/protocol" [dependencies.polkadot-node-primitives] -path = "../polkadot/node/primitives" default-features = false optional = true +path = "../polkadot/node/primitives" [dependencies.polkadot-node-subsystem] -path = "../polkadot/node/subsystem" default-features = false optional = true +path = "../polkadot/node/subsystem" [dependencies.polkadot-node-subsystem-types] -path = "../polkadot/node/subsystem-types" default-features = false optional = true +path = "../polkadot/node/subsystem-types" [dependencies.polkadot-node-subsystem-util] -path = "../polkadot/node/subsystem-util" default-features = false optional = true +path = "../polkadot/node/subsystem-util" [dependencies.polkadot-omni-node-lib] -path = "../cumulus/polkadot-omni-node/lib" default-features = false optional = true +path = "../cumulus/polkadot-omni-node/lib" [dependencies.polkadot-overseer] -path = "../polkadot/node/overseer" default-features = false optional = true +path = "../polkadot/node/overseer" [dependencies.polkadot-rpc] -path = "../polkadot/rpc" default-features = false optional = true +path = "../polkadot/rpc" [dependencies.polkadot-service] -path = "../polkadot/node/service" default-features = false optional = true +path = "../polkadot/node/service" [dependencies.polkadot-statement-distribution] -path = "../polkadot/node/network/statement-distribution" default-features = false optional = true +path = "../polkadot/node/network/statement-distribution" [dependencies.polkadot-statement-table] -path = "../polkadot/statement-table" default-features = false optional = true +path = "../polkadot/statement-table" [dependencies.sc-allocator] -path = "../substrate/client/allocator" default-features = false optional = true +path = "../substrate/client/allocator" [dependencies.sc-authority-discovery] -path = "../substrate/client/authority-discovery" default-features = false optional = true +path = "../substrate/client/authority-discovery" [dependencies.sc-basic-authorship] -path = "../substrate/client/basic-authorship" default-features = false optional = true +path = "../substrate/client/basic-authorship" [dependencies.sc-block-builder] -path = "../substrate/client/block-builder" default-features = false optional = true +path = "../substrate/client/block-builder" [dependencies.sc-chain-spec] -path = "../substrate/client/chain-spec" default-features = false optional = true +path = "../substrate/client/chain-spec" [dependencies.sc-cli] -path = "../substrate/client/cli" default-features = false optional = true +path = "../substrate/client/cli" [dependencies.sc-client-api] -path = "../substrate/client/api" default-features = false optional = true +path = "../substrate/client/api" [dependencies.sc-client-db] -path = "../substrate/client/db" default-features = false optional = true +path = "../substrate/client/db" [dependencies.sc-consensus] -path = "../substrate/client/consensus/common" default-features = false optional = true +path = "../substrate/client/consensus/common" [dependencies.sc-consensus-aura] -path = "../substrate/client/consensus/aura" default-features = false optional = true +path = "../substrate/client/consensus/aura" [dependencies.sc-consensus-babe] -path = "../substrate/client/consensus/babe" default-features = false optional = true +path = "../substrate/client/consensus/babe" [dependencies.sc-consensus-babe-rpc] -path = "../substrate/client/consensus/babe/rpc" default-features = false optional = true +path = "../substrate/client/consensus/babe/rpc" [dependencies.sc-consensus-beefy] -path = "../substrate/client/consensus/beefy" default-features = false optional = true +path = "../substrate/client/consensus/beefy" [dependencies.sc-consensus-beefy-rpc] -path = "../substrate/client/consensus/beefy/rpc" default-features = false optional = true +path = "../substrate/client/consensus/beefy/rpc" [dependencies.sc-consensus-epochs] -path = "../substrate/client/consensus/epochs" default-features = false optional = true +path = "../substrate/client/consensus/epochs" [dependencies.sc-consensus-grandpa] -path = "../substrate/client/consensus/grandpa" default-features = false optional = true +path = "../substrate/client/consensus/grandpa" [dependencies.sc-consensus-grandpa-rpc] -path = "../substrate/client/consensus/grandpa/rpc" default-features = false optional = true +path = "../substrate/client/consensus/grandpa/rpc" [dependencies.sc-consensus-manual-seal] -path = "../substrate/client/consensus/manual-seal" default-features = false optional = true +path = "../substrate/client/consensus/manual-seal" [dependencies.sc-consensus-pow] -path = "../substrate/client/consensus/pow" default-features = false optional = true +path = "../substrate/client/consensus/pow" [dependencies.sc-consensus-slots] -path = "../substrate/client/consensus/slots" default-features = false optional = true +path = "../substrate/client/consensus/slots" [dependencies.sc-executor] -path = "../substrate/client/executor" default-features = false optional = true +path = "../substrate/client/executor" [dependencies.sc-executor-common] -path = "../substrate/client/executor/common" default-features = false optional = true +path = "../substrate/client/executor/common" [dependencies.sc-executor-polkavm] -path = "../substrate/client/executor/polkavm" default-features = false optional = true +path = "../substrate/client/executor/polkavm" [dependencies.sc-executor-wasmtime] -path = "../substrate/client/executor/wasmtime" default-features = false optional = true +path = "../substrate/client/executor/wasmtime" [dependencies.sc-informant] -path = "../substrate/client/informant" default-features = false optional = true +path = "../substrate/client/informant" [dependencies.sc-keystore] -path = "../substrate/client/keystore" default-features = false optional = true +path = "../substrate/client/keystore" [dependencies.sc-mixnet] -path = "../substrate/client/mixnet" default-features = false optional = true +path = "../substrate/client/mixnet" [dependencies.sc-network] -path = "../substrate/client/network" default-features = false optional = true +path = "../substrate/client/network" [dependencies.sc-network-common] -path = "../substrate/client/network/common" default-features = false optional = true +path = "../substrate/client/network/common" [dependencies.sc-network-gossip] -path = "../substrate/client/network-gossip" default-features = false optional = true +path = "../substrate/client/network-gossip" [dependencies.sc-network-light] -path = "../substrate/client/network/light" default-features = false optional = true +path = "../substrate/client/network/light" [dependencies.sc-network-statement] -path = "../substrate/client/network/statement" default-features = false optional = true +path = "../substrate/client/network/statement" [dependencies.sc-network-sync] -path = "../substrate/client/network/sync" default-features = false optional = true +path = "../substrate/client/network/sync" [dependencies.sc-network-transactions] -path = "../substrate/client/network/transactions" default-features = false optional = true +path = "../substrate/client/network/transactions" [dependencies.sc-network-types] -path = "../substrate/client/network/types" default-features = false optional = true +path = "../substrate/client/network/types" [dependencies.sc-offchain] -path = "../substrate/client/offchain" default-features = false optional = true +path = "../substrate/client/offchain" [dependencies.sc-proposer-metrics] -path = "../substrate/client/proposer-metrics" default-features = false optional = true +path = "../substrate/client/proposer-metrics" [dependencies.sc-rpc] -path = "../substrate/client/rpc" default-features = false optional = true +path = "../substrate/client/rpc" [dependencies.sc-rpc-api] -path = "../substrate/client/rpc-api" default-features = false optional = true +path = "../substrate/client/rpc-api" [dependencies.sc-rpc-server] -path = "../substrate/client/rpc-servers" default-features = false optional = true +path = "../substrate/client/rpc-servers" [dependencies.sc-rpc-spec-v2] +default-features = false +optional = true path = "../substrate/client/rpc-spec-v2" + +[dependencies.sc-runtime-utilities] default-features = false optional = true +path = "../substrate/client/runtime-utilities" [dependencies.sc-service] -path = "../substrate/client/service" default-features = false optional = true +path = "../substrate/client/service" [dependencies.sc-state-db] -path = "../substrate/client/state-db" default-features = false optional = true +path = "../substrate/client/state-db" [dependencies.sc-statement-store] -path = "../substrate/client/statement-store" default-features = false optional = true +path = "../substrate/client/statement-store" [dependencies.sc-storage-monitor] -path = "../substrate/client/storage-monitor" default-features = false optional = true +path = "../substrate/client/storage-monitor" [dependencies.sc-sync-state-rpc] -path = "../substrate/client/sync-state-rpc" default-features = false optional = true +path = "../substrate/client/sync-state-rpc" [dependencies.sc-sysinfo] -path = "../substrate/client/sysinfo" default-features = false optional = true +path = "../substrate/client/sysinfo" [dependencies.sc-telemetry] -path = "../substrate/client/telemetry" default-features = false optional = true +path = "../substrate/client/telemetry" [dependencies.sc-tracing] -path = "../substrate/client/tracing" default-features = false optional = true +path = "../substrate/client/tracing" [dependencies.sc-transaction-pool] -path = "../substrate/client/transaction-pool" default-features = false optional = true +path = "../substrate/client/transaction-pool" [dependencies.sc-transaction-pool-api] -path = "../substrate/client/transaction-pool/api" default-features = false optional = true +path = "../substrate/client/transaction-pool/api" [dependencies.sc-utils] -path = "../substrate/client/utils" default-features = false optional = true +path = "../substrate/client/utils" [dependencies.snowbridge-runtime-test-common] -path = "../bridges/snowbridge/runtime/test-common" default-features = false optional = true +path = "../bridges/snowbridge/runtime/test-common" [dependencies.sp-blockchain] -path = "../substrate/primitives/blockchain" default-features = false optional = true +path = "../substrate/primitives/blockchain" [dependencies.sp-consensus] -path = "../substrate/primitives/consensus/common" default-features = false optional = true +path = "../substrate/primitives/consensus/common" [dependencies.sp-core-hashing] -path = "../substrate/deprecated/hashing" default-features = false optional = true +path = "../substrate/deprecated/hashing" [dependencies.sp-core-hashing-proc-macro] -path = "../substrate/deprecated/hashing/proc-macro" default-features = false optional = true +path = "../substrate/deprecated/hashing/proc-macro" [dependencies.sp-database] -path = "../substrate/primitives/database" default-features = false optional = true +path = "../substrate/primitives/database" [dependencies.sp-maybe-compressed-blob] -path = "../substrate/primitives/maybe-compressed-blob" default-features = false optional = true +path = "../substrate/primitives/maybe-compressed-blob" [dependencies.sp-panic-handler] -path = "../substrate/primitives/panic-handler" default-features = false optional = true +path = "../substrate/primitives/panic-handler" [dependencies.sp-rpc] -path = "../substrate/primitives/rpc" default-features = false optional = true +path = "../substrate/primitives/rpc" [dependencies.staging-chain-spec-builder] -path = "../substrate/bin/utils/chain-spec-builder" default-features = false optional = true +path = "../substrate/bin/utils/chain-spec-builder" [dependencies.staging-node-inspect] -path = "../substrate/bin/node/inspect" default-features = false optional = true +path = "../substrate/bin/node/inspect" [dependencies.staging-tracking-allocator] -path = "../polkadot/node/tracking-allocator" default-features = false optional = true +path = "../polkadot/node/tracking-allocator" [dependencies.subkey] -path = "../substrate/bin/utils/subkey" default-features = false optional = true +path = "../substrate/bin/utils/subkey" [dependencies.substrate-build-script-utils] -path = "../substrate/utils/build-script-utils" default-features = false optional = true +path = "../substrate/utils/build-script-utils" [dependencies.substrate-frame-rpc-support] -path = "../substrate/utils/frame/rpc/support" default-features = false optional = true +path = "../substrate/utils/frame/rpc/support" [dependencies.substrate-frame-rpc-system] -path = "../substrate/utils/frame/rpc/system" default-features = false optional = true +path = "../substrate/utils/frame/rpc/system" [dependencies.substrate-prometheus-endpoint] -path = "../substrate/utils/prometheus" default-features = false optional = true +path = "../substrate/utils/prometheus" [dependencies.substrate-rpc-client] -path = "../substrate/utils/frame/rpc/client" default-features = false optional = true +path = "../substrate/utils/frame/rpc/client" [dependencies.substrate-state-trie-migration-rpc] -path = "../substrate/utils/frame/rpc/state-trie-migration-rpc" default-features = false optional = true +path = "../substrate/utils/frame/rpc/state-trie-migration-rpc" [dependencies.substrate-wasm-builder] -path = "../substrate/utils/wasm-builder" default-features = false optional = true +path = "../substrate/utils/wasm-builder" [dependencies.tracing-gum] -path = "../polkadot/node/gum" default-features = false optional = true +path = "../polkadot/node/gum" [dependencies.xcm-emulator] -path = "../cumulus/xcm/xcm-emulator" default-features = false optional = true +path = "../cumulus/xcm/xcm-emulator" [dependencies.xcm-simulator] -path = "../polkadot/xcm/xcm-simulator" default-features = false optional = true +path = "../polkadot/xcm/xcm-simulator" [package.metadata.docs.rs] features = ["node", "runtime-full"] diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 2216864fad0f..7b3c869588f0 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -584,10 +584,6 @@ pub use pallet_revive; #[cfg(feature = "pallet-revive-eth-rpc")] pub use pallet_revive_eth_rpc; -/// Fixtures for testing and benchmarking. -#[cfg(feature = "pallet-revive-fixtures")] -pub use pallet_revive_fixtures; - /// A mock network for testing pallet-revive. #[cfg(feature = "pallet-revive-mock-network")] pub use pallet_revive_mock_network; @@ -1123,6 +1119,10 @@ pub use sc_rpc_server; #[cfg(feature = "sc-rpc-spec-v2")] pub use sc_rpc_spec_v2; +/// Substrate client utilities for frame runtime functions calls. +#[cfg(feature = "sc-runtime-utilities")] +pub use sc_runtime_utilities; + /// Substrate service. Starts a thread that spins up the network, client, and extrinsic pool. /// Manages communication between them. #[cfg(feature = "sc-service")]